标准HTML页面骨架必须满足五个硬性条件:①<!DOCTYPE html>须首行无空格/注释;②<html lang="zh-CN">不可省略且值须精确;③<meta charset="UTF-8">须为<head>首个标签;④<meta name="viewport">须在charset后;⑤<main>须唯一、不嵌套、含标题。

标准 HTML 页面骨架不是“写完就能跑”,而是必须满足五个硬性条件才能被浏览器正确解析、被搜索引擎识别、被屏幕阅读器理解——缺一不可。
DOCTYPE 和 lang 属性为什么不能省
不写 ,浏览器会进入怪异模式(Quirks Mode),CSS 盒模型、<code>getBoundingClientRect() 行为、甚至 Flex 布局都可能错乱;不写 lang="zh-CN",屏幕阅读器发音不准,SEO 工具会降权,Chrome 的翻译按钮也可能不触发。这两个属性必须出现在第一行和 标签上,中间不能有空行或注释。
-
lang值要精确:中文用zh-CN,繁体用zh-TW,别写成zh或cn - 如果页面含多语言内容(如中英双语段落),可在局部用
lang="en"覆盖 - VS Code 里敲
!+ Tab 自动生成的骨架默认是lang="en",务必手动改掉
head 里三个 meta 必须按顺序写
<meta charset="UTF-8"> 必须是 中第一个标签,否则浏览器可能用 ISO-8859-1 解析,导致中文全乱码;<meta name="viewport" content="width=device-width, initial-scale=1.0"> 必须在 charset 之后、<title></title> 之前,否则移动端缩放失效;<title></title> 可以放在最后,但不能缺失——没有 <title></title> 的页面,浏览器标签页显示为空白,SEO 直接判为低质页。
- 不要把
charset放到title后面,某些旧版 Safari 会忽略 -
viewport的content值里别加多余空格,比如" width=device-width "会导致部分 Android WebView 解析失败 - 如果用 Webpack/Vite 构建,
html-webpack-plugin默认不生成viewport,得手动配meta选项
body 里唯一性与嵌套陷阱
<main></main> 必须且只能出现一次,且不能嵌套在 <header></header>、<footer></footer>、<nav></nav> 或另一个 <main></main> 里。常见错误是把整个页面包进 <main></main>,结果导航栏、页脚也被算作“核心内容”,破坏语义。正确做法是只包裹真正不可替代的内容区块,比如博客正文、商品列表、表单主区域。
立即学习“前端免费学习笔记(深入)”;
- 如果页面是单页应用(SPA),
<main></main>应包裹<div id="app"></div>,而不是反过来 -
<main></main>内部可以有多个<article></article>,但每个<article></article>必须自带标题(<h2></h2>~<h6></h6>) - Chrome DevTools 的 Accessibility 面板里,点开
<main></main>节点,如果显示 “No accessible name”,说明它没包含可读标题,需补<h1></h1>或aria-labelledby
section 和 article 的区分关键在“能否独立分发”
一个 <section></section> 是为组织内容而存在,比如“产品特性”“用户评价”;一个 <article></article> 是为独立存在而设计,比如一篇博客、一条新闻、一个评论。判断标准很简单:把它复制出来单独保存为一个 .html 文件,是否仍有完整意义?能,就是 <article></article>;不能,就是 <section></section>。
- 别用
<section></section>包裹单个<p></p>—— 没标题的<section></section>是无效语义,Lighthouse 会报错 -
<article></article>可以嵌套在<section></section>里,但反过来不行:<section></section>不能作为<article></article>的直接子元素 - RSS 订阅器只抓取
<article></article>,所以博客首页的每篇文章必须用<article></article>包裹,而非<div class="post"> <p>最容易被忽略的是嵌套合法性:HTML5 规范对哪些标签能包哪些标签有明确限制,浏览器虽会自动修正(比如把 <code><div> 里的 <code><h1></h1>提升到最近的节根),但修正后的 DOM 和你写的源码不一致,JS 查询document.querySelector('main h1')可能返回 null——这种问题只在真实设备上调试时才暴露。



















