什么是 HTML 5?
前言
作为程序员,技术的落实与巩固是必要的,因此想到写个系列,名为 why what or how,每篇文章试图解释清楚一个问题。
这次的 why what or how 主题:现在几乎所有人都知道了 HTML5,那么 H5 相比于 HTML4 到底有什么区别呢?
升级版?标准版!
HTML5 作为 HTML 标准的第 5 版,于 2014 年发布。相信关注过 HTML5 发展史的朋友都知道,该版本是 WHATWG 和 W3C 握手言和后诞生的,是 W3C 组织与浏览器厂商相互妥协的结果。其中的绝大部分规范都由 WHATWG 组织制定,之后由 W3C 采纳并纳入标准。
但 HTML5 是 HTML4 的升级版吗?
是,也不是。如果从版本更迭来看,HTML5 确实在 HTML4 之后诞生,但是 HTML5 本质上却已经不同于 HTML4 了。
相信大家目前还留有对 HTML4 的些许印象,在编写 HTML4 时,需要加一段特殊说明来声明文档类型:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "https://www.w3.org/TR/html4/strict.dtd">
该段声明说明了该文档基于 https://www.w3.org/TR/html4/strict.dtd 规范。从一个侧面来看,该文档仅仅是符合这种规范的文本而已,而这种规范被称为 SGML(标准通用标记语言)。
接着再来看看 HTML5 的文档声明:
<!DOCTYPE html>
简简单单、清晰明了,说明该文档是 HTML 文档,并没有基于其他规范。
从浏览器的角度来对比,HTML5 之前的版本,浏览器必须要从 W3C 官网上获取规范文件,才能解析文档,而 HTML5 文档可以被浏览器直接识别。
这些角度都表明,HTML5 之前的 HTML 是 SGML 规范的一种实现,而 HTML5 却是原原本本的 HTML,有自己的规范。因此,HTML5 可以认为是一种新的标准。该标准诞生于 HTML4 之后,却不是 HTML4 的升级。
但不管是基于 SGML 的 HTML 版本,还是 HTML5 版本,其语法内容都差不多。因此,也不需要过多纠结这个问题。实用主义者,能用、好用就行~
语义化
在看过 什么是 CSS?之后,大家应该知道,样式的发展过程经历了一个用标签表达样式的阶段。该阶段产生了一些样式标签,比如 <font>、<center>、<big> 等。但 HTML5 提出结构和样式分离,样式在 CSS 中表达,而 HTML 负责结构。样式标签正式宣告退出舞台;在 HTML5 的规范下,这些标签正式被废除,一些代表结构的标签被提出并规范。
结构化、样式分离的 HTML 文档,极大地提高了文档的表达力。不管是机器还是人类,都能更快地理解文档的结构,这种文档就被称为语义化文档。
语义化主要体现在以下几个方面:
结构标签
写过 HTML5 的人都知道大概新增了哪些标签,这里简单罗列一下:
| 标签 | 释义 |
|---|---|
section |
代表文档组成的一部分,应该与 h[1-6] 结合使用,表示文档结构。 |
article |
代表文档的独立内容区域,该区域内容为博文、报纸文章等内容。 |
main |
代表文档的主要内容区域。 |
aside |
代表与内容主题略有相关的区域。 |
header |
代表该文档的介绍性区域。 |
footer |
代表该文档的页脚,通常用于存放版权、作者等信息。 |
nav |
代表文章导航区域。 |
figure |
代表该区域内有多媒体内容,通常多媒体标签作为该标签的子元素。 |
template |
模板区域,可以被 JavaScript 所使用。 |
video |
通过该标签可以引用视频,该标签代表视频可以显示的区域。 |
audio |
通过该标签可以引用音频,该标签代表音频可以显示的区域。 |
track |
该标签为 video 提供了字幕。 |
mark |
代表需要特殊注意的内容区域。 |
progress |
该区域代表某项任务的进度。 |
meter |
该区域代表某项内容的使用量,比如 CPU 使用量等。 |
time |
该区域代表时间。 |
canvas |
该区域代表可以被 JavaScript 所控制的画布。 |
可能有些朋友会纳闷:这些东西其实也不是那么重要,用 div + CSS 也都能实现,而且在各个浏览器上的表现还都一致,也不用考虑兼容问题。那么,为什么这里还要提呢?
试想一个问题:
如果你是浏览器,或者说是解析 HTML5 文本内容的程序,你会怎么看待 HTML4 与 HTML5?
首先,需要解决的第一个问题是显示页面。两者都能解析、生成树状结构,并成功地显示页面,这也是大部分用户所需要的。在这方面两者平局,HTML5 没有任何优势。
那么,现在来看第二个问题:识别该文档。这或许不是大部分用户的需求,但小部分用户并不意味着人数少。
相信大部分朋友都有使用搜索引擎的习惯,那么搜索引擎是如何帮你找到这个网页的呢?
搜索引擎通过适当的策略解析爬虫抓取到的网页内容,将文章分类,再与用户提供的搜索词进行匹配,最终把结果呈现给用户。面对 HTML4 时,爬虫的解析策略需要识别出特定的 div,而这个特定的 div 该如何去找呢?经验?特定字符串?面对 HTML4,只能得到一个个 div,而具体是哪一个 div,emmm... 不好找。面对 HTML5 呢?程序从结构上就能大致理解文档,进而识别出这篇文章的大体内容。
问题二可以简单地理解为:我们需要生成文章大纲。一篇文章可以由几部分内容组成,而规范这些内容的就是大纲。相信写过文章的人都知道大纲的作用,它可以清晰地表达内容。那么 HTML4 呢?一堆 div,分不清哪个是主体,哪个是次要内容。但 HTML5 结构清晰,解析程序也能很快地生成文档大纲。
大纲只能用在搜索引擎吗?并不是,阅读设备就很需要大纲生成目录,无障碍设备可以识别到文档的主体内容等等。
看到这里,相信大家对于语义化标签的重要性也有了了解。使用成本几乎为 0,但文档的清晰程度却上了一个层级,干嘛不用呢?
新增的表单类型
表单类型(type)代表了该表单内容的类型,新增了以下几个:
telsearchurlemaildatetimenumberrangecolor
新的标签属性
| 属性 | 示例 | 含义 |
|---|---|---|
target |
<base target="..."> |
base 标签新增 target 属性,虽然之前已经被广泛使用。 |
charset |
<meta charset="utf-8"> |
meta 标签新增 charset 属性,规范文档所使用的字符集。 |
placeholder |
<input placeholder="..."> |
可输入的表单元素新增 placeholder 属性,代表默认内容。 |
form |
<input form=1> |
表单元素新增 form 属性,代表关联的 form 表单,而不需要在 form 标签内。 |
contenteditable |
<div contenteditable> |
代表该元素可编辑。 |
data-* |
<div data-a="..."> |
与该元素相关联的数据,可以在 JavaScript 中获取。 |
以上为 HTML5 语义化的具体呈现,希望大家拥抱并使用 HTML5 的新标签。
多媒体
HTML5 的上一代标准 HTML4 于 1999 年发布。当时互联网还处于图文混排的时代,通信也不是很发达,数据交互受限于网速。但是,近 20 年来数据通信高速发展,图文混排已经不能满足用户的需求了。由于浏览器并不支持视频,促成了 Flash/ActionScript 的发展;但是由于 Flash 的繁琐(需要安装插件)以及安全问题,Apple 拒绝使用 Flash。之后,各大浏览器厂商也开始重视 Flash 的安全问题,并提出了多媒体标签,直到 HTML5 规范化了多媒体应用。
相关多媒体标签:
建议查看英文的相关文档,中文的翻译文档好像还没有及时跟进。
除了多媒体标签的更新,这里同时还列举一些与显示相关的内容:
- Canvas
画布,可以使用 JavaScript 在该元素规定的区域内进行绘画,参见文档说明。
- WebGL
光栅化的图片绘画引擎,主要用于 3D 制作,参见文档说明,以及 WebGL 理论基础。
- Camera API
通过 Camera API,你可以使用手机摄像头拍照,然后把拍到的照片发送给当前网页。
- SVG
现在可以直接在 HTML5 文档中写 SVG(可缩放矢量图形)。这是一种基于 XML、用于描述二维矢量图形的标记语言。参见文档说明。
- MathML
MathML(Mathematical Markup Language) 是一种基于 XML 的标记语言,用以描述数学公式,但目前浏览器的支持力度有点低。具体可以查看文档说明。
通信
HTML5 之前,JavaScript 只能通过 XMLHttpRequest 与后端程序进行交互。随着 HTML5 标准的提出,前端可以使用各种各样的姿势与后端进行沟通,数据交互变得简单、灵活。
fetch
XMLHttpRequest 虽然在实际开发中很少直接使用,但是它的封装库我们却经常使用,比如 axios、$.ajax。虽然封装库降低了使用成本,但源头是复杂的,而且 XMLHttpRequest 是基于回调的异步模式。虽然 axios 进行了 Promise 化,但毕竟不是原生支持。因此,HTML5 标准提出了一个基于 Promise 的请求 API:fetch。
一个简单的 fetch 例子:
fetch('https://example.com/movies.json')
.then(function(response) {
return response.json();
})
.then(function(myJson) {
console.log(myJson);
});
fetch 支持两个参数:
- 资源地址。
- 请求参数,一个
JavaScript对象,用于设置请求方式、请求头、请求体等内容。
学习资源:
WebSocket
在 HTML5 出现之前,做一个实时聊天的 Web 项目是极其困难的。由于之前的版本仅支持浏览器主动向服务器发送内容,必须先有请求,才能有服务器响应的数据。简单来说,服务器并不能主动将数据提交给客户端。
面对这些需求,大家的做法通常是轮询:通过前端设置一个定时器,每隔固定时间请求一次服务器资源,即使服务器并没有发生数据更新。这浪费了大量服务器资源,那么,有没有一种方式支持服务器推送呢?
有!WebSocket 是 HTML5 新增的一种协议,目的是在浏览器和服务器之间建立一个双向数据通道,浏览器可以推送数据到服务端,服务端也可以推送数据到客户端。WebSocket 对于前端来说仅是一个简单的 API,最重要的是服务端的支持。
WebSocket 的客户端代码示例:
// 创建连接
const socket = new WebSocket('ws://localhost:8080');
// 连接开启事件
socket.addEventListener('open', function (event) {
// 向服务端推送数据
socket.send('Hello Server!');
});
// 服务端推送事件,event.data 即为服务端推送的数据
socket.addEventListener('message', function (event) {
console.log('Message from server ', event.data);
});
至于服务端如何实现,不同语言有不同的方式,比较出名的是 Node.js 下的 Socket.IO。如果担心服务端语言实现困难,不妨用 Node.js 搭建中间层,使用 Node.js 与客户端沟通,并将数据交由服务端程序处理。当然,也可以查看 MDN 的文章:编写 WebSocket 服务器。
一些资源:
- WHATWG Web sockets
- websocket.org HTML5 WebSocket
- MDN WebSockets
EventSource
fetch 实现了请求的 Promise 化,WebSocket 实现了双工通信,那么 EventSource 又是什么?
简单来说,EventSource 实现了服务端对客户端的单向通信。可以理解为客户端是订阅者,服务端是内容发布者,也就是发布订阅模式的实现。
一个简单的例子:
// 开始订阅
var evtSource = new EventSource('sse.php');
var eventList = document.querySelector('ul');
// 服务端发布数据回调
evtSource.onmessage = function(event) {
// event.data 即为服务端发布的数据
console.log('Message from server ', event.data);
}
同样,前端代码很简单,但服务端实现该通信方式需要一定的成本。具体可以查看以下文档:
- WHATWG EventSource
- MDN EventSource
- sse.php 编写
WebRTC
WebRTC(网页即时通信)是一个支持网页浏览器进行实时语音对话或视频对话的 API。由于该 API 目前并未纳入标准中,这里就不过多深入了,可以通过以下文档进行了解:
- MDN WebRTC API
- W3C WebRTC 1.0
存储
在 HTML5 出现之前,前端开发者仅能通过 cookie 存储用户在不同页面之间跳转的数据。但从意义上来说,使用 cookie 存储数据是不对的,不能因为 cookie 可以在同域名下通用,就让它携带各种各样的数据。cookie 应该用来标志用户身份。HTML5 出现之后,数据存储得到了规范,cookie 也回到了原始用途。
storage
相信大家对该 API 已经熟悉得不能再熟悉了。storage 分为两部分:sessionStorage 与 localStorage,二者拥有同样的方法:
setItemgetItemremoveItemclear
localStorage 会将数据永久存储下来(当然,用户可以主动清除),sessionStorage 中设置的数据会在用户关闭页面后清除。
- WHATWG Web storage
- MDN Storage
IndexedDB
小型数据使用 storage 已经够用,那么浏览器端如何存储大量数据呢?IndexedDB 就是 HTML5 给出的答案。IndexedDB 是浏览器内置的数据库,用于存储结构化数据。但这个数据库是异步存取数据的,说实话有点难用。如果使用它,那基本上所有代码都在 then 方法里了。酌情使用吧。
可以通过使用 IndexedDB进行学习。
DOM 的更新
query
querySelector:使用CSS选择器选择元素,仅选取匹配元素中的第一个。querySelectorAll:使用CSS选择器选择元素,返回所有匹配的元素。
data-*
可以通过在标签上使用 data-* 设置与元素绑定的数据,JavaScript 可以通过 dataset 获取或设置。
<p id="title" data-text="hello"></p>
const p = document.querySelector('#title');
p.dataset.text // hello
元素添加
prepend:在规定标签的最前面添加元素。append:在规定标签的最后面添加元素。
element 相关
firstElementChild:获取规定标签中的第一个子元素。lastElementChild:获取规定标签中的最后一个子元素。previousElementSibling:获取前一个兄弟元素。nextElementSibling:获取后一个兄弟元素。
类名操作
Node.classList.add:添加类名。Node.classList.remove:移除类名。Node.classList.toggle:切换类名。Node.classList.contains:检测是否有类名。
拖拽
在 HTML4 中想实现元素拖拽,我们需要经历这样一个过程:获取元素、设置元素定位、与需要被拖入的元素进行碰撞检测,检测完成后再进行拖入操作。在 HTML5 中,这一过程得到了规范。
相关事件:
dragstart:设置在拖动元素上,标志拖动开始。dragenter:设置在拖入元素上,标志有元素开始拖入该元素。dragover:设置在拖入元素上,标志元素完全拖入该元素。dragleave:设置在拖入元素上,标志元素即将离开该元素。drop:设置在拖入元素上,标志拖动元素被放下。
拖动元素与拖入元素可以通过 e.dataTransfer.getData(xxx) e.dataTransfer.setData(xxx, xxx) 进行数据交互。
MutationObserver
MutationObserver 字面意思为变动观察器,用来观察文档节点的变动。相关文章:
最后
DOM 中接触最多的也就是这些内容了,更为详细的内容可以通过 DOM STANDARD查看。
BOM 的新增
在什么是 JavaScript?中,我们提到过,BOM 并没有相关的标准去规范它。HTML5 中一些没有归到 DOM 中的 API 更新,就归到这里。
Web Workers
我们都知道,JavaScript 是以单线程的形式运行在客户端,这就避免不了进行大规模数据运算时所带来的阻塞问题。为解决这一问题,HTML5 提出了 Web Workers 的概念,并最终将其纳入规范。使用 Web Workers,可以将与页面渲染无关的数据运算代码放入另一个线程。线程间通过 postMessage 发送数据,通过 onmessage 回调获取数据。
一个简单的例子:
// workers.js
let i = 0;
function timedCount() {
i = i + 1;
postMessage(i);
setTimeout(timedCount, 500);
}
timedCount();
const w = new Worker("workers.js");
w.onmessage=function(event){
console.log('Message from worker ', event.data);
};
相关资源:
目前大火的 PWA 应用,其核心 Service Worker 其实也是 Web Workers 的一个实现。Service Worker 使用编程的方式进行资源缓存、与后台同步数据等操作。虽然该内容已经在不少浏览器上实现,但标准仍在草案阶段,等标准规范发布后再详细介绍。
相关资源:
- W3C Service Workers
History
在 HTML5 之前,前端开发者只能通过 history 对象进行前进、后退操作,却不能在不刷新当前页面的情况下修改 URL。那时,单页应用仅能通过 hash 模式进行路由管理;而通过 HTML5 新提出的 history API,单页应用就能像正常应用那样管理页面的 URL 了。通过以下 3 个方法即可:
pushState:不刷新页面,导航到指定URL并产生历史记录。replaceState:不刷新页面,将当前页面的URL替换为指定URL,不产生历史记录。popstate事件:在当前页面点击返回时,window对象会触发该事件,可以使用addEventListener进行监听。
相关资源
requestAnimationFrame
通知浏览器在下一次重绘之前调用指定的 callback。由于重绘与屏幕刷新率挂钩,因此该 API 的调用也与屏幕刷新率挂钩。可以使用该 API 分解一些复杂运算,将任务放在每次刷新的间隔中。这样就不会出现屏幕要刷新了,但浏览器却未能及时绘制出页面的尴尬情况,使得页面显示平滑、不掉帧。因此,该 API 的出现促进了 Canvas 的发展,而 Canvas 的发展又促进了页游的发展。
requestAnimationFrame(callback)
如果想实现类似定时器的效果,只需要在 callback 中再次调用 requestAnimationFrame 即可。
相关资源
全屏 API
Element.requestFullscreen():将当前元素全屏展示。Document.exitFullscreen():取消全屏显示。
相关资源
- MDN 全屏 API
获取地理位置信息
navigator.geolocation.watchPosition():监听地理位置信息,当信息发生改变时触发回调。navigator.geolocation.getCurrentPosition():获取地理位置信息。
以上两个方法都需要传入成功回调和失败回调,分别为参数一和参数二。
相关资源
- MDN 使用地理位置定位
CSS3
在什么是 CSS?中,我们提到过,CSS 标准被 W3C 采纳,并最终成为 HTML 标准的一部分,因此,CSS 内容的更新也算是 HTML5 更新的一部分。
这部分单独说吧。
总结
按照惯例,问几个问题:
HTML5涵盖了哪几个方面的更新?- 通信方式有什么新姿势?
- 语义化的体现,以及语义化的作用?
JS如何更好地处理数据而不影响页面渲染?- 单页应用的
history是基于哪些API实现的?
谈谈感受:
随着 HTML5 的更新,前端再也不是切图仔,浏览器也开始作为一个 GUI 工具存在,而不仅是为了展示页面。相信随着技术的发展,当通信延迟降低到一定程度后,乔帮主的设想 all in browser 将会成为现实。