高性能 HTML

发布于 南北

在阅读本文之前,你是怎样优化网页的呢?

大多数开发者的焦点集中于 JavaScript、图片、服务器配置、文件压缩合并,甚至是 CSS。

虽然 HTML 是前端技术的核心之一,但却一直没有得到应有的重视。

HTML 的体积日渐臃肿。目前,全球访问量前 100 的网站每个页面大概有 40kB 的大小,类似亚马逊和雅虎这样的网站,甚至每个页面包含了数千行的 HTML 代码。最近,youtube 主页的 HTML 代码量甚至达到了惊人的 3.5K 行(翻译本文时已达到了 4.8K 行)。

降低 HTML 的复杂度以及代码量,并不会直接改善解析性能——但是,对于创建快速响应和适配多种尺寸的页面来说,精心构建的 HTML 是至关重要的基础。

在本文中,你能学到怎样编写简洁精练的 HTML,进而实现快速加载页面和兼容多种设备尺寸。在整个过程中,你也会了解到怎样构建易于调试和维护的网站或应用。

编写代码的方式从来都不会固定的,尤其是对于 HTML 更是如此。在本文中,不会直接介绍那些通识或公认的教条,而是直接从我们的工作中的最佳实践出发。对于每一条建议,请具体情况具体采纳。

概述

  • 结构分离:使用 HTML 实现页面结构而不是添加表现样式;
  • 用法准确:在开发中使用代码校验工具
  • 逻辑清晰:对于代码结构和格式采用相同的工具编程规范,保持开发和维护的一致性。
  • 标记合理:合理正确地使用语义化标签
  • 确保可用:使用ARIA作为备用选项。在只能查看文本内容的浏览器,或者使用屏幕阅读器,测试当前网站。
  • 多维测试:使用模拟器模式性能检测工具,在多种设备和屏幕尺寸上测试网站。

性能检测工具

HTML、CSS 和 JavaScript

HTML 只是一门标记语言,用以添加结构和内容。

HTML 不应该用于美化内容的表现样式。永远不要将标题标签用于“放大字体”,或者使用引用标签表现缩进。与之相反,应该使用 CSS 表现表现和布局样式。

浏览器会使用默认的样式表来渲染 HTML 元素:Chrome、Firefox、Internet Explrer 和 Opera 都拥有各自的默认样式。比如,在 Chrome 中,h1 标签默认的表现样式为 32px bold Times

通用三原则:

  • 使用 HTML 构建结构,使用 CSS 渲染样式,使用 JavaScript 控制行为。CSS ZenGarden 上展示了许多基于该原则的实例。
  • 先使用 HTML 构建,当需要渲染样式时使用 CSS,如果确有必要,再使用 JavaScript。比如,大多数情况下,会使用 HTML 验证表单,使用 CSS 或者 SVG 实现验证动效——由此就无需使用 JavaScript 了。
  • 将 CSS 和 JavaScript 文件与 HTML 分离。这种分离有助于代码复用和调试。在上线前,可以通过构建简称压缩和合并 CSS、JavaScript 文件。

文档结构

使用 HTML5 文档类型。下面是一个基本框架:

<!DOCTYPE html>
<html>

<head>
 <title>Recipes: pesto</title>
</head>

<body>

  <h1>Pesto</h1>

  <p>Pesto is good!</p>

</body>
</html>

在 Head 中引入相关的 CSS 文件:

<head>
  <title>My pesto recipe</title>

  <link rel="/css/global.css">
  <link rel="css/local.css">

</head>

使用这种方式,有助于浏览器在解析 HTML 前加载和解析 CSS。

将对 JavaScript 文件的引用置于页面底部,在闭合 body 标签之前——这样做有助于浏览器在解析 JavaScript 之前渲染页面,进而提高加载速度,也有助于在执行 JavaScript 之前,保证页面加载完成:

<body>

  ...

  <script src="/js/global.js">
  <script src="js/local.js">

</body>

不要使用内联形式的 JavaScript:

<head>
  
  ...

  <script src="js/local.js">

</head>

<body onload="init()">

  ...

  <button onclick="handleFoo()">Foo</button>

  ...

</body>

下面的形式编程方法更好:

index.html

<head>

  ...

</head>

<body>

  ...

  <button id="foo">Foo</button>

  ...

  <script src="js/local.js">

</body>

js/local.js

init();
var fooButton =
    document.querySelector('#foo');
fooButton.onclick = handleFoo();

校验

Web 技术能够流行的一个重要因素就在于,浏览器可以处理一些无效的 HTML 语法,甚至专门有一个标准规范规定浏览器应对无效代码的解决方案

然而,这并非我们可以为所欲为的借口。有效的 HTML 代码更易于调试,通常也更简洁,易于解析和渲染。无效的 HTML 代码往往让响应式设计难以实现。

编写有效的 HTML 代码对使用模板也非常重要:某些独立代码虽然看起来不错,但引用到其他文件进行解析时可能就会出现大量错误。

  • 将校验纳入工作流:使用类似 HTMLHint 和 [SublimeLinter] 的校验插件校验代码,同时可以在 Grunt 中使用 HTMLHint 进行校验。
  • 使用 HTML5 文档类型;
  • 确保良好的层次结构便于后期维护:正确嵌套元素,确保所有元素正确闭合。这有助于给大段代码添加注释方便调试,特别是使用模板的情况下:
<div id="foobar">

...

</div> <!-- foobar ends -->

确保正确闭合那些不能自闭和的元素:

比如下面这段代码:

<p>Pesto is good to eat...
<p>...and pesto is easy to make.

建议使用如下形式,减少出现错误的可能性:

<p>Pesto is good to eat...</p>
<p>...and pesto is easy to make.</p>

虽然列表项不必使用闭合标签,甚至一些开发者认为你不用在意它。但无论如何,建议你关闭每一个列表项:

<ul>
  <li>Basil
  <li>Pine nuts
  <li>Garlic
</ul>

videoaudio 标签是必须闭合的元素,它们不具有自闭和的特性:

<!-- wrong: liable to cause layout grief -->
<video src="foo.webm" />

<!-- better -->
<video src="foo.webm">
  <p>Video element not supported.</p>
</video>

与上述相反的一些建议是,去掉冗杂代码:

  • 没有必要为类似 <img><link> 的标签添加闭合标签,更多类似标签请参考这里
  • 布尔值属性无需明确指出具体的值:如果填写了该属性,那么就表明了是 true。

下面的代码表示不能自动播放,也没有控制按钮:

<video src="foo.webm">

下面的代码并不能实现禁止自动播放和禁用控制按钮,因为只要出现相关属性就会被强制赋值为 true

<video src="foo.webm" autoplay="false" controls="false">

下面是正确的:

<video src="foo.webm" autoplay="true" controls="true">

下面的代码更具有可读性:

<video src="foo.webm" autoplay controls>

无需为样式表和脚本引用代码添加类型属性:CSS 和 JavaScript 本身就是默认值。当使用外部内容时省略协议信息:有助于避免混合内容出现的错误。用法举例:

<a href="//en.wikipedia.org/wiki/Tag_soup">Tag soup</a>

编码格式

一致的代码格式有助于理解、优化和调试。

  • 项目成员共用同一个 HTML 编码格式,也可以使用类似谷歌的既有代码格式。
  • 使用编辑器自动美化代码。比如,在 Sublime Text 添加快捷键实现快速缩排。还可以使用类似 SublimeLinterCSS BeautifyJS Beautify 的代码审查工具检查布局。
  • 不用反感 HTML 层次分明的缩进排列。在开发前使用合理的默认间距即可摆脱这个问题。相反的是,如果层次结构特别深,那么你就需要考虑重构了。
  • 统一缩进格式,使用 tab 或空格,不要两者兼具。
  • 使用有意义的嵌套改善可读性。比如,下面的代码清晰地表明了这是一个标题:
<h2><a href="/contact">Contact</a><h2>

而下面的代码则像是一个链接:

<a href="/contact"><h2>Contact</h1></a>
  • 使用合理的顺序排列元素,不致于误导后期维护的开发者,甚至是许久之后回顾这段代码的你。比如,footer 标签虽然可以置于任何地方,但你应该将它置于页面底部。
  • 统一使用单引号或双引号。
  • 标签和属性名使用小写形式,阅读大写形式往往带来疲惫感:
<A HREF="/">Home</A>

没有比混合两种形式更糟的情况了:

<H2>Pesto</h2>

语义化标签

语义化,意味着见名知意。

HTML 标签为页面内容增加了含义:元素和属性名表述了对内容的角色定位。

HTML5 引入了一系列的语义化标签,比如 <header><footer><nav>

使用正确的标签包裹内容,既有利于可用性,也确保了代码的可读性。

  • 使用 <h1><h2><h3>……)创建标题,使用 <ul><ol> 创建列表。
  • <article> 标签内应该有一个类似 <h1> 的标题标签(点击查看相关文章)。
  • 合理运用语义化标签,比如 <header><footer><nav><aside>
  • 使用 <p> 标签创建文本内容,使用其他语义标签创建结构框架(如果没有适当语义化标签,可以使用 <div>)。
  • 在表单中明确 <label> 标签、输入类型、占位符文本和其他所需的属性,形成良好的验证机制(更多信息请参考这里)。
  • 混合标签和文本的写法,有可能会制造布局错误,比如下面这样:
<div>Name: <input type="text"></div>

下面是更好的编写方式:

<div><label>Name:</label><input type="text"></div>

布局

有必要再次重申:HTML 应该用于语义化和创建页面结构,而不是美化样式。

  • 使用 <p> 标签创建文本,而不是创建布局。<p> 一般会被浏览器默认样式提那家外边距和其他样式。
  • 避免使用 <br> 进行断行:使用块级元素或者 CSS display 属性代替。<br> 只应该被使用到文本之内,即使如此,也应该尽少使用。
  • 避免使用 <hr> 添加水平分割线:CSS border-bottom 更适合做这件事。使用 <hr> 往往代表着分割不同的主题
  • 不要添加冗余的 <div>: W3C HTML 规范表述 <div> 是一种后背元素,当没有其他适合元素可以使用时,方可使用过它。对于类似 <a><img> 这样的行内元素,可以通过 display: block,而不是将其放入 <div> 中,更不要随意添加 <br>
  • 深入了解具体的块级元素,避免不必要的包裹,比如将列表放入 <div> 中。
  • 不要使用表格标签来布局,而应该使用表格来表现表格数据。
  • Flex 已经收到了广泛的支持,请使用它!
  • 统一外边距:为元素添加底边和右边的外边距是非常棒的实践,而不是添加顶部和左边的外边距。无论你使用哪种方式,避免混合使用各边外边距。使用 :last-of-type 选择器避免冗余外边距。

HTML email

开发邮件和开发网页完全是两回事。

本文中我们不会深入探讨相关的细节——可以说开发 HTML email 的最佳实践和上个世纪九十年代非常类似:表格、GIFs、不一致和压缩的 CSS,以及大量的补丁(可以点击这里查看来自 MailChimp 的模板示例)。

更多信息请点击这里这里这里

CSS

虽然本文主讲 HTML,但这里有必要穿插一些基础的 CSS 知识:

  • 避免使用行内 CSS。为了优化性能,可以将 CSS 文件融入你的构建流程中。
  • 只能有一个 ID 选择器,且只能使用一次。
  • 当定义多个同类元素时,使用 Class 选择器,更多信息请参考 BEM 语法。尽量在父级元素使用 Class 选择器,而不是子元素上。举例如下:
<!-- verbose :( -->
<ul>
  <li class="ingredient">Basil</li>
  <li class="ingredient">Pine nuts</li>
  <li class="ingredient">Garlic</li>
</ul>
  
<!-- better :) -->
<ul class="ingredients">
  <li>Basil</li>
  <li>Pine nuts</li>
  <li>Garlic</li>
</ul>

可用性

充分考虑页面在多种设备、环境和输入方式中的交互体验。

  • 使用语义化标签。
  • 提供预备方案:使用跟踪式导航添加标题和子标题,为视频和音频标签添加提示文字或图片;为视频元素使用海报图片;为图片添加 alt 属性(如果图片只是用来装饰的,该属性可以置空)。
  • 为链接标签添加 title 属性——当且仅当该属性有意义,同时不要重复链接内容。
  • input 标签中添加 typeplaceholder 属性。
  • 使用 ARIA 属性

其他建议

  • 确保 HTML 中的特殊字符得到正确转义,比如 <& 字符。正确使用方法:<title>HTML &amp; JavaScript</title>
  • 与上一条相反的是,无需编码连字符之类的特殊符号,或者是货币符号。
  • 当且仅当代码无法见名知意时添加注释(牢记,注释利于重构,优秀的 HTML 代码,即使复杂,依然通俗易懂)。
  • 对于需要全大写的地方,可以使用 CSS 的 text-transformfont-variant 属性来实现,而不是直接输入大写文本。毕竟需求是多变的!当用户拷贝文本时,它们可能想要大小写混合的形式。下面的 <h4> 标签被显示为小写形式,但拷贝使用时则是大小写混合形式的:

HTML:

<h4>W3C Web Accessibility Initiative ARIA guidance</h4>

CSS:

h4 {
  font-variant: small-caps;
}

最后

无论你写了什么,记得测试!

将 HTML 测试流程融入你的工作流、工具链和发布管程中。

在不同的设备上测试,在不同的屏幕尺寸上测试,甚至做到在不同网络环境下测试。使用类似 Lynx 只能使用显示文本的浏览器,或者是类似 ChromeVox 的屏幕阅读器,测试页面的交互体验。使用类似谷歌开发者工具的模拟器模式监视变动。还可以将 Page SpeedWeb Page Test 等工具融入工作流中,实现项目上线前的自动测试。

编写高性能 HTML 的知识,请参考 HTML,CSS and JavaScript resourcesWeb Fundamentals

本文根据@Sam Dutton的《High performance HTML》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:https://samdutton.wordpress.com/2015/04/02/high-performance-html/

南北

在校学生,本科计算机专业。狂热地想当一名作家,为色彩和图形营造的视觉张力折服,喜欢调教各类JS库,钟爱CSS,希望未来加入一个社交性质的公司,内心极度肯定“情感”在社交中的决定性地位,立志于此改变社交关系的快速迭代。个人博客

如需转载,烦请注明出处:https://www.fedev.cn/performance/high-performance-html.htmlAdidas Energy Boost