或许在许多年后,培训公司将会教授新人:TypeScript 怎么写,Sass 怎么写,JSX 怎么写,这时可能会出现 jQuery 时代的荒诞问题——jQuery 与JavaScript 哪一个更快?这是一种悲哀,也是时代的进步吧。正如我们开心敲着电脑,不用关心底层的芯片是如何运作的。这是文明建立在极度脆弱的生态下的至高产品。
而我们浏览的复杂页面的底层是 HTML+CSS+JavaScript 构建的,其中HTML 是基础中的基础,但它经常被人所忽视。要不想页面文明轻易湮灭,我们需认真封存这部分知识,就像亚述人把他们的知识楔入到泥板中一样。
HTML 的前身 SGML
战争驱动文明发展,互联网是美国军队为了快速传送情报而发明的。如果单纯传送文字,当时的电报就可以实现,但显然像地图上的图像信息,电服就不行了。这时候需要一种语言来组织这些文字与影像,好还能存在交互性。交互虽然不能实时,但总好过没有。于是学者们找到当时流行的文档描述语言 SGML。
SGML 是国际上定义电子文档和内容描述的标准。它源于 1969 年 IBM 公司开发的文档描述语言 GML,GML 主要用来解决不同系统中文档格式不同的问题。后经过多年发展,1986 年经 ISO 批准为国际标准 ISO8897,并被称为 SGML。
它有许多 HTML 的特征,如内容与样式分离。在 SGML 中,标记分两种:一种用来描述文档显示的样式,称为程序标记;另一种用来描述文档中语句的用途,称为描述标记。一个 SGML 文件通常分三个层次:结构、内容和样式。结构为组织文档的元素提供框架,内容是信息本身,样式控制内容的显示。正因为如此,它的使用范围很广,被许多大型公司用来创建和发布信息。诸如布告、技术手册、章节目录、设计规范、各种信函等,都可以用它来设计描述。
但是 SGML 有致命的缺憾,并且它的优点成为了它的缺点。SGML 设计精良,规范严谨,导致了其复杂性也高,在军情紧急的情况下,需要快速交换情报,不能慢吞吞写好每个标签,因为当时每秒几个比特的网速也是一个问题。
因此它需要裁减,于是有了HTML。
浏览器大战对 HTML 的影响
当时大家原本要的是一个精简版的 SGML,但终他们得到的一个完全不同的东西。
这要从解析网页的浏览器说起,Web 之父 Tim Berners Lee 设计的浏览器WorldWidWeb 过于简单,于是让商业浏览器有可乘之机。
在刚开始时,浏览器商还是按照 W3C 的制定的规则,如 Mosia、Netscape,但微软介入之后就发生改变。微软制定自己的浏览器语法与标准,于是导致了两套标准的出现。
在规划中,HTML 也是一门严谨的语言,是高度有组织性、规范化、模块化。例如,规范化是有一个文档类型声明 DOCTYPE 来指明它怎么解析的。模块化,是说各种标签其实也是有组强性的,几个几个地划分地不同的族群,合起来实现一个功能,著名的是表单与表格。
但是后来出现了一些意外,一些用来装饰用的标签(s、b、i、u、font)因为 CSS 的出现,被人们诉之败作,渐渐被边缘化与废弃。一些用来模拟 Excel 功能的标签(table、tbody、tr)被人们用来布局,弄得页面难以维护。
在 CSS 标准化时代,又矫枉过正,硬生生地用 DIV 来模拟表格。一些用来实现广告功能的标签,导致会有满屏飘动、不让用户关闭的乱象。在这几个大事故中,许多标签就是被胡乱使用或边缘化。
我个人认为大原因是 W3C 没能自己开发一个浏览器,一直倚重某一个方,导致造成 HTML 的失控。
HTML 在语法上设计得非常简单易学。
HTML 标签是包在小括号里面,没有人规定标签名是大写还是小写。开标签中,标签名旁边有一些属性,这些属性的属性值没有人规定它是否能引号,引号是单引号还是双引号,没有规定标签是否一定要闭合。
可能当初是有规定的,但无法遵循。浏览器需要快地将内容呈现给用户,但当时的网速不太可能,于是浏览器大厂允许用户可以不用闭合标签,不用严格括起属性值,也能跑起页面。这种纵容在当时成了优势,被其他浏览器争相模仿。
HTML 的版本
HTML 发布以来,迭代过许多版本,现在是小步快跑的第 5 版,但 HTML5 已经不是 W3C 所规范的了,是由一个浏览器大厂们组成的俱乐部 WHATWG 发布的。下面是一个简单的路线图:
不存在 HTML1.0, 各自为战
HTML2.0,从 1995 年 11 月到 2000 年;
HTML3.2, 从 1996 年 1 月到现在;
HTML4.0,从 1997 年 12 月到现在;
HTML4.01,从 1999 年 12 月到现在;
XHTML 1.0,从 2000 年 1 月 20 日到现在;
HTML5.0,从 2014 年 10 月 29 日到现在。
可以看出几个断层,HTML1.0 还没有准备好时,大家就争先抢后地开始做,于是当时相当地混乱。
早期的浏览器包括了:Tim Berners 的 WorldWideWeb 浏览器,兼具浏览器和编辑器功能,但只能运行在NeXTStep操作系统上;CERN的一位数学实习生 Nicola Pellow 开发出 Line-mode 浏览器,能运行在 UNIX 和 MS-DOS 上;Erwise 是第一个带图形界面的浏览器,支持搜索网页中的单词,由四名芬兰大学生开发,在 1992 年发布;加州伯克利的 Pei-Yuan Wei 在1992 年 4月发布了 ViolaWWW,这个浏览器受到了 Mac 程序 HyperCard 的启发,但他没有 Mac 只能接触到 UNIX 机器,1992 年夏天,斯坦福线性加速器中心物理学家 Tony Johnson 为斯坦福的物理学家发布了图形浏览器 Midas;与此同时,CERN 的 Nicola Pellow 和 Robert Cailliau 发布了第一个Mac浏览器 Samba;基于 Viola和 Midas 的 Mosaic 在 1993 年发布;堪萨斯大学发布了 Lynx;康奈尔大学法学校学生 Tom Bruce 发布了 Cello。——节选自《被遗忘的早期浏览器》
HTML3.0时,改了又改,那时五大浏览器的四个玩家已经全场(IE、Netscape、Opera、Safari),要满足四家的喜好非常难。这也是目前还在支持的早期标准。XHTML 是 W3C 后一次赌博,想用 XML 的规范来修正 HTML 一直以来松散的编写形式,即要来闭合的地方必须闭合,属性值必须要括起来,废弃的标签不能再使用,还要求对 script 标签的内容使用 CDATA 包裹起来,DOCTYPE 变得很长……
俗话说,由俭入奢易,由奢入俭难。用户不习惯,如果写的页面不合格,浏览器不解析,意味着用户会跑去竞争对手中。因此这闹剧草草收场了。浏览器商也看到自己的能量所在,把 HTML 的规范制定收归手中。
HTML的模块介绍
在语义化时代,人家过于关注于单个标签所表示的意思,而忽略了组件是分群体的。只不过有的群体是弱联连,可以混杂其他标签,加之浏览器的自动纠错功能导致人们对它们的误解。这些群体我称之为模块。
我稍微归纳一下,当然在 W3C 的 HTML5.2 中它们也有另一套划分。那套划分很奇怪,某一种标签可能归类到多个类别中。
文档模块
文档模块就是<html>、<body>、<head>、<title>这几个标签,我们可以在 document 上访问到它,document.documentElement、document.body、document.head、document.title。它们可以省略不写,浏览器魔术般地补全它们。这些标签只是提供一个框架,告诉人们一些内容性的东西应该放在 body 中,功能性的东西应该放在 head 中。功能模块
它是用来设置文档整体的功能或一些元信息,涉及的标签有<link>、<meta>、<base>、<script>和<style>除了后两个,由于页面功能的膨胀,需要多人协作一个页面,于是出现一个页面存在多个<script>与<style>标签,它们可以分散到其他位置。<link>、<meta>、<base>都集中在head 标签内。我也尝试过将 div 放在 head 中, head标签会自动将它赶回body里面。<link>标签有两个作用:1. 定义文档与外部资源的关系;2. 是链接样式表。HTML5 新加的预加载,预渲染等功能就在这标签上添加。
<meta>标签可提供有关页面的元信息(meta-information),比如针对搜索引擎和更新频度的描述和关键词。有用的就是设置页面的字符集。
<base>标签为页面上的所有链接规定默认地址或默认目标。通常情况下,浏览器会从当前文档的 URL 中提取相应的元素来填写相对 URL 中的空白。
使用<base>标签可以改变这一点。浏览器随后将不再使用当前文档的 URL,而使用指定的基本 URL 来解析所有的相对 URL。这其中包括<a>、<img>、<link>、<form>标签中的 URL。在 IE6-8 中这标签有一个可怕的 Bug,会将整个页面装进它的 innerHTML 中,导致你的选择器失灵。
排版模块
这涉及到的都是一些块狀元素,如div、h1-h6、blockquote、有序列表、无序列表、定义列表等,它们是自带样式的一种元素。在 HTML5 时代,会继续加上 article、aside、nav、section 等标签。
装饰模块
这是覆行 SGML 的样式显然功能,于是才出现这类标签,常见的有 s、u、i、b、big、small、sub、sup、center、font、br、nobr、hr。在强调语义化的时代,除了 br、nobr、hr 都完了。此外,还有一些不起眼的标签,被忘了,又赋以特殊含义又活下来,如:code、kbd、samp、cite、tt、var……它们自带样式,通常以另一种字体特别显示。
我们知道页面在传输过程会被加工,处理掉一些换行符与空白,如果我们想保留这些换行符与空白就需要这里面的三种标签了:pre、plaintext、xmp。其中 plaintext 已经被浏览器废弃掉了,彻底不能用了,不像那些被声明废弃还能苟活着的标签。pre 标签,大家可能熟悉些,它与 code 标签经常组合在一起,用于语法高亮。
xmp 则是在语法高亮没有发明之前,能完整地显示某一段 HTML 片断的结构的唯一标签。
xmp 会把里面的内容当成一个字符串,不会生成对应的 DOM。这种能原样保持用户HTML的元素是非常有用的,常常用于做模板容器, 其他的如<script type="template"></script>、<noscript></noscript>都有其优缺点,直到 HTML5 推出了<template>标签才解决这问题。
多种文档的混排
上面走马看灯地回顾了一些标签,我们也了解到不断有标签被废弃,也不断有新的标签涌现出来。这些标签默认具有什么功能,有什么属性,有什么外观,或者如何与其他标签共存,都是规定在 DOCTYPE 中。所谓 HTML 规范其实就是这个文档类型声明。
一个页面加载下来,经过比特到字符到字符串到标签到 DOM 的层层转换,其中标签到 DOM 的解析就需要文档类型声明来处理,当然这里可能存在浏览器私下的非正式的纠错处理。但是文档类型声明作为页面的 DNA 角色是不变的。
在HTML5之前文档类型的声明基本都使用 DTD(document type definition),由于之前的版本基于 SMGL,DTD 规定了标记语言的规则,才能使浏览器正确的解析并呈现需要展示的内容。
很长的代码不借助于工具或贴粘复制,是很难写的。因此 HTML5 的写法是异常简洁,也屏蔽了里面的 dtd 链接,反正也没有几个人打开它。
加之 HTML5 本来就是遵循小步快跑的规则,不断小版本迭代,因此 dtd 文件会时不时变化,这个就内置到浏览器中就行了。时至今天,所有大厂的网页都用上 HTML5 了。
下面是 HTML5 的 DOCTYPE 写法:
但是 html 上面的文档类型声明只是告诉浏览器如何处理 HTML 标签,在 HTML 文档中可能混杂其他文档。
比如我们要让页面更有说明力,需要出现雷达图、线段图、饼状图等等,就要用到 SVG。我们的页面是为高校制作的,需要用到专业的数字公式,这时需要用 math 标签。事实上,它们都是出自同一渊源,多种文档混排可能在 IE4 时代就存在了。
1998 年,微软发布了 VML 矢量标签语言,对于 XML 的混排则使用一种叫 XML 数据岛的技术实现了。因此多文档的混排在IE4~8的情况是 HTML+VML+XML, 在其他浏览器则是 HTML+SVG+math,并且 SVG 里有<foreignObject>
HTML5 的进化
现在我们对 HTML 的关注不如以前了,事实上 WHATWG 对它做了非常宏大的规划,非常多的功能需要逐年来迭代。但 React 这些大型前端框架的出现,掩盖了浏览器的努力。以前 Chrome 每次发版本常常吸引眼球,但 babel 可以让你用上还在讨论中的语言特性!那么让我们略微看一下 HTML5 的新特征吧。
装饰性标签基本废弃,使用带语义的装饰化标签代替
增加大量的表单元素
增加大量的布局标签
多媒体标签进化
语义化标签的崛起
这些标签能做功能CSS也能做,因此被干掉。HTML5带来了全新的标签,它们富有语义,对SEO或机器学习分析内容有帮助。
在人们受够了table布局,前端工程师开始关注每个标签在发明时赋以它们的本来意义。
更多布局元素
在新布局元素没有出来时,人们对页面也是划分成不同区域。每个区域标识不同的 ID 或类名,以前谷歌做过一次调整,发现大家对这些ID或类名的取名都很相似,比如顶部的区域都叫 header,底部的区域都叫 footer,侧边栏都叫 leftside 或 rightside, 主内容区都叫 main,导航区几乎都叫 nav,还有弹出层,也统一叫 dialog。
DOM的标准化
自定义标签
各种页面性能优化方案的内置实现
人们对页面性能的优化是永无止境,即便网速已经这么快了,CPU已经这么多核了。于是为了尽快加载资源,我们有DNS, 为了防止<script>堵塞页面渲染,我们把它们放到body的后面……这些奇技淫巧都被浏览器所收吸,做成一个个配置项了。
结语
HTML发展到今天,功能远远超过当初展示页面提交表单的需求了。我的文章还有许多HTML5的新特征没有提到,浏览器不断提高它的外延,相当于把它自己当成一个操作系统了。
虽然现在有了非常好用的框架,让我们暂时忘记这些底层知识,但是我们所有一切的功能都是筑建在HTML之上,这一点万万不能忘记。我们要把自己当成一个建筑师,了解每一个材料的质地,才能打造更好的大厦。