高性能 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>
video
和 audio
标签是必须闭合的元素,它们不具有自闭和的特性:
<!-- 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 添加快捷键实现快速缩排。还可以使用类似 SublimeLinter、CSS Beautify 或 JS 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>
进行断行:使用块级元素或者 CSSdisplay
属性代替。<br>
只应该被使用到文本之内,即使如此,也应该尽少使用。 - 避免使用
<hr>
添加水平分割线:CSSborder-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
标签中添加type
和placeholder
属性。 - 使用
ARIA
属性。
其他建议
- 确保 HTML 中的特殊字符得到正确转义,比如
<
和&
字符。正确使用方法:<title>HTML & JavaScript</title>
。 - 与上一条相反的是,无需编码连字符之类的特殊符号,或者是货币符号。
- 当且仅当代码无法见名知意时添加注释(牢记,注释利于重构,优秀的 HTML 代码,即使复杂,依然通俗易懂)。
- 对于需要全大写的地方,可以使用 CSS 的
text-transform
和font-variant
属性来实现,而不是直接输入大写文本。毕竟需求是多变的!当用户拷贝文本时,它们可能想要大小写混合的形式。下面的<h4>
标签被显示为小写形式,但拷贝使用时则是大小写混合形式的:
HTML:
<h4>W3C Web Accessibility Initiative ARIA guidance</h4>
CSS:
h4 {
font-variant: small-caps;
}
最后
无论你写了什么,记得测试!
将 HTML 测试流程融入你的工作流、工具链和发布管程中。
在不同的设备上测试,在不同的屏幕尺寸上测试,甚至做到在不同网络环境下测试。使用类似 Lynx 只能使用显示文本的浏览器,或者是类似 ChromeVox 的屏幕阅读器,测试页面的交互体验。使用类似谷歌开发者工具的模拟器模式监视变动。还可以将 Page Speed、Web Page Test 等工具融入工作流中,实现项目上线前的自动测试。
编写高性能 HTML 的知识,请参考 HTML,CSS and JavaScript resources 和 Web Fundamentals。
本文根据@Sam Dutton的《High performance HTML》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:https://samdutton.wordpress.com/2015/04/02/high-performance-html/。
如需转载,烦请注明出处:https://www.fedev.cn/performance/high-performance-html.htmlAdidas Energy Boost