前端的诞生 - 3. CSS的从无到有

相比于HTML的横空出世和Javascript的一锤定音,CSS的出现就要漫长的多。

时间回到1991年,当时伯纳斯-李开发HTML的时候忘记了一个东西,那就是他没有提供给网页写样式的方法,而这个网页是什么样式完全由浏览器来决定,而CSS直到五年后才出现,十年后才完全的实现,这导致当时多种网页样式的实现方案在互相的竞争,尽管这些竞争方案最终没有使用起来,但是这并不方案我们去重新看看那他们当时的方案。

1993年初,那个时候Mosaic还没有发布1.0版本,当时浏览器还在研究的是应该怎么处理HTML,样式的实现完全是交给浏览器开发者按照喜好渲染,这个时候Robert Raisch提出过一个样式提案,命名为RRP。

RRP:

1
@BODY fo(fa=he,si=18)

CSS:

1
2
3
4
body{
font-faimily:helvetica
font-size:18px;
}

不得不说在那个网速只有14.4k而且没有gzip的时代,尽量压缩格式还是非常合理的。当时的样式表是要求在终端浏览器和图形浏览器都可以工作。很超前的是RRP当时设计了列布局的模式,这个是在CSS在2011年才引用的功能。RRP当时设计的是一个文档只能有 一个样式表,这个今天看来就比较奇怪了。

马克·安德森知道RRP这个提案,但是他在他开发的Mosaic中并没有实现这个提案,而使用了HTML标签的方式来实现样式,如<FONT>,<CENTER>,他当时的看法是为什么我要学习一种语言来开发文档,而学习另一种语言来把文档变成你想要的样子,从今天的角度来看,他当时确实是错了。

Mosaic其实并不是第一款图形界面的浏览器,ViolaWWW才是,这个是魏培源花了4天时间开发出来了,相比安德森花了6周开发的Mosaic他更加高效,他当时也创建了一个样式表语言PWP,并且支持嵌套结构。

PWP

1
2
3
4
5
6
7
(BODY fontSize=normal
BGColor=white
FGColor=black
(H1 fontSize=largest
BGColor=red
FGColor=white)
)

CSS

1
2
3
4
5
6
7
8
9
10
11
body{
font-size:normal;
background-color:white;
color:black;
}

body h1{
font-size:large;
background-color:red;
color:white;
}

可以看出PWP不仅风格简洁,并且是使用了类似StylusSASS的嵌套和缩进,避免了重复选择器来表示层级,这已经是很超前的设计。而且PWP还是外联样式的提出者:

1
<LINK REL="STYLE" HREF="URL_to_a_stylesheet">

只能说666,可惜的是ViolaWWW只能在X Window System下工作,当Mosaic移植到了Windows后,ViolaWWW也就消失了。

在HTML出现之前其实已经有类似的东西,SGML(标准通用标记语言)和HTML比较像,准确的说是HTML是派生自他,而另一种派生自SGML的语言叫做XML, XML产生的目的就是为了简化SGML。1987年美国国防部就成立一个名字为CALS(持续采办与全寿命支持计划)的小组,他们创造一个一门语言叫做FOSI来为SGML定义文档样式,

1993年就在魏培源给出提案的第四天,CALS提出了FOSI的一个变体来定义web样式。但是他并没有重新发明语言,因为FOSI就是直接用SGML书写的。

1
2
3
4
5
6
7
8
9
10
11
<outspec>
<docdesc>
<charlist>
<font size="12pt" bckcol="white" fontcol="black">
</charlist>
</docdesc>
<e-i-c gi="h1">\<font size="24pt" bckcol="red", fontcol="white"\></e-i-c>
<e-i-c gi="h2">\<font size="20pt" bckcol="red", fgcol="white"\></e-i-c>
<e-i-c gi="a"><font fgcol="red"></e-i-c>
<e-i-c gi="cmd kbd screen listing example"><font style="monoser"></e-i-c>
</outspec>

这段代码也就不翻译成对应的CSS了,因为你很难搞清楚docdesc和charlist是什么,而且当时接受提案的www-talk小组成员也搞不清,只能说明的是e-i-c代表的是element-in-context。
但是FOSI值得骄傲的事情是他们引入了em字体单位,这个已经被CSS开发者所熟悉。

另一个提案是DSSSL,这个是一个基于函数式语言Scheme创建的一门新语言,整理写法也很简洁,功能超级强大。我们来看一看他的功能。

定义样式:

1
2
3
4
(element H1
(make paragraph
font-size: 14pt
font-weight: 'bold))

定义函数:

1
2
3
4
5
6
7
(define (create-heading heading-font-size)
(make paragraph
font-size: heading-font-size
font-weight: 'bold))

(element h1 (create-heading 24pt))
(element h2 (create-heading 18pt))

样式中使用计算,比如定义一个黑白相间的表格:

1
2
3
4
5
(element TR
(if (= (modulo (child-number) 2)
0)
… ;even-row
…)) ;odd-row

而且可以把继承的属性值作为变量,在上面进行计算:

1
2
3
(element H1
(make paragraph
font-size: (+ 4pt (inherited-font-size))))

它的强大显而易见,但是它也继承了Scheme的缺点-括号太多,而且因为它语言上复杂让开发者望而却步,它在标准中包括了超过210项的独立样式。

PSL提案也值得一提,他有和CSS很像的基础语法

PSL

1
2
3
H1 {
fontSize: 20;
}

但是它的可扩展性以及功能性要比CSS丰富的多

获取浏览器真实尺寸

1
2
3
LI {
VertPos: Top = LeftSib . Actual Bottom;
}

支持逻辑表达式

1
2
3
4
5
6
A {
if (getAttribute(self, "href") != "") then
fgColor = "blue";
underlineNumber = 1;
endif
}

可以扩展很多想做的事情

1
2
3
4
5
6
7
8
9
LI {
if (ChildNum(Self) == round(NumChildren(Parent) / 2 + 1)) then
VertPos: Top = Parent.Top;
HorizPos: Left = LeftSib.Left + Self.Width;
else
VertPos: Top = LeftSib.Actual Bottom;
HorizPos: Left = LeftSib.Left;
endif
}

遗憾的是这种扩展性让人望而生畏。

说了这么提案,该说说CSS的前身了,1994年Håkon W Lie提出了CHSS

CHSS

1
2
h1.font.size = 24pt 100%
h2.font.size = 20pt 40%

这个行尾的百分比表示的是权重,假如之前定义的h2的大小为30pt,权重60%,那么加上这个样式表的24pt的40%,那么h2就应该是26pt。好吧,这个确实挺着有些科幻,但是它的一个思想影响到了之后的CSS,那就是样式表是可以叠加的,一个页面可以被允许有多个样式表。

1996年Håkon LieBert Bos合作,他们之前都有提交过样式表的提案,这个合作让他们一起设计了一个名为CSS的样式表天,在11月份发布了CSS规范的第一版,最终他把CSS的诞生写入了自己的博士论文中。

CSS相比其他提案的最大优势就是简单,易于阅读和编写,这再一次印证里一些历史的规律,很多最后取胜的技术并不是面向那些专家的,而是面向技术入门的初学者。

不过CSS的诞生对于浏览器依然是新生事物,浏览器需要重新设计解析器也可以完全支持CSS,1997年以前基本上CSS无法使用,大概到2000左右才有浏览器完全支持了它,但是大概在2010年之后才做到了与标准完全一致,这大概用去了15年的时间。

在浏览器大战期间,IE3在发布时开始支持CSS,但还是很糟糕,网景公司决定在Netscape 4上支持CSS,但是它的方案是将CSS转化为Javascript执行,命名为JSSS。当时很多开发者要么不使用CSS,要么就需要为IE和Netscape单独写两套样式表,可见当时浏览器对CSS支持之差。直到Netscape 6的时候Netscape也放弃了对JSSS的支持。

2000年IE 5.5 发布,才宣布着对CSS1的大部分支持。