Skip to content

HTML5 语义与原生校验 ​

前两节已经能让学员填写报名信息。现在需要让页面结构更清楚:导航、课程通知和报名区域分别承担什么作用?邮箱写错或年龄超出范围时,浏览器能否在提交前提醒填写者?

本节先用语义元素划分学员管理页面,再为报名字段选择准确的输入类型和校验规则,最后组合成一张页面。完成后,要能指出主要区域,并用错误邮箱和超出范围的年龄触发浏览器提示。

页面语义结构 ​

div 可以包裹任何内容,但它本身不说明这部分内容是导航、正文还是页脚。HTML 提供了一组语义元素,用标签名直接表达区域用途。

元素常见用途
header页面或区域的头部
nav主要导航链接
main页面独有的主要内容
section有明确主题的内容区域
article可以独立理解或复用的内容
aside与主要内容相关的补充信息
footer页面或区域的尾部

下面是页面区域示意图。图中的颜色和排列只用于说明结构,不是语义元素自带的样式;窄屏下两栏会自动换行。

<header>
<nav>
<article>
<section>
<aside>
<footer>

这张图展示一种可能的区域关系,不与下一段代码逐项对应。实际页面通常用 main 包住主要内容;section 和 article 谁在外层,要由内容含义决定。

学员管理页面示例 ​

复制第一节的 HTML 文档骨架,把下面的 <body>...</body> 放进去,保存为 semantic-page.html 后用浏览器打开。本例只组织内容,不处理颜色、间距和布局:

html
<body>
  <header>
    <h1>学员管理系统</h1>
    <nav aria-label="主要导航">
      <a href="#pending">待处理报名</a>
      <a href="#notice">课程通知</a>
      <a href="#help">使用提示</a>
    </nav>
  </header>

  <main>
    <section id="pending">
      <h2>待处理报名</h2>
      <p>当前有 3 条报名记录等待审核。</p>
    </section>

    <section id="notice">
      <h2>课程通知</h2>
      <article>
        <h3>周末班开课提醒</h3>
        <p>请在开课前完成环境检查。</p>
      </article>
    </section>

    <aside id="help">
      <h2>使用提示</h2>
      <p>新增学员前,请先确认手机号没有重复。</p>
    </aside>
  </main>

  <footer>
    <small>&copy; 2026 学员管理系统</small>
  </footer>
</body>

外观预览如下。这里的样式只用于课件展示,语义结构和导航行为以上方代码为准:

学员管理系统
待处理报名课程通知使用提示
待处理报名
当前有 3 条报名记录等待审核。
课程通知
周末班开课提醒
请在开课前完成环境检查。
使用提示
新增学员前,请先确认手机号没有重复。
© 2026 学员管理系统

打开页面后,点击三个导航链接,地址栏的片段标识会变化;页面足够长时,还会滚动到对应的 id。代码中“课程通知”是页面的一个 section,其中的“周末班开课提醒”离开当前页面也能独立理解,所以用 article 包裹。这与示意图中 article 包住 section 的结构不同,但都由实际内容决定。

一个页面通常只放一个代表主要内容的 main。header 和 footer 既可以描述整个页面,也可以描述某个独立区域。语义元素负责说明结构,不会自动完成视觉布局,页面样式仍由 CSS 处理。

section、article 与 div 的使用边界 ​

选择容器时依次判断:

  1. 内容有明确主题,是页面中的一个区域:考虑 section。
  2. 内容离开当前页面仍能独立理解:考虑 article。
  3. 只是为了分组、布局,或没有更合适的语义:使用 div。

不要为了使用新标签而把每个 div 都替换成 section。语义来自内容用途,不来自标签的新旧。

表单输入类型 ​

浏览器不仅会显示输入框,还会根据 type 提供合适的键盘、选择器和基础校验。先看报名页面中常见的类型:

html
<label for="email">邮箱</label>
<input id="email" name="email" type="email" autocomplete="email">

<label for="mobile">手机号</label>
<input id="mobile" name="mobile" type="tel" autocomplete="tel">

<label for="age">年龄</label>
<input id="age" name="age" type="number" min="16" max="80" step="1">

<label for="birthday">出生日期</label>
<input id="birthday" name="birthday" type="date">

<label for="homepage">个人主页</label>
<input id="homepage" name="homepage" type="url">

<label for="keyword">搜索学员</label>
<input id="keyword" name="keyword" type="search">

预览效果如下:

类型适合的数据浏览器可能提供的帮助
email邮箱地址邮箱键盘和基础格式校验
tel电话号码电话键盘,不自动验证真实手机号规则
number可计算的数值数值输入和范围、步长校验
date日期日期选择器
url网址网址键盘和基础格式校验
search搜索关键词与搜索场景匹配的输入体验

不同浏览器和系统的控件外观可能不同,因此仍要使用 label 说明业务含义。手机号是标识信息,不用于数值计算,应使用 tel,不要使用 number。

数值与日期范围 ​

html
<input name="age" type="number" min="16" max="80" step="1">
<input name="score" type="number" min="0" max="100" step="0.5">
<input name="start_date" type="date" min="2026-01-01" max="2026-12-31">

预览效果如下:

  • min、max:允许的最小值和最大值。
  • step:数值变化的步长;例如 0.5 表示可以按半分递增。

这些属性既会影响部分控件的操作方式,也会参与浏览器原生校验。

多文件选择 ​

上一节已经使用 file 和 accept 选择文件。在需要提交多份学习资料时,可以再添加 multiple:

html
<label for="materials">学习资料</label>
<input
  id="materials"
  name="materials"
  type="file"
  accept=".pdf,image/png,image/jpeg"
  multiple
>

预览效果如下:

  • multiple:允许一次选择多个文件。
  • accept:提示文件选择器优先显示允许的类型。

accept 不是安全校验,文件的真实类型和大小仍需由后端检查。

浏览器原生校验 ​

浏览器可以根据输入类型和约束属性,在提交前检查必填、格式、长度和范围。复制第一节的 HTML 文档骨架,把下面的表单放入 <body>,保存为 validation-form.html:

html
<form action="/students" method="post">
  <p>
    <label for="register-email">邮箱</label>
    <input id="register-email" name="email" type="email" required>
  </p>

  <p>
    <label for="register-age">年龄</label>
    <input
      id="register-age"
      name="age"
      type="number"
      min="16"
      max="80"
      required
    >
  </p>

  <button type="submit">提交</button>
</form>

下方仅预览表单外观,按钮不会提交数据;原生校验请在上面创建的独立 HTML 文件中观察:

用浏览器打开文件,按下面的顺序观察原生校验:

操作预期现象
两项都留空,点击“提交”浏览器阻止提交,并提示先填写邮箱
邮箱填入 abc,年龄填入 20,点击“提交”浏览器提示邮箱格式不正确
邮箱改为 student@example.com,年龄填入 15,点击“提交”浏览器提示年龄低于允许范围

浏览器通常会定位到当前首先发现的无效字段。修正一个字段后再提交,才能继续观察下一个字段的提示;提示的文字和外观会因浏览器而异。

文本长度与格式约束 ​

常见文本长度可以直接声明:

html
<input name="nickname" type="text" minlength="2" maxlength="20" required>

格式简单且稳定时,可以使用 pattern:

html
<label for="student-code">学员编号</label>
<input
  id="student-code"
  name="student_code"
  type="text"
  pattern="S[0-9]{4}"
  placeholder="例如:S1001"
  title="请输入字母 S 和 4 位数字"
  required
>

这里要求学员编号由大写字母 S 和 4 位数字组成,例如 S1001。title 为填写规则提供补充说明。

两个文本字段的外观预览如下:

本课程不展开复杂正则表达式。手机号、姓名等真实业务规则经常变化,应由后端执行权威验证并返回清楚的错误信息。

不参与原生校验的情况 ​

html
<input name="student_id" value="S1001" readonly>
<input name="source" value="import" disabled>

预览效果如下:

readonly 控件不能修改,但仍可获得焦点并通常会提交;disabled 控件不能操作,不参与原生校验,也通常不会提交。

表单还可以使用 novalidate 关闭整体原生校验:

html
<form action="/students" method="post" novalidate>
  <!-- 浏览器不执行表单级原生约束检查 -->
</form>

基础课程案例保留原生校验,不主动添加 novalidate。这些浏览器规则用于改善填写体验,不能代替后端验证。

语义与校验综合示例 ​

现在把语义结构、准确输入类型和原生校验合并到一张报名页面中:

html
<header>
  <h1>Web 全栈课程报名</h1>
  <nav aria-label="报名导航">
    <a href="#intro">课程说明</a>
    <a href="#register">填写资料</a>
  </nav>
</header>

<main>
  <section id="intro">
    <h2>课程说明</h2>
    <p>请使用真实联系方式,标记为“必填”的内容必须填写。</p>
  </section>

  <section id="register">
    <h2>报名资料</h2>
    <form action="/students" method="post">
      <p>
        <label for="name">姓名(必填)</label>
        <input id="name" name="name" type="text" minlength="2" maxlength="20" required>
      </p>

      <p>
        <label for="email">邮箱(必填)</label>
        <input id="email" name="email" type="email" autocomplete="email" required>
      </p>

      <p>
        <label for="age">年龄</label>
        <input id="age" name="age" type="number" min="16" max="80">
      </p>

      <button type="submit">提交报名</button>
    </form>
  </section>
</main>

<footer>
  <small>报名问题请发送邮件到 support@example.com</small>
</footer>

下面是页面外观预览,报名按钮不会发送请求;可运行的语义结构和校验规则以上方代码为准:

Web 全栈课程报名
课程说明填写资料
课程说明
请使用真实联系方式,标记为“必填”的内容必须填写。
报名资料
报名问题请发送邮件到 support@example.com

仍以第一节的 HTML 文档骨架新建文件,把这段代码放入 <body>,保存为 register-page.html 并用浏览器打开。先检查导航链接能否定位到对应区域,再分别测试空值、错误邮箱和超出范围的年龄。通过校验后,页面可能进入不存在的 /students 地址,这是因为本节没有启动后端服务,不影响对 HTML 和浏览器校验的观察。

基础无障碍检查 ​

语义标签不仅方便阅读,也为屏幕阅读器、键盘操作和辅助技术提供结构信息。完成页面后,可以按下面的顺序检查:

对话框标题关联 ​

弹窗内容需要声明自己的角色,并让辅助技术知道弹窗标题是什么。p01 先学习静态 HTML 关系,打开、关闭和焦点管理会在后面的 DOM 与事件章节处理:

html
<div role="dialog" aria-labelledby="remove-dialog-title">
  <h2 id="remove-dialog-title">确认删除学员</h2>
  <p>删除后将无法从当前列表中恢复。</p>
  <button type="button">取消</button>
  <button type="button">确认删除</button>
</div>

静态外观预览如下,按钮尚未连接打开、关闭或删除操作:

确认删除学员
删除后将无法从当前列表中恢复。

aria-labelledby 的值必须对应标题元素的 id。它补充的是对话框的语义关系,不负责实现弹窗显示、隐藏或按钮行为。

表单错误关联 ​

下面模拟用户提交后邮箱格式不正确的状态。错误文字有独立的 id,输入框通过 aria-describedby 指向它,并用 aria-invalid="true" 表明当前值无效:

html
<main>
  <h1>学员登记</h1>
  <form>
    <fieldset>
      <legend>基本信息</legend>
      <label for="student-name">姓名</label>
      <input id="student-name" name="name" type="text" required>

      <label for="student-email">邮箱</label>
      <input
        id="student-email"
        name="email"
        type="email"
        value="abc"
        aria-describedby="email-error"
        aria-invalid="true"
        required
      >
      <small id="email-error">邮箱格式不正确,请重新填写。</small>
    </fieldset>
  </form>
</main>

错误状态的外观预览如下:

学员登记
基本信息
邮箱格式不正确,请重新填写。
  • 页面只保留一个清楚的 h1,后续标题按层级递进,不用标题标签只为了放大字体。
  • 每个表单控件都要有对应的 label;一组相关控件使用 fieldset 和 legend。
  • 图片提供准确的 alt;装饰图片使用空 alt="",不要把文件名当说明。
  • 对话框使用 role="dialog",并通过 aria-labelledby 关联清楚的标题。
  • 错误提示要有自己的 id,再用 aria-describedby 关联;aria-invalid="true" 只在确实无效时设置。值恢复有效后,应移除错误状态或改为有效状态。
  • 表格补充 caption、th 和 scope;导航区域使用 nav,主内容使用 main。

aria-* 是补充语义,不是用来替代原生 HTML 的第一选择。优先使用准确的原生元素,再在确实需要时添加 ARIA 状态或关系。

小结 ​

  1. 语义元素用于说明页面区域的用途,不负责视觉布局。
  2. section 表示有明确主题的区域,article 表示可以独立理解的内容。
  3. 准确的输入类型可以改善键盘、选择器和基础校验体验。
  4. required、长度、范围和简单的 pattern 可以声明输入约束。
  5. readonly 与 disabled 对操作、校验和提交的影响不同。
  6. 浏览器原生校验用于改善填写体验,关键业务规则仍需由后端再次验证。
  7. 语义结构、标签关联、替代文本和错误关系共同构成基础无障碍检查清单。