12k
All articles

现代 HTML 样板代码应包含哪些内容

了解现代 HTML 基础模板必备的五项内容,以及实用元数据、网站图标和社交标签;掌握旧模板中应保留、添加或删除的代码。

OpenReplay Team
OpenReplay Team
现代 HTML 样板代码应包含哪些内容

一份现代 HTML 样板代码必须包含五项内容:HTML5 doctype、<html> 上的 lang 属性、UTF-8 字符集声明、viewport meta 标签,以及一个唯一的 <title>。其余内容则取决于页面是否会被分享、安装或加入书签。

大多数页面都是从 Emmet 的 ! 代码片段、某个框架自带的 index.html,或是一份已有十年历史的 HTML5 Boilerplate 副本起步的。很少有人回头检查这些代码行,于是过时的写法就在一个又一个项目之间被复制下去。

本文将逐行梳理整个文档。对每一行,我们会说明它的作用、缺少它会出什么问题,以及它属于必需、可选还是可以安全删除。关于 head 中元素的排列顺序以及更全面的元数据话题,请参阅配套文章文档 head 中真正应该放什么。

以下是 Emmet 的 ! 生成的内容:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>

</body>
</html>

这是一个合法的起点。不过,它没有 description、canonical、社交标签、图标或 color-scheme,而且它的 viewport 中还包含一个如今已不再需要的值。

核心要点

  • 现代 HTML 样板代码中的必需项是 doctype、lang、<meta charset="UTF-8">、viewport 标签和 <title>。缺少其中任何一项,页面都会渲染错误、可访问性下降或不符合规范。
  • lang 属性控制屏幕阅读器的发音、CSS 断字以及浏览器翻译。Google 不会用它来检测页面语言。
  • maximum-scale、minimum-scale 和 user-scalable=no 会阻止低视力用户缩放页面。无论出现在哪里,都应将其删除。
  • 完整的 favicon 套件包括 favicon.ico、favicon.svg、一个 180×180 的 apple-touch-icon.png,以及一个包含 192 和 512 像素图标外加一个 maskable 图标的 Web 应用清单(manifest)。
  • X-UA-Compatible、shrink-to-fit=no 和 type="text/javascript" 在新项目中毫无用处,可以删除。

Doctype 与 lang 属性

必需。 <!DOCTYPE html> 会让浏览器切换到标准模式。缺少它时,HTML 解析器会回退到怪异模式(quirks mode),复现旧版浏览器的布局 bug。随之而来的就是盒模型和表格尺寸上的差异,任凭你怎么调试 CSS 都找不出原因。

必需。 <html> 上的 lang 属性承担三项职责:

  • 告诉屏幕阅读器应采用哪种发音规则。
  • 让 CSS hyphens: auto 使用正确的词典进行断字。
  • 帮助浏览器的翻译功能识别页面语言。

缺少它时,屏幕阅读器可能会用英语发音来朗读法语文本。其取值为 BCP 47 语言标签,例如 en、de 或 pt-BR,并且子元素可以覆盖该值,详见 MDN 的 lang 参考文档。

lang 关乎可访问性和语言,与搜索排名无关。Google 搜索明确表示,它会忽略 lang,而是根据页面内容来检测语言。

<!DOCTYPE html>
<html lang="en">

先写 Charset,再写 Viewport

必需。 <meta charset="UTF-8"> 必须位于文档的前 1024 个字节之内。这就是它要放在 <head> 最前面的原因——它必须先于 <title> 以及其他任何可能被浏览器以错误编码解码的文本。如果缺少它或位置太靠后,标题中的重音字符和 emoji 就会变成乱码。

必需。 viewport 标签告诉移动端浏览器按设备宽度来布局页面。缺少它时,手机会以桌面宽度(通常约 980px)渲染布局再整体缩小,导致你的媒体查询永远不会生效。仅使用 width=device-width 就已足够,initial-scale=1 通常是多余的。完整的取值列表请参阅 MDN 的 viewport 参考文档。

<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">

可选,需先测试。 <meta name="text-scale" content="scale"> 定义于 CSS Fonts Level 5 草案中,目前只有基于 Chromium 的浏览器支持。它会让根字号跟随用户在操作系统或浏览器设置中选择的文字大小。因此,只有使用 rem 和 em 的文字会放大,而固定高度的组件可能会出现内容溢出。上线之前,请先调大系统文字大小并检查你的布局。

Title、Description 与 Canonical

必需。 <title> 用于在浏览器标签页、书签、历史记录和搜索结果中标识页面。如果保留默认的 Document,你打开的每个标签页看起来都一模一样。

可选但推荐。 <meta name="description"> 为搜索结果摘要提供一段概述。如果 Google 发现页面内容更贴合搜索查询,它可能会改写这段摘要,并且会按显示宽度来截断摘要。因此,基于字符数的规则并不可靠。

可选但推荐。 当同一内容可通过多个地址访问时(例如带查询字符串或末尾斜杠不同的变体),<link rel="canonical"> 用于指定首选 URL。更多细节请参阅与 SEO 相关的 HTML 标签及其优化方法。

<title>Page title – Site name</title>
<meta name="description" content="One or two sentences describing this page.">
<link rel="canonical" href="https://example.com/page">

Open Graph 与 Twitter Card 标签

可选,但凡是会被分享的页面都必需。 Open Graph 标签控制链接在社交平台和聊天应用中的预览效果。缺少它们时,分享出去的链接要么只显示一个光秃秃的 URL,要么显示一张由爬虫随意抓取内容拼凑出的卡片。

Open Graph 协议将 og:title、og:type、og:image 和 og:url 列为必需属性,并规定未声明类型的页面应视为 website。请将 og:url 设置为与 canonical URL 相同的值,这样带有跟踪参数的链接就不会被当作独立页面缓存。对于 og:image,Meta 建议使用至少 1200×630 像素、比例接近 1.91:1 的图片。

X 会读取它自己的 twitter:* 标签(使用 name 而非 property 编写),缺失时则回退到对应的 og:* 值。实际上,你唯一需要的 X 专属标签是 twitter:card,而且只有在你想要大图卡片时才需要。

<meta property="og:title" content="Page title">
<meta property="og:description" content="Description for link previews.">
<meta property="og:image" content="https://example.com/og-image.jpg">
<meta property="og:url" content="https://example.com/page">
<meta name="twitter:card" content="summary_large_image">

如需为每个页面生成这些标签,可以使用 meta 标签生成器。

Favicon 套件

可选,但属于标配。 一套完整的 favicon 配置包含四个部分。如果省略,你会看到空白的标签页图标、iOS 主屏幕上截图式的图块,以及 Android 上千篇一律的安装图标。

两个 <link rel="icon"> 元素都要保留:一个指向 favicon.ico,一个指向 favicon.svg。这样,无法使用 SVG favicon 的浏览器(包括 26 版之前的 Safari)仍然可以拿到 ICO 文件。

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
  <style>
    circle { fill: #1a1a2e; }
    @media (prefers-color-scheme: dark) {
      circle { fill: #f5f5f5; }
    }
  </style>
  <circle cx="16" cy="16" r="14"/>
</svg>
{
  "name": "Site name",
  "short_name": "Site",
  "icons": [
    { "src": "/icon-192.png", "sizes": "192x192", "type": "image/png" },
    { "src": "/icon-512.png", "sizes": "512x512", "type": "image/png" },
    { "src": "/icon-maskable-512.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" }
  ]
}

关于如何生成上述每个文件,请参阅如何为网站添加 favicon。

color-scheme 与 theme-color

可选,如果提供深色模式则推荐使用。 <meta name="color-scheme" content="light dark"> 会在任何 CSS 加载之前告诉浏览器,该页面同时支持浅色和深色两种模式。这样,默认背景、表单控件和滚动条都会跟随用户的偏好设置。缺少它时,深色主题的网站在加载时可能会闪现一下白色画布。详见 MDN 关于 color-scheme 的说明。

可选。 theme-color 用于为浏览器 UI 着色,并且支持 media 属性,因此你可以分别设置浅色和深色的值。它在 Android 上的 Chromium 中有效,但 MDN 将其浏览器支持度标注为有限,所以应将其视为锦上添花的功能,而不要指望所有浏览器都会显示。

<meta name="color-scheme" content="light dark">
<meta name="theme-color" content="#ffffff" media="(prefers-color-scheme: light)">
<meta name="theme-color" content="#111111" media="(prefers-color-scheme: dark)">

默认减弱动效

可选,强烈推荐。 默认减弱动效是写在基础样式表中的一条规则,而不是 head 中的标签。之所以把它放进样板代码,是因为事后几乎没人会再回头补上。一个 prefers-reduced-motion: reduce 代码块可以为那些在操作系统中要求减少动效的用户缩短动画和过渡时长,并关闭平滑滚动。

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

时长被设为 0.01ms 而不是 0,是为了让 animationend 和 transitionend 事件依然能够触发。这样一来,等待这些事件的 JavaScript 就不会卡住。这是一种比较粗放的默认做法。个别组件可以重新启用不会引发前庭不适的轻柔动效,例如透明度渐变。

应该从旧样板代码中删除哪些行?

删除。 旧 HTML 样板代码中有四类代码行源自 IE 时代的模板和早期的响应式入门模板,如今都已毫无用处:

  • X-UA-Compatible 用于选择 Internet Explorer 的文档模式。你需要支持的浏览器中没有任何一个会读取它。
  • maximum-scale、minimum-scale 和 user-scalable=no 会阻止低视力用户双指缩放,这与 WCAG 1.4.4 调整文本大小的要求背道而驰。请从所有 viewport 标签中移除它们。
  • shrink-to-fit=no 曾用于规避旧版 iOS Safari 的缩放行为,如今已不再起任何作用。
  • type="text/javascript" 只是重复了默认值。HTML 规范要求开发者在经典脚本中省略 type。
<!-- Before -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, shrink-to-fit=no">
<script type="text/javascript" src="/app.js"></script>

<!-- After -->
<meta name="viewport" content="width=device-width">
<script type="module" src="/app.js"></script>

type="module" 脚本默认是延迟执行的,因此它会在解析完成后运行,不会阻塞渲染。如果某个脚本无法作为模块使用,请为它加上 defer。

完整的 HTML 样板代码

下面这份完整的现代 HTML 样板代码整合了本文中所有必需和推荐的代码行。你可以按需在此基础上添加站点特有的内容,例如订阅源或预加载。跳转链接(skip link)和 <main> 地标放在 body 中,接下来要用到的语义化元素可参阅 10 个必备 HTML 元素。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width">
  <!-- Optional, test with large OS text first: <meta name="text-scale" content="scale"> -->
  <title>Page title – Site name</title>
  <meta name="description" content="One or two sentences describing this page.">
  <link rel="canonical" href="https://example.com/page">

  <meta name="color-scheme" content="light dark">
  <meta name="theme-color" content="#ffffff" media="(prefers-color-scheme: light)">
  <meta name="theme-color" content="#111111" media="(prefers-color-scheme: dark)">

  <link rel="stylesheet" href="/styles.css">
  <script type="module" src="/app.js"></script>

  <link rel="icon" href="/favicon.ico">
  <link rel="icon" href="/favicon.svg" type="image/svg+xml">
  <link rel="apple-touch-icon" href="/apple-touch-icon.png">
  <link rel="manifest" href="/site.webmanifest">

  <meta property="og:title" content="Page title">
  <meta property="og:description" content="Description for link previews.">
  <meta property="og:image" content="https://example.com/og-image.jpg">
  <meta property="og:url" content="https://example.com/page">
  <meta name="twitter:card" content="summary_large_image">
</head>
<body>
  <a href="#main">Skip to content</a>
  <main id="main"></main>
</body>
</html>
代码行作用缺少时的问题结论
Doctype标准模式怪异模式布局必需
lang发音、断字、翻译屏幕阅读器发音错误必需
charset声明 UTF-8 编码字符乱码必需
viewport按设备宽度布局手机上显示缩小的桌面布局必需
<title>为页面命名标签页和书签全都一样必需
Description、canonical搜索摘要与首选 URL摘要效果变差、URL 重复可选
Open Graph、twitter:card链接预览光秃秃或千篇一律的卡片可选
Favicon 套件标签页和主屏幕图标空白或截图式图标可选
color-scheme原生深色模式白屏闪烁、浅色控件可选
X-UA-Compatible、缩放限制、shrink-to-fit、type="text/javascript"遗留的兼容性写法无删除

一份 HTML 样板代码中只有五行是必需的。其余内容要么是可选项(取决于页面是否会被分享、安装或设置主题),要么是应当删除的遗留代码。打开你当前项目的 index.html,对照上表逐行检查,并在把这个文件复制到下一个项目之前,删掉所有属于”删除”一栏的内容。

常见问题

meta charset 与 meta http-equiv Content-Type 是一回事吗?

是的。根据 WHATWG HTML 规范,http-equiv Content-Type 写法与 charset 属性的作用相同。两者都属于字符编码声明,也都必须位于文档的前 1024 个字节之内。一个文档中不能同时包含两者,否则验证器会将其标记为错误。请使用更简短的 meta charset='UTF-8'。如果服务器在 HTTP Content-Type 响应头中发送了字符集,请确保它同样是 UTF-8。

HTML 中的 meta 和 link 标签需要加结尾斜杠吗?

不需要。meta、link、img 以及其他空元素都没有闭合标签,HTML 解析器会忽略它们末尾的斜杠。带斜杠和不带斜杠的同一个标签会生成完全相同的元素。斜杠是合法的,但不起任何作用,因此加不加纯属代码风格问题。唯一有影响的情况是以 XML MIME 类型作为 XHTML 提供的页面。

可以省略 html、head 和 body 标签吗?

可以。HTML 规范在很多情况下将 html、head 和 body 标签标记为可选,即使缺少这些标签,解析器也会自动创建对应的元素。但样板代码仍应将它们写出来。lang 属性需要一个显式的 html 开始标签作为载体,而且显式的标签能让 head 与 body 之间的边界更加清晰易读。如果省略 html 标签,lang 也就随之丢失了。

如何修改 Emmet 的 ! 代码片段中默认的 lang 值?

在 VS Code 的 emmet.variables 设置中配置 lang 变量。在 settings.json 中,向 emmet.variables 对象添加一个 lang 键,并设置诸如 de 之类的值,此后 Emmet 每次展开 ! 代码片段时都会写入该语言代码。同一设置中还有一个 charset 变量,请保持其为 UTF-8。viewport 行中仍然包含 initial-scale=1.0,因此需要手动删除,或者自定义一个代码片段。

Open-source session replay

Gain control over your UX

See how users are using your site as if you were sitting next to them, learn and iterate faster with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.