引言
作为一个从业快 10 年的 Web 前端开发,我对 CSS 的使用非常熟练,但也仅是熟练而已。在这 10 年期间,我碰到过很多关于 CSS 的问题,但碰到的问题越多我就越感到困惑,为什么会碰到这些问题?在工作时因为疲于应付工作本身的问题,很少有时间和精力去寻找答案,直到离职后我有了相对充裕的时间,我想是时候来回答这个问题了。
背景
2013 年在我刚开始从事 Web 前端开发时 W3C 已经开始发布部分 CSS3 的规范了,而在 2012 年 IE 浏览器在中国市场的占有率是 65.13%,这里面还排除了那些用 IE 内核换皮的「国产浏览器」的数据,也就是说中国当时用浏览器上网的人 10 个人里至少有 6 个是用的 IE。
IE 在浏览器市场的长期统治和实现 W3C 规范的不积极,结合中国大量操作系统更新不及时的情况,导致在很长一段时间里中国很多前端开发者还没有脱离用 Table 进行布局的思维,直到 2009 年后,DIV + CSS 的布局方式才成为主流。下图是我在豆瓣读书搜索出来的关于 DIV+CSS 的书目,时间主要集中在 2007-2011 期间。
当然从 Table 布局过渡到 DIV+CSS 是一件好事,但有一段时间这种行为变得矫枉过正,一些开发者不再注重文档结构的语义化,而是只用 DIV 等几个标签配合 CSS 来编写网页,一些比如 H1 H2 等标签也使用 DIV 来进行替代,虽然这样也能达到效果,但是机器完全无法识别文档语义,这明显违背了 HTML 的初衷。我就是这种人,我在一开始使用 DIV + CSS 布局时,我也完全无法理解语义化的必要,因为我当时所在的公司开发的页面很简单,而且推广渠道几乎只有一个,那就是百度,只要针对百度做好 SEO 就行,实在不行可以给百度交推广费,这样你就能保证自己的网站在百度搜索中名列前茅了。CSS 有很多属性,但开发基础网页需要知道的并不多。通过模仿别人的网页代码,不用多久就能了解到哪些是常用属性,开发过程中遇到的问题网上也基本都有答案,所以 CSS 对于当时的我来说有一些难度,但不多。随着工作要求的不断变化,从垂直居中都要找很久的资料,到掌握多种布局方式(实际需要用的很少);从只能靠试来了解 CSS 属性的差异,到熟悉浏览器渲染原理;从为各个浏览器编写兼容属性,到 LESS、SASS、Post CSS;从研究大规模项目 CSS 组织命名方式,到 CSS Module 和组件化,这一切让我觉得自己越来越懂 CSS 了,直到近几年我才明白,我并不真的了解 CSS,我只是跟随着技术潮流变得越来越「熟练」,并且在越来越熟练的过程中失去了对 CSS 最初的兴趣和好奇心,那些埋在心底的问题也渐渐被「新技术的尘埃」给覆盖。而现在这些问题又重新浮出水面——为什么需要 CSS?为什么是 CSS?
什么是 CSS?
我去维基百科上搜索了一下 CSS 的定义,维基百科是这么定义 CSS 的——「CSS 是一种用来描述 HTML、XML、XHTML 等标记语言文档表现的 style sheet language」,和我之前的认知基本是一致的,和之前不同的是现在我有时间来问自己「style sheet language」到底是什么了。
什么是 SSL?
跟着维基百科的索引,我又找到了「style sheet language」的定义——style sheet language 是一种用于描述结构化文档 (structured document)表现的计算机语言。之前见到有人说 CSS 是 DSL(Domain-specific language),这么说确实没什么大问题,因为目前 CSS 几乎只应用在 HTML 中,但我认为这个分类不是特别准确,更准确的描述应该是「 SSL (style sheet language)」。
大部分 Web 前端能接触到的 SSL 几乎只有 CSS,但实际上 SSL 是一种语言类型,例如 DSSSL(Document Style Semantics and Specification Language)、XSL (Extensible Stylesheet Language ) 都属于 SSL。而且在 CSS 出现之前,就已经有 SSL了,例如用来描述 SGML (Standard Generalized Markup Language) 表现的 FOSI (Formatting Output Specification Instance)。总之,CSS 不是凭空出现的,而在它出现之前就已经有 SSL,所以问题变成了——为什么会有 SSL?
为什么会有 SSL?
Web 最初的目的是为了能让电子文档在互联网上方便地被链接和共享,在电子文档出现之前,大部分出版物都是纸质文档,也就是我们常见到的书。随手翻开你手边的几本书,你会发现它们的排版格式都「大同小异」,尽管这看起来很「平常」,但截止目前世界上已经存在差不多 1.3 亿本书了,这么庞大的数量,是什么没让它们能够保持「大同小异」的呢?答案就是「style guide」,维基百科上说「格式指南(style guide)或格式手册(manual of style)是一套用于文档的编写、编排格式和设计的标准」,也常被称作 style sheet。
假设我写了一本关于 CSS 的书籍,现在我要找出版社进行出版,那么出版社会帮我找到计算机类书籍的 style sheet,让我的书看起来像「技术书籍」。这种计算机类书籍的 style sheet 术语叫做 house style,它决定了这一类书的排版格式。但我不仅想让我的书看起来是一本技术书籍,我还想要在书里面加入一些个性化的样式,让它看起来更像是我写的书,怎么才能做到?为了满足出版物的个性化需求,style sheet 支持使用「层叠」的方式来覆盖一部分 house style 的属性,这既能保证我的书可以保留计算机类书目的阅读习惯,同时又能添加我自己的个人趣味,这听起来和 CSS 的「层叠」其实很像,可以利用重复的样式属性以及合并不同的样式表,而CSS 的层叠设计灵感也源于此。style sheet 中包含了很多样式和排版的标准,诸如标题、正文、行高、字体大小等等,而这些排版和样式的标准同样也挪用到了电子文档中,大部分的 SSL 属性的设计,也源自纸质文档的排版加上针对电子文档的属性扩展而来的。到这里,算是追溯到 CSS 的源头了,当然还可以再往上追溯 style sheet 是如何形成的,但是我觉得到这就差不多了。不过问题仍然还没有解答,为什么是 CSS 而不是其他样式表?
为什么是 CSS?
在 W3C 的官方网站中我几乎找到了这个答案,一篇名为「A brief history of CSS until 2016 (www.w3.org/Style/CSS20… CSS 是如何从一个提案发展成目前应用最广泛的 SSL 的。CSS 最早的提案在 1994 年由当时在 CERN 工作的 Håkon Wium Lie 提交,经过1996 年被采纳为 W3C 推荐规范。在 1994 年以前,HTML 并不支持自定义样式,因为从 1990 年起文档结构和文档布局分离就是 HTML 的目标,所以大部分 HTML 的样式都是由浏览器制定的,用户和开发者几乎没法自定义网页的外观。但显然开发者和用户都对这种情形不满意,因为 HTML 是一个蕴藏着能让用户和开发者自定义文档样式机会的新事物,所以开发者和用户都十分渴望拥有自定义网页样式的能力。
受不了束缚的 Marc Andreessen (后来的网景公司创始人) 在向 www-talk 抱怨无效后,1994 年 10月 13 日向 www-talk 宣布,Mozilla 的第一个 beta 版本可供测试,新浏览器支持的新标签包括 center,而且宣布很快会有更多标签。这一行为间接导致了一个让后来的很多开发者疑惑的问题——为什么有 CSS 可以自定义样式,我还需要样式标签?不过站在当时 Marc Andreessen 的角度来讲,他做的只是快速响应了大家的需求罢了。在 Netscape推出其新浏览器后的第三天,Håkon 发布了 CHSS (Cascading HTML Style Sheets) 的提案。这个提案很快得到了响应,因为 HTML3.0 的主要架构师 Dave Raggett 当时已经意识到 HTML 永远不会变成页面描述性语言,需要有其他机制来填补作者和用户的需求。当时向 www-talk 提案的并不是只有 Håkon 的 CHSS,还有其他大约 9 种 SSL,所以 CHSS 是如何从众多提案中脱颖而出的呢?文章的结论是 CSS 有一个区别于其他提案的特性——层叠,这个特性可以让作者、读者、浏览器厂商都能施加对网页的影响力。虽然这可能是使得 CSS 最终被采纳的原因,但是我相信一定有更详细的结论,并且其他的 SSL 是什么样的,我也很好奇。刚好在文章的注释中我发现这篇文章的最初的版本是从「Casading Style Sheets desgin for the web 」里摘取的,而这本书是由 CSS 提案人 Håkon Wium Lie 和 Bert Bos 一起编写的,我相信这本书里有我要的答案。
找到这本书可能是我做的所有决策里面最正确的一个,这本书以论文的形式阐述了 CSS 是如何被设计出来的,本文中我只会引用书中的结论来解答我的问题,如果你对 CSS 有更深入了解的想法,你应该去读一读这本书,相信它能解答你大部分问题。书中的第三章讲述了在 Web 出现之前就存在的 SSL (FOSI、DSSSL、P94),这些 SSL 被用在各自的领域,并且从来没有受到过 Web 的影响,毕竟那时还没有 Web。通过研究这些 SSL,作者提议了 SSL 的常规结构,指出 SSL 需要具备的 6 个组件:Syntax、Selectors、Properties、Values and units、Value propagation、Visual formatting model,这个提议到现在还能在 SSL 的wikipedia 中看到。
书的第四章描述了当时作者所注意到的所有对于 Web SSL 的 9 个提案 (RRP、PWP、SHP、CHSS、JEP、SSFP、SSP、PSL96),并在第五章描述了所有提案满足 Web 的需要的情况,同时作者结合 Web 的特性和提案分析列出了 6 点 Web 所需要的 SSL 的特性:
- 后期绑定需要流式样式表(Later binding requires stream-based style sheets):HTML 是渐进式渲染的,那么样式表的引入不能减慢网页展示的速度。因此 style sheet 需要支持在文档下载时也能被应用。这一点在 CHSS 提案中并没有提到,但是 Bert Bos 的 SSP(Stream-based Style sheet Proposal)刚好可以满足这一需求,甚至这一需求的命名都是由这个提案产生的。
- 以屏幕为中心的出版需要对基于屏幕的属性、值和单位进行支持。(Screen-centric publishing requires support for screen-based properties, values and units):纸质印刷品和电子屏幕都是视觉媒体类型,有很多属性、值和单位是可以从纸质印刷品挪用到电子屏幕的,比如绝对单位 cm、mm、字体、颜色等等。但为了优化计算机屏幕的表现,需要支持一些额外的属性、值和单位。比如在网页的设计中,设置文本的背景是很常见的需求,而且需要一个像素(px)单位来确保样式在不同的屏幕之下肉眼看起来是一致的,比如边框正好是 1px 的宽度这种情况。
- 作者和读者共享影响力需要能在相互冲突的样式偏好之间进行协商(Shared author/user influence requires negotiation between conflicting stylistic preferences):Later binding 使读者和作者都能对文档的表现进行影响,这一特性正是影响样式表是否能成为 Web 样式语言的关键特性,而支持呈现的协商的其中一种方法是将不同来源的样式表进行结合。
- 多种输出需要特定媒体的样式表(Multiple outputs require media-specific style sheets):网络内容被显示在许多类型的输出设备上,style sheet 必须能让这一系列设备都能展示。例如,是否有针对非视觉媒体的属性?单位是否适合不同类型的输出设备?最后,样式表能否表明它只应适用于某些媒体类型?
- 支持超链接的文档需要链接的样式(Hyperlinked documents require link styling):用户已经开始期望浏览器能记录他们过去访问过的那些链接。区分已访问和未访问的超链接的方法之一是对它们进行不同的样式设计。因此,为了呈现超链接,浏览器必须使用文件和样式表本身以外的信息。
- 不确定的交付需要稳健性(Uncertain delivery requires robustness.):互联网是一个容易失败的媒介,样式表语言应该像其他网络机制一样,在设计时考虑到这一点。如果一个样式表不能出现,内容仍然应该可以呈现给用户。因此,健壮性是一个要求。实现稳健性的一个方法是有冗余的呈现回退值。后备值必须超越简单的为每个属性提供默认值。例如,默认值不能够区分 inline 和 block 元素。
CHSS 满足了其中大部分的需求,Bert Bos 的 SSP 满足了其他一些需求。Ber Bos 也是响应 CSS 初稿的人之一,他决定与 Håkon 联手,最终的 CSS 提案则在主要以这两个方案为基础,吸取其他方案的一些特性后诞生了。很快 CSS1 就得到了发布,并由于它的易读、易写、易实现而迅速被浏览器支持。虽然后来出现了各种各样的问题,但它仍然是最成功的 SSL。
直到现在我们还能看到 CSS 第一版标准的草稿:www.w3.org/Style/CSS/d…。
在第一版的草稿中甚至连 Visual formatting model 都没有,而从这份提案也能看出 CSS 的设计是很简单的,并不像我们现在看到 CSS 那么复杂,虽然很多规范和现在的规范已经大不一样,但不妨碍我们通过这份标准草稿来了解 CSS,甚至我认为这是了解 CSS 最好的方式——从它最简单的时候开始。
总结
从纸质文档到电子文档,世界对于信息的共享效率有了更大的要求,于是出现了 Web。 Web 重要组成部分的 HTML,作为一门结构化文档的标记语言,需要保持自己的抽象等级,才能适应不同的浏览器、设备。只有让 HTML 结构和样式分离,才能不致使 HTML 变成一门「样式标记语言」,这是「为什么会有 CSS?」的答案。适应 Web 的加载和呈现方式需要满足多种条件,对多个 SSL 提案筛选后,选出了符合条件最多的 SSL——CHSS,再由多个提案人的通力合作,最终有了 CSS,这也是「为什么是 CSS?」。
闲话
对于我来说,了解「为什么需要 CSS?」「为什么是 CSS?」后,很多关于 CSS 的「疑难杂症」都迎刃而解了。但我相信这篇文章并不是所有人都能有所收益,写这篇文章目的更多是阐述我对这两个问题的理解和回答,不是什么「标准答案」。