Agent Developer Roadmap
Web 基础

HTML:从字节流到可访问文档

最后核验:2026-06-30|适用版本:HTML Living Standard(现代常青浏览器)|前置知识:无

HTML 在浏览器流水线中的职责

HTML 不是“给 CSS 和 JavaScript 挂钩的字符串”,而是浏览器创建文档树、表单行为、焦点顺序、可访问性树和默认交互的输入语言。工程师需要掌握它,才能解释这些现象:查看源代码与 Elements 面板为什么不同,脚本为何阻塞首屏,错误嵌套为何被浏览器重排,以及一个按钮为何能在没有 JavaScript 时提交表单。

HTML 负责内容结构与交互语义,不负责业务状态、复杂计算或视觉布局。以下情况不要试图只靠 HTML:跨字段异步校验、客户端离线数据库、复杂可视化、持续更新的应用状态。反过来,能由链接、表单、detailsdialog 或 Popover 完成的行为,也不应先造一套 div、键盘监听和 ARIA 状态机。

判断标准很直接:先问“浏览器是否已经理解这个意图”。原生语义通常同时提供键盘、表单、历史记录和辅助技术入口;自定义控件则必须逐项补齐。

Tokenizer 与 Tree Builder

导航得到的响应字节先按编码解码为码点流,再进入 HTML Tokenizer。Tokenizer 根据状态产生开始标签、结束标签、字符、注释等 token;Tree Builder 按插入模式维护开放元素栈,并增量修改 DOM。WHATWG 明确规定,HTML 采用自己的容错解析算法,不等同于 XML 或 SGML;Tree Builder 的输入是 token 序列,输出是对 Document 树的动态修改。HTML 解析规范

DOM 是解析结果,不是源文本的逐字符镜像。比如表格上下文中的非法节点可能触发 foster parenting(寄养处理),浏览器也会自动补出某些隐含元素。定位结构问题时,应同时比较 Network 中的原始响应与 Elements 中的 DOM。

脚本加载、执行与解析阻塞

脚本属性决定解析、下载和执行的关系:

写法下载执行时机与顺序主要用途
<script src>解析遇到时开始默认暂停解析,下载后立即执行必须在后续标记前建立全局状态的遗留脚本
<script defer src>与解析并行解析完成后、DOMContentLoaded 前,保持文档顺序依赖 DOM 的经典脚本
<script async src>与解析并行下载完成即执行,不保证相互顺序独立统计或广告脚本
<script type="module">依赖图并行获取默认延后执行;模块按依赖关系求值现代应用入口

DOMContentLoaded 表示文档已解析且延后脚本执行完毕,不代表图片、字体等全部加载。把所有初始化都放到 load 往往无端推迟交互。

内容模型、语义与可访问名称

语义元素同时建立内容模型。buttonalabel、标题、列表、表格不是可互换的皮肤:它们约束合法子内容,也向浏览器和辅助技术表达角色、名称与关系。页面级 landmark 应来自 headernavmainasidefooter 等结构;一个页面通常只有一个主要内容 <main>

可访问名称可能来自元素文本、关联的 <label>aria-labelaria-labelledby。优先使用可见文本和原生 <label for>,因为它同时扩大点击区域并让所有用户看到同一名称;ARIA 用于补充缺失语义,不用于覆盖错误元素选择。

文档元数据、语言与标题层级

<head> 中的元数据决定编码、视口、标题、资源提示、图标和搜索/分享入口。<meta charset="utf-8"> 应尽早出现,避免浏览器用错误编码重新解析;viewport 声明让移动浏览器按设备宽度布局,不应禁用用户缩放。每个页面需要能区分任务的 <title>,单页应用导航后也要同步更新。

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>JavaScript 执行模型|前端开发路线图</title>
  <meta name="description" content="从执行上下文、对象到异步任务系统学习 JavaScript。">
  <link rel="canonical" href="https://example.com/roadmap/javascript">
</head>

根元素的 lang="zh-CN" 帮助屏幕阅读器选择发音、浏览器断词和翻译工具判断语言。局部外文使用 lang="en";阿拉伯语等方向变化使用 dir,不要仅靠 CSS direction 隐藏文本语义。

HTML 没有可靠的自动 outline 算法替作者修复标题。h1h6 表示内容层级而非字号:页面主题通常一个 h1,直接子主题用 h2,不要因为样式跳到 h4section 通常应有可识别标题;仅为样式分组用 div,不要制造大量无名 section landmark。

语义元素如何选择

语义化不是“把 div 全换成标签”,而是选择与内容/操作角色匹配的最小元素。浏览器、搜索引擎和辅助技术从元素得到默认行为,CSS 再决定视觉。

内容或行为首选元素边界与易错点
站点/页面主要导航nav + 链接列表不是所有链接组都需要 nav;多个 nav 用可访问名称区分
页面唯一主要内容main不放在 article/aside/nav 内;通常一个可见 main
可独立分发的内容article一条评论、帖子、卡片可独立成文时适合
主题章节section + 标题无主题、只为布局时用 div
补充或间接相关内容aside页面侧栏、文章补充;不等于“放右边”
时间/日期time datetime="..."可见文案可本地化,datetime 保留机器可读值
联系方式address只表示最近 article/body 的联系信息,不是任意邮政地址
用户操作button无导航目标;明确 type 防止表单内意外提交
导航到资源a href没有 href 的 a 不具备链接行为;不要按钮模拟导航
术语定义dfn,配合 dl/正文dl 也适合键值元数据,不限字典
机器输入/输出codekbdsampprepre 保留空白但不自动表示代码
重要/强调strong / em不等同于粗体/斜体装饰,装饰交给 CSS
删除/新增内容del / ins可带 datetime/cite,适合变更语义

header/footer 的含义取决于最近的 sectioning content:页面级 header 可以放品牌与导航,article 内 header 放文章标题/作者;它们不是全局只能出现一次。figure 表示可从正文主流移走、但被正文引用的自包含内容,figcaption 给出说明;普通图片不必套 figure。

链接与按钮的行为差异

链接拥有 URL、可复制地址、可在新标签打开、进入历史记录,并由浏览器支持状态栏和上下文菜单。按钮执行当前页面命令,支持 Space/Enter 激活并参与表单。用样式让两者看起来相似没有问题,但不能交换语义。

下载链接仅在同源或符合浏览器规则时尊重 download;外链新窗口通常使用 target="_blank" 并声明 rel="noopener",同时在文案中说明新窗口行为。mailto:/tel: 依赖用户设备处理器,不能作为唯一联系方式。

锚点、片段导航与滚动定位

URL 中 #fragment 用来定位文档中的 id。片段导航是平台状态:可复制、可收藏、参与前进后退,并让目标匹配 :target。目录、跳过链接、错误摘要和长文定位都应使用真实 <a href="#id">,不必先写 click handler。

<nav aria-label="本文目录">
  <ol>
    <li><a href="#execution-context">执行上下文</a></li>
    <li><a href="#event-loop">事件循环</a></li>
  </ol>
</nav>

<main id="main-content" tabindex="-1">
  <section id="execution-context">
    <h2>执行上下文</h2>
    <p>每次函数调用都会建立新的执行上下文。</p>
  </section>
</main>

id 在同一 tree 中必须唯一,值区分大小写,并应保持稳定;标题改名时若同时改 id,会破坏外部链接。生成 id 时处理中文、重复标题和版本迁移,必要时保留旧锚点作为兼容入口。不要把用户输入直接拼成 selector,DOM 定位可使用 document.getElementById

固定 header 可能遮住目标位置,使用 CSS scroll-margin-block-start 给目标预留空间,而不是在点击后手工计算像素。跳过链接通常在获得焦点时显示,目标 main 若不能自然聚焦可临时/永久使用 tabindex="-1",但不要把大量非交互标题加入 Tab 顺序。

:target {
  scroll-margin-block-start: 5rem;
  outline: .2rem solid currentColor;
}

更新 fragment 的方式决定历史:普通链接会创建历史条目;同页高频同步若不希望每次创建条目,可用 History API replaceState,但要保留可复制 URL 和 hashchange/popstate 恢复。平滑滚动属于表现,尊重 prefers-reduced-motion;不要让动画阻止目标获得可见焦点。

文本片段 URL(形如 #:~:text=)由浏览器定位文本,不由页面 id 控制,适合外部深链但可能随文案变化失效。站点自己的长期目录仍应提供稳定 id。

列表、表格、图片与媒体的内容模型

有序步骤用 ol,无序集合用 ul,术语/键值用 dl。不要为去掉项目符号改用 div;视觉由 CSS 控制,列表语义仍能告诉辅助技术项目数量和位置。

数据表格使用 caption 说明目的,th scope="col|row" 建立简单表头关系;复杂多层表头再使用 headers/id。布局不要使用 table。响应式时优先让表格容器局部滚动并保留表头,不把每个 cell 拆成无法理解的卡片。

<figure>
  <picture>
    <source media="(width >= 60rem)" srcset="event-loop-wide.avif" type="image/avif">
    <source srcset="event-loop.webp" type="image/webp">
    <img src="event-loop.png"
         width="960" height="540"
         alt="任务、微任务与渲染机会的时序图"
         loading="lazy" decoding="async">
  </picture>
  <figcaption>一次 task 结束后清空 microtask,随后浏览器才可能渲染。</figcaption>
</figure>

imgwidth/height 提供固有宽高比,减少布局偏移;alt 描述图片承担的信息,装饰图片用空 alt="",不要省略让文件名被朗读。loading="lazy" 不用于首屏关键图;响应式尺寸选择使用 srcset/sizes,不同裁切构图使用 picture/source。

audio/video 应提供 controls、字幕 track 和文本替代;自动播放通常受策略限制且会伤害用户体验。iframe 需要准确 title,按最小权限设置 sandbox/allow,第三方嵌入仍是网络、隐私与供应链边界。

表单、Dialog 与渐进增强

下面的单文件示例展示无 JavaScript 基础版本、带标签的搜索表单、原生约束验证、详情对话框和对比表。环境是现代常青浏览器与 Python 3;它不需要包管理器。

<!doctype html>
<html lang="zh-CN">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>技术目录</title>
</head>
<body>
  <a href="#catalog">跳到技术目录</a>
  <header>
    <h1>技术目录</h1>
    <p>按关键词筛选,并查看技术边界。</p>
  </header>

  <main id="catalog">
    <form action="." method="get" role="search" aria-label="筛选技术目录">
      <label for="q">关键词</label>
      <input id="q" name="q" type="search" minlength="2" required>
      <button type="submit">搜索</button>
    </form>

    <section aria-labelledby="results-heading">
      <h2 id="results-heading">结果</h2>
      <article>
        <h3>HTML</h3>
        <p>解析、语义与渐进增强。</p>
        <button type="button" commandfor="html-detail" command="show-modal">
          查看详情
        </button>
      </article>
    </section>

    <section aria-labelledby="compare-heading">
      <h2 id="compare-heading">对比</h2>
      <table>
        <caption>已选技术边界</caption>
        <thead><tr><th scope="col">技术</th><th scope="col">职责</th></tr></thead>
        <tbody><tr><th scope="row">HTML</th><td>内容与语义</td></tr></tbody>
      </table>
    </section>
  </main>

  <dialog id="html-detail" aria-labelledby="detail-title">
    <h2 id="detail-title">HTML 详情</h2>
    <p>浏览器把 HTML 解析为 DOM。</p>
    <form method="dialog"><button>关闭</button></form>
  </dialog>
</body>
</html>

将内容保存为 index.html,在其目录运行:

python3 -m http.server 4173

输入:访问 http://localhost:4173/,提交少于两个字符的关键词,再输入 html 提交。

预期结果:浏览器先用原生提示阻止第一个提交;第二次导航产生 ?q=html。支持 Invoker Commands 的浏览器会声明式打开对话框;尚不支持时,文档、表单和表格仍可阅读,这就是渐进增强边界。若产品要求覆盖不支持声明式命令的目标浏览器,可用一次特性检测为按钮补充 showModal(),而不是重写整个对话框。

表单约束是用户体验层,不是安全边界。typerequiredminlengthpattern 可声明常见约束,checkValidity() 只返回结果,reportValidity() 还会请求浏览器展示提示;请求可以绕过页面,因此服务端必须再次验证。Constraint Validation 指南

dialog.showModal() 会把对话框放入 top layer,并让背景内容不可交互;非模态提示更适合 Popover。Popover 没有固有对话框语义,默认 popover="auto" 支持 light dismiss。不要用模态对话框承载普通提示,也不要把 tooltip 做成阻断页面的模态窗口。Dialog 与 Popover 模式

表单提交的数据模型

表单提交的是 successful controls 组成的 name/value 集合。没有 name、被 disabled、未选中的 checkbox/radio、非提交按钮等不会进入数据;readonly 控件仍会提交。GET 把数据编码到 URL,适合安全、幂等、可分享查询;POST 把数据放请求体,适合产生副作用或较大/敏感载荷,但 HTTPS、认证、授权和 CSRF 仍由服务端负责。

控件关键语义高频错误
input type="email/url/number/date"提供输入模式、约束和移动键盘提示认为 number 能表达金额精度,或 date 自带业务时区
checkbox未选中时不提交任何值服务端未给缺失值默认 false
同名 radio一组选一个值每个 radio 使用不同 name,导致可同时选择
select单选或 multiple 值集合只靠 placeholder option 却未处理 required
textarea多行纯文本输入初始值写 value 属性而不是元素文本/DOM value
button默认 type 在表单内通常是 submit普通操作按钮漏写 type="button"
input type="file"用户授权选择 File;表单需 multipart试图设置 value 或信任文件名/MIME

fieldset/legend 给一组相关控件共同名称,特别适合 radio、地址和条件字段。placeholder 不是 label:输入后会消失、对比度通常较弱,也不能稳定形成说明。错误提示应靠 aria-describedby/aria-errormessage 与控件关联,并把提交后的错误摘要链接到对应控件 id。

浏览器 autocomplete 能减少输入和可访问成本。使用语义 token 如 nameemailcurrent-passwordnew-passwordone-time-code;不要普遍 autocomplete="off" 对抗密码管理器。用户名、密码和一次性验证码属于安全敏感字段,但阻止自动填充通常会诱导更弱密码。

约束验证的触发与自定义错误

约束包括 required、type、min/max/step、minlength/maxlength、pattern。validity 暴露 valueMissingtypeMismatchpatternMismatch 等状态;setCustomValidity('') 清除自定义错误,任何非空字符串都会让控件保持 invalid。

<form id="schedule-form">
  <label for="start-date">开始日期</label>
  <input id="start-date" name="start" type="date" required>

  <label for="end-date">结束日期</label>
  <input id="end-date" name="end" type="date" required
         aria-describedby="date-error">
  <p id="date-error" role="status"></p>

  <button>保存</button>
</form>

<script type="module">
  const form = document.querySelector('#schedule-form');
  const start = form.elements.start;
  const end = form.elements.end;
  const error = document.querySelector('#date-error');

  const validateRange = () => {
    const invalid = start.value && end.value && end.value < start.value;
    end.setCustomValidity(invalid ? '结束日期不能早于开始日期' : '');
    error.textContent = invalid ? end.validationMessage : '';
  };

  form.addEventListener('input', validateRange);
  form.addEventListener('submit', (event) => {
    validateRange();
    if (!form.checkValidity()) event.preventDefault();
  });
</script>

日期 input 的 value 使用规范化字符串,比较纯日期时可按 ISO YYYY-MM-DD 比较;这仍不是服务端验证。异步用户名占用、库存等规则不属于原生同步约束,提交时应展示 pending、取消陈旧请求,并在服务端重新执行。

Dialog、Popover、details 的不同状态机

details/summary 适合文档流内可展开补充,支持键盘和 open 状态;同 name 的 details 可以形成互斥组,但采用前检查目标浏览器。dialog.show() 是非模态,showModal() 进入 top layer 并使其余文档 inert;关闭结果可通过 returnValue 表达。Popover 进入 top layer 但默认不模态、没有固有 role,适合菜单说明、非阻断浮层。

打开模态前记录逻辑触发点,关闭后恢复焦点;对话框初始焦点应落到标题说明后的第一个合理任务控件,危险确认不要默认聚焦破坏性按钮。Escape/cancel、表单 method=dialog 和 requestClose() 需要统一处理未保存数据,不能只监听自定义关闭按钮。

语义骨架在知识浏览器中的落地

本仓库的知识浏览器示例把 HTML 保持为可理解的稳定骨架:

  1. 跳过链接把键盘用户直接送到 <main>
  2. role="search" 表单包含真实标签;没有 JavaScript 时仍能理解筛选意图。
  3. 结果区使用带标题的 section 和列表,动态状态使用 role="status"aria-live="polite"
  4. 详情使用 <dialog>,关闭后由脚本把焦点交还触发按钮。
  5. 对比数据使用带列标题、行标题和说明的 <table>,窄屏只让表格容器横向滚动。
  6. <noscript> 提供五篇核心文章的直接入口,不把“下载失败”伪装成空白页面。

编译并启动示例:

pnpm --filter @roadmap/web-foundations test
python3 -m http.server 4173

预期输出:测试报告包含 页面提供可渐进增强的语义工作区 并通过;访问 http://localhost:4173/examples/frontend-slices/web-foundations/ 后状态区显示 41 / 41 项技术。

这里有意不使用自定义组件基类或模板系统。固定页面只有一个渲染入口,原生 DOM API 已足够;增加抽象只会隐藏正在学习的语义和浏览器行为。

从源响应到可访问性树的调试证据

调试结构时使用三条证据链:Network/响应查看服务端实际发送的文本,Elements 查看解析后的 DOM,Accessibility 面板查看最终角色、名称和状态。只看页面截图无法发现标题层级、错误标签关联或焦点顺序。

症状常见根因最短验证路径
元素跑到预期父节点之外内容模型不合法或解析器纠错用 HTML Validator 检查,再对比源文本和 DOM
首屏长时间空白头部存在解析阻塞脚本Performance 查看 Main 线程,改用模块或 defer
点击标签不能聚焦输入框forid 不匹配Accessibility 查看名称来源
Enter 键行为异常div 模拟按钮或按钮类型遗漏换回原生控件,明确 type
对话框关闭后焦点丢失未记录触发元素close 事件中恢复焦点

HTML 的性能收益主要来自少阻塞、少节点和可流式解析。把大段同步脚本放进 <head> 会暂停 Tokenizer;过深 DOM 增加样式匹配、布局和辅助技术遍历成本。不要为了“语义化”套多余容器,也不要为了少几个节点删除必要标题和标签。

安全上,把外部字符串拼成 HTML 会进入解析器并可能创建可执行上下文。知识浏览器使用 textContentcreateElement 和属性赋值,不使用 innerHTML。CSP 能缩小脚本执行面,但不能把不可信 HTML 变可信;可信边界仍应拒绝不合规数据。新窗口链接使用 rel="noopener noreferrer",表单和服务端都执行验证。

常见误区包括:

  • “有 ARIA 就等于可访问”:错误角色无法补回原生键盘和表单行为。
  • “HTML5 验证能保护 API”:客户端请求可被绕过。
  • “DOM 与 View Source 必须相同”:解析器会纠错、补元素,脚本也会修改 DOM。
  • “所有脚本都加 async 更快”:依赖顺序会变成竞态。
  • div 更容易统一样式”:原生元素同样可样式化,却少一套行为实现。

Living Standard 与平台原语演进

HTML 是 Living Standard,不再以一次性大版本描述平台。工程决策应记录核验日期、规范条目与浏览器支持,而不是写“HTML5 已完成”。截至 2026-06-30,WHATWG 规范仍持续更新;本篇核验时解析规范页面标注最近更新为 2026-06-28。

近年的方向不是堆更多“标签语法”,而是把高成本交互变成平台原语:Popover 进入 Baseline 2025,Invoker Commands 允许按钮通过 command/commandfor 声明操作目标,dialog.requestClose() 提供可取消的关闭请求。Baseline 说明“主要浏览器引擎均可用”的时间点,但产品仍需结合真实用户浏览器验证范围。Baseline 2025 清单

采用新能力的顺序:先保留可理解的 HTML 基础结构,再检测关键方法或属性,最后加载增强逻辑。不要仅用 User-Agent 字符串猜支持度,也不要因为一个增强能力较新就让整页不可用。

截至核验日,适合重点评估的原语如下:

能力解决的问题渐进增强策略
Popover非模态 top-layer 浮层、light dismiss基础版本内容保持在文档;检测 popover/方法后增强触发
Invoker Commands按钮用 command/commandfor 声明控制 dialog/popover保留普通按钮,缺失时加一个事件监听调用现有方法
dialog.requestClose()发出可取消关闭请求,统一 Escape/按钮关闭策略缺失时调用 close(),未保存检查放共同函数
contenteditable="plaintext-only"允许纯文本编辑并拒绝富文本粘贴服务端仍验证长度/内容;旧浏览器回退 textarea 更可靠
::details-content样式化 details 展开内容不支持时 details 开合仍可用,只损失动画/样式
Declarative Shadow DOM服务端用 template 声明 Shadow Root无组件封装需求不引入;SSR/旧目标需明确 polyfill/回退

Popover 与 Invoker Commands 已列入 Baseline 2025,但“Newly available”不等于满足每个产品浏览器政策。固定 Baseline 年份或真实用户浏览器范围比“最新版浏览器”更可审查。Baseline 2025

可定制 select、部分锚点定位/interest invocation 等能力仍可能处于实现推进或跨引擎差异阶段。实验或单引擎实现只能作为增强,不能让选择值、键盘操作或表单提交依赖它;文档必须记录测试版本和回退,不以截图证明可访问性。

功能检测应检测具体契约:

const supportsPopover = 'popover' in HTMLElement.prototype;
const supportsDialog = typeof HTMLDialogElement !== 'undefined'
  && 'showModal' in HTMLDialogElement.prototype;
const supportsInvoker = 'commandForElement' in HTMLButtonElement.prototype;

if (!supportsInvoker && supportsDialog) {
  document.querySelector('[command="show-modal"]')?.addEventListener('click', () => {
    document.querySelector('#html-detail')?.showModal();
  });
}

检测通过只说明 API 形状存在,不证明辅助技术、嵌套 top layer、移动键盘或企业内核行为满足产品要求。关键交互仍要在目标浏览器与屏幕阅读器组合上测试。

解析与交互中最危险的兼容陷阱

HTML Living Standard 没有应用框架式的 major 迁移,但平台变化仍会让旧假设失效。以下问题属于行为风险,不应被当作标签知识:

现象根因修正与回归证据
在解析期间调用 document.write() 后文档被覆盖它可能重新打开已完成文档,第三方脚本还会阻塞解析删除调用;用模块和 DOM API;比较调用前后 DOM 与导航时间线
自定义元素升级前后布局或属性状态闪动元素可先以 unknown element 解析,定义注册后再 upgrade保留可读 HTML 基础结构,用 :defined 只处理增强视觉,不隐藏核心内容
服务端与客户端生成的表格 DOM 不一致Tree Builder 会在表格插入模式重排非法子节点修正内容模型,不用水合忽略选项掩盖差异
dialog、Popover 或 Invoker Commands 在旧目标浏览器失效新原语独立进入各引擎,支持时间不同方法级特性检测;回退仍保留链接、表单和正文
仅用 ARIA 重写按钮或链接角色ARIA 不自动补键盘、激活、表单和焦点行为换回原生元素;键盘与 Accessibility 树共同验收

解析器的兼容承诺很强,因此严重问题通常来自“依赖容错结果”而非规范突然重构。升级浏览器或引入 SSR/水合框架时,回归重点应是解析后 DOM、焦点顺序、表单提交和脚本时序,而不是只对源 HTML 做字符串快照。Custom elementsDynamic markup insertion

原生语义与脚本增强的职责表

需求首选原生能力何时增加 JavaScript不建议做法
页面导航<a href>客户端路由确实需要保留应用状态时点击 div 后修改 location
提交筛选GET <form>即时筛选与无刷新状态同步时删除 name,只在内存保存条件
展开补充内容<details>需要跨区域协调状态时自造折叠状态机
模态任务<dialog>.showModal()打开、装载动态内容与恢复焦点时div role="dialog" 从零实现
非模态浮层Popover数据驱动定位或复杂生命周期时用极大 z-index 管理层级
常见输入约束类型与约束属性跨字段、异步规则时仅靠正则和提交事件
二维数据<table>排序、虚拟化、编辑时用 Grid 模拟表格语义

原生能力并不意味着“零 JavaScript”,而是让 JavaScript 只负责数据和协调。若交互已经发展成大量可复用复合控件、跨页面状态和服务端渲染约束,再进入框架选型;不要把单个筛选页的复杂度提前外推成框架需求。

浏览器验证练习

  • 在 DevTools 中找出源文本与解析后 DOM 的一处差异,并解释 Tree Builder 为何这样修复。
  • 分别使用普通、deferasync 和模块脚本记录执行顺序及 DOMContentLoaded 时间。
  • 仅使用键盘完成跳过导航、搜索提交、详情打开与关闭,确认焦点可见且顺序合理。
  • 临时禁用 JavaScript,确认标题、功能说明和文章入口仍然可读。
  • 用 Accessibility 面板核对搜索框、对话框、表格的角色与可访问名称。
  • 绕过页面直接构造无效请求,说明为什么服务端验证不可删除。
  • 对不支持 Invoker Commands 的浏览器写一次特性检测,并保证增强失败不影响基本内容。

验收问题:为什么解析阻塞脚本会影响 DOM 构建?dialog 与 Popover 的模态性有什么差异?aria-label 何时不如可见 <label>?如果不能分别从解析算法、平台行为和用户操作回答,就应回到示例复现,而不是背标签列表。

HTML 规范与平台资料

  • HTML Living Standard:元素、解析、脚本、表单与交互的规范来源;核验于 2026-06-30。
  • HTML Parsing:Tokenizer、Tree Builder、插入模式与脚本重入;核验于 2026-06-30。
  • ARIA in HTML:HTML 元素允许的 ARIA 角色和属性;核验于 2026-06-30。
  • Constraint Validation:原生约束、API 与服务端复验边界;核验于 2026-06-30。
  • Popover API:声明式控制、light dismiss 与可访问性;核验于 2026-06-30。
  • Web Platform Baseline:按跨浏览器可用时间评估平台能力;核验于 2026-06-30。
在 GitHub 上编辑此页

本页目录