CSS的誕生
1. HTML的困境
我是著名的CSS, 很多人都知道我的名字, 但是卻對(duì)我的原理和細(xì)節(jié)不求甚解。
這也可以理解,相比于簡(jiǎn)單的HTML,我要復(fù)雜得多, 尤其是想要使用我做出美奐美倫的頁(yè)面,需要了解太多的細(xì)節(jié),那真不是一件普通人能干的事兒。 于是大家看見我以后最多打個(gè)招呼,然后馬上低頭繞行。
說起HTML,這其實(shí)是個(gè)非常單純的家伙, 他只關(guān)注內(nèi)容的語義, 比如說他用<h1>表明這是一個(gè)大標(biāo)題,用<p> 表明這是一個(gè)段落,用<img> 表明這兒有一個(gè)圖片, 用<a> 表示此處有鏈接。
鏈接真是個(gè)有趣的發(fā)明, 它可以從一個(gè)網(wǎng)頁(yè)跳到另外一個(gè)網(wǎng)頁(yè),從一個(gè)網(wǎng)站跳到另外一個(gè)網(wǎng)站,于是整個(gè)世界的網(wǎng)站都鏈接了起來,形成了一張大網(wǎng) 。
在我誕生之前, 世界上的網(wǎng)站雖然很多,但是他們都有一個(gè)共同的特點(diǎn): 丑。
原因很簡(jiǎn)單, 一個(gè)HTML文檔有很多標(biāo)簽, 當(dāng)這些標(biāo)簽組合起來的時(shí)候,到底該怎么顯示呢? 用什么樣的字體? 什么顏色? 怎么對(duì)齊?
HTML不想管也管不了,于是早期的網(wǎng)站大部分長(zhǎng)這個(gè)樣子:
真是難以想象,上個(gè)世紀(jì)的人們竟然用這么簡(jiǎn)陋的網(wǎng)站來購(gòu)物 !
無數(shù)的人向HTML投訴: 你就不能把自己打扮得漂亮一點(diǎn)嗎?
HTML理直氣壯地回答:不不,我的主人只讓我負(fù)責(zé)網(wǎng)頁(yè)的內(nèi)容和結(jié)構(gòu),至于這些結(jié)構(gòu)要顯示成什么樣子,瀏覽器可以負(fù)責(zé)啊。
而瀏覽器也會(huì)推卸責(zé)任:“這我可管不了,你不告訴我你用什么字體,什么顏色,我怎么可能給你展示出來?”
理由很充分,對(duì)吧,瀏覽器確實(shí)不應(yīng)該做這件事情。
HTML沒有辦法,只好向組織上申請(qǐng),給自己加上一堆新的標(biāo)簽, 專門用來描述展示相關(guān)的東西:
于是網(wǎng)頁(yè)變得比以前漂亮了一些,大家似乎滿意了。
只是HTML發(fā)現(xiàn)自己的身軀越來越臃腫,這些負(fù)責(zé)顯示的標(biāo)簽把原本的內(nèi)容都給淹沒了, 更要命的是修改的難度越來越高,你可以想象一下,當(dāng)一個(gè)html文件中有上百個(gè)<font>標(biāo)簽時(shí), 老板讓你把字體改小一號(hào), 那肯定要抓狂的。
組織上看到了問題的癥結(jié)所在, 決定為HTML瘦身, 他定下了一個(gè)目標(biāo): “內(nèi)容和樣式必須要分離!”
這個(gè)重?fù)?dān)就交給了我。
2 選擇器
剛開始的時(shí)候,我一點(diǎn)思路都沒有,到底怎么把內(nèi)容和樣式分離呢? 我為此苦苦思考了好幾天,既然我想給內(nèi)容施加樣式, 作為***步, 必須要解決定位的問題,換句話說我需要能找到HTML中的元素才可以。
我問HTML:“ 你一個(gè)頁(yè)面這么多標(biāo)簽, 我怎么才能獲得你完整的結(jié)構(gòu)呢?”
“結(jié)構(gòu)? 那很簡(jiǎn)單啊, 我在瀏覽器中就是一個(gè)DOM 樹啊, 你盡管訪問啊 ”
好 ! 有這個(gè)玩意兒就好辦事了,但是我怎么定位到一個(gè)元素,去設(shè)定這個(gè)元素的字體,顏色等顯示屬性呢?
XML向我支招: “這太容易了, 你可以仿照我的XPath啊,例如那個(gè)DOM樹,你想選中title 元素,就用 /html/head/title ,或者簡(jiǎn)單一點(diǎn)//title ; 你想選中***個(gè)div 下面的h3, 可以這么做 /html/head/div[1]/h3 ,是不是很方便? ”
(碼農(nóng)翻身老劉注:實(shí)際上XPath的出現(xiàn)要比CSS晚)
“方便是方便, 可是你這為什么要一個(gè)斜杠呢? 直接寫成html head title 不行嗎? ”
"這。。。" XML無語了。
我決定不用斜杠,我要討好程序員,就用div ul li 這樣寫起來很簡(jiǎn)潔的方式, 我也不想叫XPath, 那是XML的寶貝。
我打算把它叫做選擇器(Selector)。比如說我想把所有的h3都變成紅色, 黑體, 可以這么寫:
h3 {color:blue ; font-weight:bold;}
當(dāng)然我設(shè)計(jì)的選擇器能力可不僅僅這么簡(jiǎn)單,使用它你完全可以選擇一個(gè)特定的節(jié)點(diǎn)(如果有id屬性或class屬性的話),不管這個(gè)節(jié)點(diǎn)“隱藏”得有多深。
還可以選擇一個(gè)節(jié)點(diǎn)的兄弟節(jié)點(diǎn), 某組元素的第x個(gè)孩子,任何帶有屬性名的標(biāo)簽名等等。
一句話, 使用Selector, 你可以盡情在DOM樹中遨游, 找到你想要的地方, 然后設(shè)置樣式。
內(nèi)容和樣式就分離了。
3 盒子
定位的問題解決了, 初步的樣式也解決了。 但是最讓人排版的問題依然存在, 想想你曾經(jīng)看過的報(bào)紙和雜志,人家那圖文并茂,賞心悅目的排版, 我們得好好學(xué)習(xí)下了。
我對(duì)雜志的排版做了仔細(xì)的研究, 分欄,間距,對(duì)齊, 圖文混排, 本質(zhì)上他們是由一個(gè)個(gè)“塊”組成的。
我對(duì)HTML說: 咱們能不能也把內(nèi)容搞成一個(gè)一個(gè)的塊啊, 然后把這些塊進(jìn)行組合不就成了?
HTML回答: “塊(block) 我有啊, 你還不知道嗎, 所有的HTML元素要么是塊級(jí)(block)元素,要么是行內(nèi)(inline)元素。”
“什么意思?”
“塊級(jí)元素(比如標(biāo)題和段落) 會(huì)一個(gè)接一個(gè)的堆疊起來沿著頁(yè)面向下排列,每個(gè)元素占一行; 行內(nèi)元素(比如鏈接和圖片)則會(huì)在一行內(nèi)相互并列,只有在空間不足以并列的時(shí)候才會(huì)折到下一行。你可以想象一下, 一個(gè)文檔其實(shí)就是這些元素在頁(yè)面上堆疊流動(dòng)而已, 俗稱文檔流。”
既然如此, 我就可以把這些元素當(dāng)成一個(gè)個(gè)的“盒子”了,為了能夠排版,我給每個(gè)盒子都都設(shè)定三個(gè)屬性:
邊框(border): 可以設(shè)定寬窄,樣式,顏色
內(nèi)邊距(padding): 內(nèi)容到邊框的間距
外邊距(margin): 邊框到相鄰元素的間距
通過調(diào)整內(nèi)外邊距和邊框,你就可以對(duì)頁(yè)面做一點(diǎn)基本的美化排版了。
4 浮動(dòng)和定位
盒子還只是在在文檔流中按次序流動(dòng)而已, 想要做到漂亮的排版, 還得讓他們靈活地定位才行。
比如說有人想把一個(gè)盒子放到瀏覽器的最右邊,不會(huì)隨著頁(yè)面滾動(dòng)而滾動(dòng);
或者大盒子中套了一個(gè)小盒子,小盒子要相對(duì)于大盒子來定位;
或者兩個(gè)盒子想羅列起來;
或者像報(bào)紙雜志那樣分欄顯示,左邊是菜單,中間是內(nèi)容,再加上一個(gè)右邊欄; 等等諸如此類的要求。
所以,一個(gè)盒子必須得能在常規(guī)的文檔流中重新定位,于是我給盒子添加了兩個(gè)重要的屬性:float和position 。
float可以讓一個(gè)盒子脫離標(biāo)準(zhǔn)的文檔流,一直往上飄,直到遇到父元素的邊界。
當(dāng)有多個(gè)盒子都在飄的時(shí)候,就可以按照次序形成分欄的效果了。
比如下面這3個(gè)<div> 本來是從上往下依次往下流動(dòng)的, 如果給div2, div3加上float:left屬性,他們就橫著排列起來了:
對(duì)于position 來說, 那就更加靈活了。 如果不設(shè)置,那就是默認(rèn)定位,在文檔流中的位置不做改變。
可以設(shè)置為相對(duì)于盒子在原來文檔流中的位置做定位(原來的位置沒有被別的div占據(jù)):
還可以設(shè)置成相對(duì)于某個(gè)父元素做絕對(duì)定位(下圖中祖先元素就是橙色的框,div2原來的位置被div3占據(jù)了) 。
唉,給大家說這么多瑣碎的東西, 我自己都有點(diǎn)煩了, 總結(jié)下就是:我提供了各種各樣的方式讓你的盒子可以靈活的排列起來。
當(dāng)然我必須得承認(rèn), 這些布局對(duì)程序員們確實(shí)不那么友好,你沒有辦法通過拖拽的方式對(duì)這些盒子進(jìn)行排版。
為了減少工作量,大量CSS框架在源源不斷地推出,例如Bootstrap, Semantic UI, Pure.css , EZ-CSS。。。。。。 這是后話了。
5 CSS
浮動(dòng)和定位可以說是我搞出的最復(fù)雜的東西, 其他的像背景了,字體了,文本了就簡(jiǎn)單得多,就不再啰嗦了。
當(dāng)我告訴HTML我的定義工作基本搞定時(shí), 他提出了一個(gè)問題: “你這些選擇器,盒子模型,浮動(dòng)和定位, 背景,字體之類定義,最終要放在哪兒啊? 你不會(huì)還是想放在我這里吧?”
我想了想,必須得有***的靈活度,程序員可以直接寫到元素的標(biāo)簽中(叫行內(nèi)樣式), 也可以寫到html的<style>標(biāo)簽里(這叫嵌入樣式), 當(dāng)然我是建議大家寫到單獨(dú)的CSS樣式中,然后通過鏈接的方式和html內(nèi)容結(jié)合起來。
行內(nèi)樣式長(zhǎng)這個(gè)樣子:
很明顯,這和最早的在html中寫<font>標(biāo)簽差不多。
嵌入樣式就好一點(diǎn):
如果把這些樣式完全從html中分離,放到獨(dú)立的文件中,就可以使用鏈接樣式:
- <link href="mystyle.css" rel="stylesheet" type="text/css" />
正像你猜到的那樣, 嵌入樣式會(huì)覆蓋鏈接樣式, 行內(nèi)的樣式會(huì)覆蓋嵌入樣式。 就像一層蓋著一層那樣, 就是由于這個(gè)原因,W3C把我命名為層疊樣式表(CSS)。
【本文為51CTO專欄作者“劉欣”的原創(chuàng)稿件,轉(zhuǎn)載請(qǐng)通過作者微信公眾號(hào)coderising獲取授權(quán)】