【Hello CSS】序章-起源

陳大魚頭發表於2019-03-03

HTML的誕生

HTML是怎麼來的?

在1982年的時候,全球資訊網的發明者Tim Berners-Lee爵士為了讓全世界的物理學家能夠方便的進行合作與資訊共享,造了HTML(HyperText Markup Language) 超文字標記語言。

在1991年3月,Tim Berners-LeeHTML介紹給了給他在CERN(歐洲核子研究中心) 工作的朋友,當時網頁瀏覽器被其世界各地的成員用來瀏覽CERN龐大的電話薄。

然後在8年之後的1990年,博士發明了世界上第一個瀏覽器WorldWideWeb,也因此推動著網際網路高速發展。

WorldWideWeb問世之後的1993年NCSA推出了Mosaic瀏覽器並且迅速火了起來,成為第一個世界級應用的瀏覽器,推動著網際網路發展。隨後跟著的有當時的兩大霸主Netscapede Netscape瀏覽器與MicroSoftInternet Explorer瀏覽器,這兩個瀏覽器在當時掀起了一場網際網路瀏覽器大戰。這場戰爭的結果是以Internet Explorer全勝告終。但也因此大大的推動了網際網路的發展。

CSS的誕生

CSS是怎麼來的?

就在承載HTML的瀏覽器迅猛發展的90年代,CSS (Cascading Style Sheet)也應運而生。不同的瀏覽器結合各自HTML 語法結構實現了很多不同的外部樣式語法。但隨著HTML的發展,為了滿足設計師的要求而增加了很多顯示功能,隨著這些功能的增加,外部樣式語法作用越來越沒有意義。

在1994年10月10日,CSS之父Håkon Wium Lie提出了 CSS 的最初建議,並且為 HTML 樣式在芝加哥的一次會議上正式提出了 CSS 。

在1996 年 12 月,W3C在經過多方的討論之後,推出了CSS1.0。這一規範一出現就引起了各方的注意,隨即 MicroSoft 公司和 Netscape 公司紛紛表示自己的瀏覽器能夠支援 CSS1.0

CSS的各個版本

CSS各版本的更新

  1. CSS1.0在1997 年 由W3C釋出,第一版主要規定了選擇器樣式屬性偽類 / 物件幾個大的部分;
  2. CSS2.0/2.1在1998 年 由W3C釋出,CSS2 規範是基於 CSS1 設計的,擴充和改進了很多更加強大的屬性。包括選擇器位置模型佈局表格樣式媒體型別偽類游標樣式
  3. 由於CSS2經歷了 9 年的時間(從 2002 年 8 月到 2011 年 6 月)才達到 Recommendation(推薦) 狀態,此後W3C為了加快那些已經確認沒有問題的特性的標準化速度,便作出了一項被稱為 Beijing doctrine 的決定,將CSS模組化,並且按照每個模組的進度來標準化。所以從形式上來講,CSS3已經不存在了。現在CSS 包括了修訂後的 CSS2.1 以及完整模組對它的擴充,模組的 level(級別)數並不一致。可以在每個時間點上為 CSS 標準定義一個 snapshots(快照)。

下圖為CSS模組化的發展程式圖,來自MDN

【Hello CSS】序章-起源

差點要成為CSS的語言

現在的CSS也是經過一番爭鬥才脫穎而出的

以下內容翻譯於The Languages Which Almost Became CSS

第一個提案

早在1993年Mosaic瀏覽器1.0釋出之前,當時現有的瀏覽器已經開始獨立處理HTML了,但是它們並沒有能給標籤定製樣式的方式,這就意味著你看到的標籤長什麼樣就長什麼樣,不能改。

所以在1993年的6月,Robert Raischwww-talk郵件發了一個提案,希望建立一個“一種易於解析可以與Web文件一起提供樣式資訊的格式”,並給它起名叫RRP

格式如下:

@BODY fo(fa=he,si=18)
複製程式碼

看不懂上面的程式碼是情有可原的。在gzipping之前的時代,網路傳輸速度只有14.4K,所以格式儘量壓縮都是合理的。這個特殊規則是將font family (fa)設定為helvetica (he),將font size(si)設定為18 points

Viola 以及原始瀏覽器之戰

和流行的看法不一樣,Mosaic並不是第一個圖形瀏覽器,ViolaWWW才是。由Pei-Yuan Wei花了4天寫的。

以下是Pei-Yuan Wei建立的樣式表語言:

(BODY fontSize=normal
      BGColor=white
      FGColor=black
  (H1   fontSize=largest
        BGColor=red
        FGColor=white)
)
複製程式碼

在這個例子中我們給body新增了顏色選擇器,並且給body中的h1新增了樣式。

值得一提的是PWP還是引用外部樣式表的方法提出者,他提出的方法一直沿用至今。

<LINK REL="STYLE" HREF="URL_to_a_stylesheet">
複製程式碼

不幸的是,ViolaWWW只能執行在X Window System系統中,這個系統只在Unix中受歡迎。當Mosaic移植到Windows上不久後就把ViolaWWW拋到身後了。

Web之前的樣式表

早在網際網路之前就有對文件樣式進行修改的語言要求。

正於你所知道的,HTML源於一個在網際網路之前就出現的語言,SGML。早在1987年,美國國防部就決定研究SGML是否可以使文件儲存和傳輸更加便捷,他們有大量的文件需要處理。跟其他好的政府專案一樣,他們沒有時間可以浪費在起名上。這個團隊最初叫計算機輔助後勤支援隊,後來叫計算機輔助採集和後勤支援隊,最後叫持續獲取和生命週期支援計劃。反正簡寫都是CALS

CALSSGML建立了一個叫FOSI(這是一個四字單詞簡寫,但是因為年代久遠,已經不知道是哪四個單詞了)的語言來為文件新增樣式。 例子如下:

<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>
複製程式碼

如果你困惑docdesccharlist,那麼你要知道,www-talk的成員跟你有同樣的困惑。唯一給出上下文資訊的是e-i-c,即element in contextFOSI值得注意的是引入了em作為字型單位,現在已經成為了很多熟悉CSS的人中更受歡迎的方法。

圖靈完備的樣式表

由於它的複雜性,FOSI被認為是格式化文件問題的臨時解決方案。長遠的解決方案是建立一個基於函數語言程式設計語言Scheme的新語言,它可以做任何你能想象到的文件轉換。這門語言叫DSSSL

下面是語法:

(element H1
  (make paragraph
    font-size: 14pt
    font-weight: 'bold'))
複製程式碼

因為它是一門程式語言,所以你可以函式化:

(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))
複製程式碼

並在樣式中使用數學結構,例如“條帶化”表的行:

(element TR
  (if (= (modulo (child-number) 2)
        0)
    …   ;even-row
    …)) ;odd-row
複製程式碼

最後,讓你妒忌一下,DSSSL可以把繼承的值當成變數進行數學運算:

(element H1
  (make paragraph
    font-size: (+ 4pt (inherited-font-size))))
複製程式碼

不幸的是,DSSSL擁有和跟所有Scheme類語言一樣的致命弱點:括號太多了。此外,當它最終釋出時,它可能過於完整,使瀏覽器開發人員感到害怕。 DSSSL規範包含210多個獨立的可以定製樣式的屬性。

為什麼樣式表脫穎而出?

CSS 沒有父級選擇器(一種基於子元素的樣式給父元素設定樣式的方法)。 這個問題在Stack Overflow上被頻繁的提問(這是其中一個)。但是事實證明,這個特性缺失是有理由的。特別在網際網路早期,讓網頁在完全載入完成之前被渲染,是很重要的。意思就是,大家希望HTML載入完之前,就可以渲染已經載入完的部分。

父選擇器意味著樣式得在HTML文件一邊載入時,一邊更新。像DSSSL這樣的語言如果實現了這個功能,因為它們可以對文件進行操作,所以也沒很可能就不能用了。

在1995年3月,Bert Bos作為第一個提出這個問題的人,還提供可行方案。他的提案中還包括了一個早期的笑臉表情包:-)

這個語言有點像物件導向:

*LI.prebreak: 0.5
*LI.postbreak: 0.5
*OL.LI.label: 1
*OL*OL.LI.label: A
複製程式碼

使用.來指定直接子節點,使用* 來指定祖先節點。

他的語言還有一個很酷的屬性,就像這樣在樣式表中定義超連結:

*A.anchor: !HREF
複製程式碼

在上面的例子中,指定link的目標為其HREF的值。像這種可控制連結等元素的行為在很多提案中都很流行。在Javascript還沒出來之前,沒有什麼可控制元素的方法,所以它們看起來是很合理的。

一個函式式的提案,1994年被一位叫C.M. Sperberg-McQueen的紳士提出,裡面包含了類似的行為。

(style a
  (block #f)     ; format as inline phrase
  (color blue)   ; in blue if you’ve got it
  (click (follow (attval 'href)))  ; and on click, follow url
複製程式碼

他的語言還引入了content關鍵字作為從樣式表控制HTML元素內容的一種方式,這個概念後來被引入到CSS 2.1中。

可能還有什麼

在我談到實際成為CSS的語言之前,還有另一種語言值得一提,因為它在某種程度上是早期Web開發者的夢想。

它就是PSL96,按照當年的命名規範,1996年版的Presentation Specification Language。PSL的核心很像CSS:

H1 {
  fontSize: 20;
}
複製程式碼

然而,它很快就變得很有趣了。例如,你不僅可以根據元素寬度來渲染它的位置,也可以基於瀏覽器的實際寬度來渲染。

LI {
  VertPos: Top = LeftSib . Actual Bottom;
}
複製程式碼

甚至你可以使用元素左邊的兄弟姐妹來定製。

你還可以為樣式新增邏輯表示式。例如,僅設定具有href的錨元素的樣式:

A {
  if (getAttribute(self, "href") != "") then
    fgColor = "blue";
    underlineNumber = 1;
  endif
}
複製程式碼

這種樣式可以擴充套件到我們今天用樣式來完成的各種事情:

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
}
複製程式碼

支援這功能的話或許真的可以實現內容與樣式分離的夢想。遺憾的是這門語言擴充性太強,這就以為著不用瀏覽器的實現可能會不一樣。而且,它是以一系列的文章出現出現在學術界,並沒有經過www-talk郵件列表進行討論,所以,它永遠不會出現在主流瀏覽器。

CSS之魂

一門語言,至少從名字上,直接引出了CSS,它叫CHSS (Cascading HTML Style Sheets)提案在1994年被Håkon W Lie提出。

跟很多好主意一樣,這個原始提案非常瘋狂。

h1.font.size = 24pt 100%
h2.font.size = 20pt 40%
複製程式碼

注意行尾的百分比,這個百分比是指當前樣式表佔用該值的“權重”。例如,如果之前的樣式表已將h2字型大小定義為30pt,擁有60%,並且此樣式表將h2s設定為20px 40%,則這兩個值將根據其權重百分比進行組合在一起,大概就是26pt。

很明顯,這個提案是在基於文件的HTML頁面的時代,基於拖鞋的設計是無法在我們面向應用的世界裡發揮作用的。不過,它已經具備了樣式表應該可以疊加的基本思想。換句話說,應該可以將多個樣式表應用於同一頁面。

它最初的形式被認為是重要的,因為它讓使用者可以控制他們所看到的內容。頁面有一個樣式表,並且Web使用者將擁有自己的樣式表,這兩個樣式表一起渲染在頁面上。支援多個樣式表被視為一種維護Web個人自由的方法,而不是支援開發人員(他們仍然手動編寫單獨的HTML頁面)的方式。

使用者可以控制該頁面作者的建議的權重,就如提案中的ASCII 圖那樣。

       User                   Author
Font   o-----x--------------o 64%
Color  o-x------------------o 90%
Margin o-------------x------o 37%
Volume o---------x----------o 50%
複製程式碼

像許多這些提案一樣,它包含了幾十年來不可能出現在CSS中的特性。例如,可以根據使用者的環境編寫邏輯表示式。

AGE > 3d ? background.color = pale_yellow : background.color = white
DISPLAY_HEIGHT > 30cm ? http://NYT.com/style : http://LeMonde.fr/style 
複製程式碼

在一個有點樂觀的未來場景中,瀏覽器會根據給定的內容對你的相關性,允許它以更大的尺寸展示給你看。

RELEVANCE > 80 ? h1.font.size *= 1.5
複製程式碼

你知道接下來發生了什麼

Håkon Lie繼續簡化他的提案,且和Bert Bos合作,並在1996年11月釋出的CSS規範的第一版。最終他將創造CSS寫進了他的博士論文裡,也就是這個文件幫助我寫了這篇文章。

與許多其他提案相比,CSS的一個值得注意的事實是它的簡單性。它易於分析,易於編寫和輕鬆閱讀。與網際網路歷史上的許多其他例子一樣,對於初學者來說,需要的是最容易上手的技術,而不是那些給更強大的專業人員用的技術。

它本身就給我們一個提醒,這是一個偶然發生的創新。例如,僅新增了對上下文選擇器(body ol li)的支援,因為Netscape已經有一種方法可以從超連結的影像中刪除邊框,並且似乎有必要實現流行瀏覽器可以執行的所有操作。這個功能本身就大大拖延了 CSS 的實現,因為大多數瀏覽器在解析HTML時沒有保留標籤的“堆疊”。這意味著必須重新設計解析器才能完全支援CSS。

像這樣的挑戰(以及廣泛使用非標準HTML標籤來定義樣式)導致著CSS直到1997年才可使用,直到2000年3月才有瀏覽器完全支援它。這跟每個開發者跟你說的一樣,瀏覽器近幾年才真正標準化,這裡距首次釋出CSS已經過去了21年(原文15年)了。

最終BOSS

IE 3以(有點可怕的)CSS支援著稱。為了競爭,Netscape 4也考慮了CSS。但它還是決定通過將CSS轉換為JavaScript並執行它來實現它,而不是將第三種(考慮HTML和JavaScript)。更有甚者,Web開發人員應該可以訪問這個“JavaScript樣式表”中間語言。

語法是直接使用JavaScript,然後新增了一些特定樣式的API:

tags.H1.color = "blue";
tags.p.fontSize = "14pt";
with (tags.H3) {
  color = "green";
}

classes.punk.all.color = "#00FF00"
ids.z098y.letterSpacing = "0.3em"
複製程式碼

你甚至可以定義一個每遇到一個標籤就執行一次的函式:

evaluate_style() {
  if (color == "red"){
    fontStyle = "italic";
  } else {
    fontWeight = "bold";
  }
}

tag.UL.apply = evaluate_style();
複製程式碼

我們應該簡化樣式和指令碼之間分界線的想法是合理的,現在在React社群還出現了各種類似的思路。

在當時,JavaScript本身就是一種非常新的語言,但是通過一些逆向工程,IE已經在IE3中新增了對它的支援(如“JScript”)。更大的問題是社群已經在CSS周圍團結起來,而Netscape在這個時候被大多數標準社群視為胖虎(原文bullies)。當Netscape確實向標準委員會提交JSSS時,它被置若罔聞。三年後,Netscape 6放棄了對JSSS的支援,而且自己也準備安樂死了。

還有什麼可能

由於W3C的一些公開羞辱IE 5.5在2000年推出了幾乎完整的CSS1支援。當然,正如我們現在所知,瀏覽器的CSS在未來10年裡都非常粗糙且難以使用。還好今天情況大大改善了,讓開發者寫一份程式碼並在不同瀏覽器中都可以執行的夢想(幾乎)實現了。

我個人的結論是,無論這些決策是拍大腿決定的還是深思熟慮的,都決定了當前工具的形式。如果CSS的設計方式只是為了滿足1996年的限制,那麼20年後的我們做事的方式應該會有些不同。

參考文章:

CSS之父的訪談錄

基於 CSS3 的下一代 Web 應用開發,第 1 部分

差點要成為CSS的語言

CSS3(MDN)

【Hello CSS】系列

【Hello CSS】是以CSS基礎概念為主題的系列文章,旨在幫助大家更深刻地瞭解並且提高CSS在各位開發者心目中的地位。由於魚頭我水平有限,文筆有限,如果各位在文章中發現有任何不合理,不正確的地方,還煩不吝指出,我會非常感謝的;如果通過文章有任何想法或疑問,也希望各位能積極留言,我們互相探討;如果通過本系列文章有所收穫,這就讓魚頭我喜不自勝了!



如果你也喜歡`CSS`,喜歡探討技術,或者對本文,本系列有任何的意見或建議,魚頭非常希望你能加入一個有趣的微信群 — “進擊的CSS”。你可以掃描下方二維碼,新增魚頭微信,新增時註明 “加群”,如果你覺得我的文章有趣,歡迎關注微信公眾號“魚頭的Web海洋”。衷心希望可以遇見你。

【Hello CSS】序章-起源

下一篇

【Hello CSS】第一章-CSS的語法與工作流

歷史文章傳送門

1.【Hello CSS】序章-起源