CSS撿屎記 // Web開發之精通CSS

本文首發於圖靈教育微信

本文作者:李松峰

農諺:「種地不上糞,等於瞎胡混。」

跟許許多多大城市裡的上班族一樣,我也是在農村長大的。因此,毋庸諱言,我小時候拾過糞。畢竟,那時候在農村長大的孩子,有幾個沒拾過糞呢。糞就是屎,主要是牛屎,因為個頭大,我們那裡也把風吹日晒幹了的牛糞叫作「牛糞坯子」。

屎,本來是廢棄物。但正如牛糞,卻是農民種地所必需的天然肥料,是莊稼茁壯成長的營養來源,更是來年好收成的重要保障。俗話說:「沒有尿屎臭,哪有稻米香?」

如今,我有幸成為一名在前端領域辛勤耕種的碼農。就在前幾天,我心血來潮,從電腦里翻出了十幾年前出版的一本CSS名著的第1版(2006年)和第2版(2009年)。翻來翻去,我不禁聯想到小時候拾糞的經歷。說到這裡,不少讀者可能還不明就裡,其實如果你是一名資深前端,我只要提幾個當年火得不得了的技術你就會明白我在說什麼了。

好吧,閑話少說,言歸正傳。馬上開始我們的CSS拾糞之旅吧!

圓角盒子

不知道大部分讀者怎麼樣,反正我一聽到這個詞就會有一種穿越感。十幾年前,CSS遠遠不如今天這麼強大。頁面仔們想要在網頁中實現稍微前沿、酷炫一點的效果,都必須絞盡腦汁。

滑動門

「滑動門」,即Sliding Doors,是誕生於2003的一種實現「圓角盒子」技術。假設最終要通過CSS實現下圖中這樣可以伸縮適應的圓角盒子:

你會怎麼做?

……等等,那可是在遙遠的2003年,當時的CSS標準里並沒有border-radius這麼一個屬性,更沒有瀏覽器支持類似的特性。於是,一位聰明的大牛Douglas Bowman發明了「滑動門」技術。其原理如下圖所示:

圖中展示了兩個GIF圖片:top-left.gif和top-right.gif,前者頭部是一個1/4圓且比較長,後者尾部是一個1/4圓且比較短。

關鍵是使用background-image和background-position屬性,後者最終會覆蓋到前者上面。當然,要實現4個圓角,就必須要用到4張圖片:

配合HTML標記和CSS代碼更容易理解:

<div class="box">
<div class="box-outer">
<div class="box-inner">
<h2>Headline</h2>
<p>Content</p >
</div>
</div>
</div>

.....

.box {
width: 20em;
background: #effce7 url(images/bottom-left.gif) ?
no-repeat left bottom;
}
.box-outer {
background: url(images/bottom-right.gif) no-repeat right bottom;
padding-bottom: 5%;
}
.box-inner {
background: url(images/top-left.gif) no-repeat left top;
}
.box h2 {
background: url(images/top-right.gif) no-repeat right top;
padding-top: 5%;
}
.box h2, .box p {
padding-left: 5%;
padding-right: 5%;
}

哇哦,精彩!

可以腦補出來最終效果的同學請為自己鼓掌,同時也恭喜你成功撿起了第一塊「牛糞」。暫時還沒搞明白的小夥伴也不必氣餒,有時候撿屎本身也是個技術活兒呢~

山頂角

「山頂角」,英文是Mountaintop Corners,誕生於2004年,由另一位牛人Dan Cederholm發明。相比於「滑動門」直接用圖片本身充當圓角,「山頂角」反其道而行之:用圓角蒙版遮住背景顏色實現圓角,因此更為靈活。上圖:

如果一看到這張圖你就立即明白了,那恭喜你,第二塊「牛糞」成功入筐。還不明白的同學,請看以下代碼,HTML跟前面類似,同樣需要4個元素來應用4張背景圖片:

<div class="box">
<div class="box-outer">
<div class="box-inner">
<h2>Headline</h2>
<p>Content</p >
</div>
</div>
</div>

CSS也極為相似:

.box {
width: 20em;
background: #effce7 url(images/bottom-left.gif) ?
no-repeat left bottom;
}
.box-outer {
background: url(images/bottom-right.gif) no-repeat right bottom;
padding-bottom: 5%;
}
.box-inner {
background: url(images/top-left.gif) no-repeat left top;
}
.box h2 {
background: url(images/top-right.gif) no-repeat right top;
padding-top: 5%;
}
.box h2, .box p {
padding-left: 5%;
padding-right: 5%;
}

成功撿到這塊「牛糞」的同學也不要過分興奮,「山頂角」雖然可以通過簡單修改背景顏色來改變圓角盒子的顏色,省去重新製作圖片的麻煩,但它也有不足。由於當時每個角的蒙版圖片是用點陣圖製作的,所以只適用於製造細微的曲線,較大弧度的圓角會顯得粗糙。

不過,瑕不掩瑜。「山頂角」無論如何都是當時製作圓角盒子當之無愧的王牌技術,更是當時每一個頁面仔的大救星。十幾年後,當屏幕前的我們與這塊「牛糞」不期而遇時,一定也會暗自讚歎。關鍵是,這塊簡潔巧妙的牛糞,它好撿啊!

多重背景圖片

在前述兩塊重量級「牛糞」的啟發下,支持多背景圖片的background-image屬性終於應運而生。於是,更簡單的實現方案出現了:

.box {
background-image: url(/img/top-left.gif),
url(/img/top-right.gif),
url(/img/bottom-left.gif),
url(/img/bottom-right.gif);
background-repeat: no-repeat,
no-repeat,
no-repeat,
no-repeat;
background-position: top left,
top right,
bottom left,
bottom right;
}

當然,給一個元素應用多個背景並不局限於實現圓角盒子效果。至於還可以實現什麼,請相信:限制你的只有你的想像力。

圓角邊框

同樣是在前兩塊「牛糞」滋養的沃土之上,迄今為止最為簡單強大的border-radius屬性也誕生了:

.box {
border-radius: 1em;
}

成功撿起兩塊「牛糞」之後,是不是很有成就感?你還想繼續撿?沒問題,走著~


下拉陰影

想當初,不僅僅是實現圓角盒子需要全世界的大牛為之殫精竭慮,同樣讓他們苦思冥想的還有下拉陰影。

先看看Dunstan Orchard大牛的傑作。其核心思想就是給元素背景上應用一大張陰影圖,然後通過負外邊距把陰影部分顯露出來。

如圖所示,這是一張800px?800px的陰影圖shadow.gif,其右下角放大後看可以看到5像素的陰影。以下是要應用陰影效果的HTML:

<div class="img-wrapper">
< img src="dunstan.jpg" width_="300"?
height="300" alt="Dunstan Orchard" />
</div>

顯然,這是一個容器div中包含一張人物圖片(dunstan.jpg)。為了讓容器div包裹住圖片,首先要利用float讓這個塊級元素收縮,從而包裹住其中的圖片:

.img-wrapper {
background: url(images/shadow.gif) no-repeat bottom right;
clear: right;
float: left;
}

但這樣背景圖片完全隱藏在了人物圖片下方,為了讓它顯露出來,還必須配合神奇的負外邊距:

.img-wrapper img {
margin: -5px 5px 5px -5px;
}

於是,立體感十足的陰影效果做成了,見下圖:

不過,這硬邊陰影看著也忒不自然了,就算是在十幾年前也是無法接受的。那好,這塊「牛糞」還要做大點。為了模擬出自然的陰影,還需要一張與剛才的陰影圖片對角的模糊蒙版:

HTML標記也要再嵌套一層div:

<div class="img-wrapper">
< img src="dunstan.jpg" width_="300"?
height="300" alt="Dunstan Orchard" />
</div>

首先,還是給最外層的容器div應用硬邊陰影背景,定位在右下角:

.img-wrapper {
background: url(images/shadow.gif) no-repeat right bottom;
float: left;
}

然後,給內層的div應用模糊蒙版背景,定位在左上角:

.img-wrapper div {
background: url(images/mask.png) no-repeat left top;
padding: 0 5px 5px 0;
}

最後,再給圖片添加個邊框:

.img-wrapper img {
background-color: #fff;
border: 1px solid #a9a9a9;
padding: 4px;
}

大功告成:

完美!

盒陰影

這塊大「牛糞」威力夠大,直接催生了box-shadow:

img {
box-shadow: 3px 3px 6px #666;
}

這裡用了僅僅一個屬性,而且效果同上。冗長的HTML和CSS代碼不見了,它們去哪兒了?那還用問,它們已經化作沉甸甸的「牛糞」裝進了你我的糞筐里。恭喜你再次撿屎成功!


圖片替換

想當年,大牛們為了使用特殊字體實現不一樣的視覺效果,必須先把文字轉換成圖片,因為用戶機器上已安裝的通用字體數量有限。但圖片對搜索引擎不友好,於是有牛人想出了點子。總體的思路是像往常一樣使用文本,讓搜索引擎可以找到,同時再通過某種方式讓它對用戶不可見,只顯示包含特殊字體效果的圖片。

比如,Todd Fahrner的Fahrner Image Replacement (FIR)。先把文本包一個span中:

<h2>
<span>Hello World</span>
</h2>

然後給標題h2添加背景:

h2 {
background:url(hello_world.gif) no-repeat;
width: 150px;
height: 35px;
}

最後,隱藏span:

span {
display: none;
}

可是,由於多數屏幕閱讀器會忽略display:none;的元素,從而導致嚴重的無障礙問題。所以,這個看似簡單的方案實踐中並不可行。

於是,另一位牛人Mike Rundle想出了一個兩全其美的點子:使用負文本縮進把文本拉到屏幕之外!

這下HTML還更簡單了:

<h2>
Hello World
</h2>

CSS:

h2 {
text-indent: -5000px;
background:url(hello_world.gif) no-repeat;
width: 150px;
height:35px;
}

這就解決了屏幕閱讀器用戶的問題。但還沒有完,新的問題又出來了。在當時網路速度很慢的情況下,可能會有用戶禁用瀏覽器顯示圖片的功能,而CSS照樣起作用。這是一種極端情況,這時候用戶會既看不到文本,也看不到圖片。

追求完美的大牛們又開始行動了。Tom Gilder和Levin Alexander最終找到了既對屏幕閱讀器友好,又能在禁用圖片打開CSS的情況下讓文本對用戶可見的方案。

這個方案首先要在被替換的元素內額外添加一個空標籤(span):

<h2>
<span></span>Hello World
</h2>

然後,將容器設置為相對定位:

h2 {
width: 150px;
height: 35px;
position: relative;
}

position:relative;將容器設定為其中span的定位上下文。接下來,把背景應用給span,並採用絕對定位,而寬和高均為父元素的100%會讓它完全把文本蓋在下面:

h2 span {
background: url(hello_world.gif) no-repeat;
position: absolute;
width: 100%;
height: 100%;
}

這裡只有一個問題,此時的圖片必須完全不透明,否則下面的文本就會「走光」。

如前所述,這幾塊「牛糞」最終要解決的是用戶計算機上字體匱乏的問題。這些需求最終也催生了十幾年後可以廣泛使用的Web字體。

@font-face {
font-family: Vollkorn;
src: url(fonts/Vollkorn-Regular.eot#?ie) format(embedded-opentype),
url(fonts/Vollkorn-Regular.woff2) format(woff2),
url(fonts/Vollkorn-Regular.woff) format(woff),
url(fonts/Vollkorn-Regular.ttf) format(truetype),
url(fonts/Vollkorn-Regular.svg) format(svg);
}

Web字體是一個大話題,在此我們就不過多涉及了。總之,我們再一次見證了「牛糞」的力量,同時也給我們今天的拾糞之旅畫上了一個完美的句號。


明日份牛糞

天下碼農千千萬,大牛卻不多。大牛之所以成為大牛,通常都會給數年後的從業者留下可供撿拾的「牛糞」。今天我們的拾糞之旅,既是對CSS歷史上曾經輝煌一時的技術的巡禮,更是對如群星般璀璨的大牛們的致敬。

這些曾經紅極一時的技術在今天看來或許不值一提,甚至幼稚可笑。然而,「後之視今,亦猶今之視昔。」今天被頂禮膜拜、推崇備至的技術,十幾年後再看,或許同樣不值一提,甚至幼稚可笑。但不容否認的是,恰恰是這些今天看來簡單、幼稚的「牛糞」,孕育、滋養了一代一代技術人,推動著技術不斷進步和突破。人類社會就是這樣一路走過來的。

朝花夕拾。從拾糞的視角看,我們不禁深思:今天的碼農,有幾人能留下供十年後的人撿拾的「牛糞」呢?所以,今天起,給自己定個小目標,著手準備我們的明日份「牛糞」吧!

看到這裡,有好奇的同學可能會問:這些「牛糞」到底來自哪本CSS名著,能否透露一下?當然可以。它們就是CSS Mastery: Advanced Web Standards Solutions (中文版《精通CSS》)的第1版和第2版。而且,這本名著的最新版也就是第3版的中文版也剛剛上市。值得一提的是,《精通CSS(第3版)》里可是滿滿的「明日份牛糞」哦,如果想開啟你的CSS「撿屎」之旅,那一定會是個不錯的體驗。

CSS暢銷經典全面升級,充分展示現代CSS實踐技巧

本書是CSS經典圖書升級版,結合CSS近年來的發展,尤其是CSS3和HTML5的特性,對內容進行了全面改寫。本書介紹了涉及字體、網頁布局、響應式Web設計、表單、動畫等方面的實用技巧,並討論了如何實現穩健、靈活、無障礙訪問的Web設計,以及在技術層面如何實現跨瀏覽器方案和後備方案。本書還介紹了一些鮮為人知的高級技巧,讓你的Web設計脫穎而出。

搶先入手升級版?到京東購買

到圖靈社區試讀更多

推薦閱讀:

TAG:CSS | 前端開發 | Web開發 |