最近有時間,想把醞釀的幾篇部落格都寫出來,今天前端國小生帶着10個問題,跟大家分享一下學習CSS的一些體會。
最近有時間,想把醞釀的幾篇部落格都寫出來,今天前端國小生帶着10個問題,跟大家分享一下學習CSS的一些體會,我覺得想學好CSS,必須保持一顆好奇心和刨根問底的勁頭,而不是複制粘貼,得過且過。本人能力有限,這篇文章從構思加完成用了四五天,如果你和我一樣是前端小白,不妨仔細斟酌體會,以期領悟到一些東西;如果你是業界大牛,也請你駐足随意瞄上兩眼,把言辭内容不妥的地方指出來,我們共同讨論。
時刻保持好奇心
第一問:當margin的值為百分比形式時,為什麼浏覽器會根據父容器寬度得出計算值?
在我之前一篇部落格檢驗你的前端基礎——Sit the test中,聊到了margin值為<percentage>時的計算方法。假如有一個父容器寬度400px,高度600px,其子元素設定margin:20% 20%後的計算值應該為“margin:120px 80px”還是“margin:80px 80px”呢?按照那篇部落格中的理論,第二個是正确答案。但是在今天這篇文章中,我給出的答案是第一個肯定錯,第二個也不一定對。一個符合W3C标準的浏覽器會根據父容器的寬度進行計算,但是這個僅限于書寫模式為橫向的時候。因為在橫向排版時,寬度“有迹可循”,可以把浏覽器寬度作為參考,但是高度是不固定的,是以margin百分比值在計算時會參考父容器的寬度。當書寫模式改為縱向,其計算參考便會變為父容器的高度了。戳我檢視DEMO(請在webkit核心或IE下檢視)。
第二問:margin:auto為什麼隻能實作水準居中,不能垂直居中?
當一個正常流中塊級元素的margin屬性左右值設為關鍵字auto,且它擁有固定寬度時,它便會平分剩餘的水準空間,居中顯示。然而如果設定上下值為auto,浏覽器得到的計算值為0,并不起任何的效果。那麼問題來了,為什麼垂直方向的auto不生效?
與上一問類似,這與布局相關。網頁排版時,正常流的塊級元素水準方向總是鋪滿浏覽器視窗,垂直方向各塊級元素按照先後順序從上往下排列,當頁面内容過多時網頁會出現縱向滾動條,是以原理上縱向是可以無限擴充的,計算時找不到一個固定的參考值,是以縱向的auto無法生效。
同樣,margin:auto會受書寫模式的影響。當書寫模式為縱向時,margin:auto垂直方向是可以居中的,水準方向仍然可以居中(僅當父元素為body時,見下方評論)。不信?請自己寫個demo試試吧。其實受到書寫模式影響的屬性除了這些外,還有margin折疊、padding百分比值的計算等。
第三問:可以讓一個position:fixed的元素相對于一個容器定位而非浏覽器視口嗎?
提到position:fixed,很多人都會說這是一個定位屬性,與absolute的差別是它針對浏覽器視口定位。我的部落格導航欄就是利用“position:fixed”屬性,讓其始終保持在視窗的最上方。不過還是不要忘記“世事無絕對”,CSS實作了一個position:fixed的元素相對于一個容器定位,請在FireFox下檢視此DEMO。
當一個元素應用了CSS3的transform屬性後,它的後代元素的fixed都将失效。http://www.w3.org/TR/css3-transforms/#issue-ca2c412c。是以可以利用這個Bug模拟出一個相對于某個包含塊fixed的效果。
關于transform更多的影響可以在張鑫旭的部落格中看到:CSS3 transform對普通元素的N多渲染影響。
第四問:可以用CSS實作面闆的隐藏和顯示嗎?
現在要實作這樣一個功能,通過CSS切換某個面闆的顯示或隐藏。當提到CSS,我們自然而然想到了控制某個單一進制素的樣式,一旦涉及到多個元素互動,我們往往使用JavaScript操作Dom。事實上這個需求不但可以用CSS來實作,甚至實作方式不止一種,請狂戳DEMO:三種CSS方式實作面闆隐藏和顯示。
第一種利用了label和checkbox,使控制方和被控制方不需要有特定的HTML結構關系,但是需要額外的HTML标簽來支援。第二種方式利用了hover和子元素選擇器,第三種方式利用了focus和兄弟元素選擇器,後兩種都受限于特定的HTML結構。三種方法都隻使用CSS實作了面闆的隐藏顯示。
第五問:可以用CSS做出一個圖示嗎?比如一個三角形?一個小房子?
一個标簽,放在HTML中,隻能代表一種語義。然而一個标簽加CSS,則可以創造出無限的可能。請看DEMO:CSS實作三角形,小房子圖案。
利用border互相覆寫呈現出的斜線,可以模拟出多種多樣的幾何狀。在CSS3中,每個元素都有::before和::after兩個僞元素,對同一個标簽,由CSS可以操控的機關由一個變為三個,再加上絕對定位的輔佐,各種各樣的形狀被創造了出來。

你能想象嗎?這些圖示都是用CSS畫出來的。要想了解更多的CSS3圖示,可以通路這個網站:http://www.uiplayground.in/css3-icons/
第六問:我想寫針對IE6,7的hack,該怎麼寫呢?
你可能會這麼回答:使用 “>”,“_”,“*”等各種各樣的符号來寫hack。是的,這樣做沒錯,但是需要記住每個符号分别被哪些浏覽器識别,并且如果寫的太亂将造成代碼 閱讀起來十分困難。學習CSS必須抱有一種質疑精神,有沒有一種hack方法可以不寫這些亂七八糟的符号,并且代碼易維護易讀呢?我們可以看看好搜首頁是怎麼做的:在頁面頂端有這樣一句話:
在頁面的CSS中,會看到這樣的規則:
這樣做的優點就是克服了使用特殊符号hack的那些缺點,缺點是需要寫更多的代碼,使頁面增大。
一個前端er對上面這些問題知道與否,并不影響他是否可以完成一個項目,建設一個網站。但是如果沒有好奇心,不想追究内在原因,僅抱着“我不想知道這麼多東西,反正我會用就行”這樣一種态度,那麼他充其量算是一個“程式員”,而非一位“工程師”。
就是要刨根問底!
第七問:行内級元素可以設定寬高嗎?
不會為自身内容形成新的塊,而讓内容分布在多行中的元素叫做行内級元素。此類元素可以與其它行内級元素在同一行中顯示而不會另起一行,例如span,strong。在面試時,當被問到行内級元素可否設定寬高時,根據我們的經驗往往會回答不能。但是這樣往往着了面試官的道,因為有一些特殊的行内元素,比如img,input,select等等,是可以被設定寬高的。一個<code>内容</code>不受CSS視覺格式化模型控制,CSS渲染模型并不考慮對此内容的渲染,且元素本身一般擁有固有尺寸(寬度,高度,寬高比)的元素,被稱之為置換元素。比如img是一個置換元素,當不對它設定寬高時,它會按照本身的寬高進行顯示。是以這個問題的正确答案應該是置換元素可以,非置換元素不可以。
第八問:CSS規則根據優先級生效,低優先級的規則會被浏覽器忽略還是覆寫?
在我的之前一篇部落格中,提到了浏覽器中CSS優先級的使用規則:多個優先級的樣式都會被渲染,隻不過高優先級會覆寫住低優先級,元素呈現為高優先級的樣式。現在請考慮這樣一個問題,在一個div應用了兩條background-image規則,照之前的理論來看,兩條規則都會渲染,那麼請問浏覽器會請求被覆寫規則的背景圖檔嗎?
真實情況是浏覽器會聰明到隻請求目前應用的背景圖檔。簡單了解的話,浏覽器隻會為生效的CSS規則中的圖檔資源發出http請求。如果深究的話,就必須談談浏覽器的工作原理了。本人目前水準不夠,以下紅色字型為個人了解,請選擇性閱讀。
在現代浏覽器中,一個頁面從請求到呈現,大緻需要經過解析-建構DOM樹-建構呈現樹(架構樹)-布局(重排)-繪制等幾個步驟。一個頁面的展現并不是一蹴而就的,而是分步驟有條不紊的進行。衆所周知的樣式表層疊順序和特異性計算發生在構造呈現樹的過程中,就是為了解決規則不止一個時的問題。以上面提到的背景圖案為例,浏覽器計算完優先級後,隻有後定義的背景圖案規則被建構到呈現樹上。接下來浏覽器會進行重排和繪制,浏覽器在繪制時才會請求背景圖檔規則用到的圖檔檔案。這就是為什麼隻發出一個HTTP請求的原因。
了解浏覽器的工作原理不僅可以認清CSS解析和渲染過程,還可以體會到重排和重繪發生的時機,這對我們寫出高效的CSS規則和JavaScript Dom操作有着非常深刻的指導意義。這個話題太大,目前我的水準也不足以涉獵到此,等學有所成後我會再發一篇文章詳細談談。這裡有一篇經典的文章,感興趣的可以看看:浏覽器的工作原理:新式網絡浏覽器幕後揭秘。如果無法通路,檢視此國内位址:w3ctech:浏覽器的工作原理。
第九問:使用margin可以做出圓角按鈕的原理是什麼?
當不能使用border-radius時,如何制造一個圓角按鈕?現在有一個制造1px圓角的小技巧:button中嵌套span,設定span的margin為:“margin:1px -1px”。戳我檢視DEMO。
知道這個小tip的人不在少數,那麼是什麼原理導緻這種現象呢?學習CSS就需要刨根問底,一張圖可以把這個問題說明白。
圖中紅色框為span标簽,藍色框為a标簽。當設定span的左右margin為-1px時,其便會在左右各突出1px,造成一種1px圓角的視覺效果。同樣的道理,在實作一些古老浏覽器下的圓角與底色漸變的按鈕時,通常也會利用到多層元素層疊制造視覺誤差的原理。
第十問:清除浮動有N種方式,他們間有什麼共同點嗎?
所謂清除浮動,一般是為了解決子元素浮動導緻父容器高度坍塌。目前有多種方式來解決這個問題,最常見的有after僞元素,父元素設定“overflow:hidden”等等,請看DEMO:七種清除浮動的方法。
其實按照原理,這幾種方法可以歸納為兩種:clear:both法和構造BFC法。
方法
分類
浮動末尾添加新标簽,設定樣式為clear:both
clear:both
浮動末尾添加<br />标簽
使用::after僞元素
父元素設定display:table
構造BFC
父元素設定overflow:auto
父元素設定overflow:hidden
讓父元素也浮動
使用“clear:both”來清除浮動自然不必多說,那麼什麼是構造BFC法呢?
Block formatting contexts(BFC),塊級格式化上下文是在CSS2.1中提出的一個概念,在布局中,BFC自成體系,對自己内部的元素負責,不會與浮動元素重疊,相鄰BFC上下margin也不會重疊。是以我們會通過構造一個BFC來防止margin重疊,清除浮動或者實作一個雙欄布局。
那麼如何構造一個BFC呢?1.float設定為非none值;2.overflow設定為非visible;3.display設定為table-cell,table-caption,inline-block;4.position設定為absolute或fixed。這些方法剛好與上面提到構造BFC來清除浮動的方法相呼應。
需要特别注意的是,在IE6,7下沒有BFC這個概念,但是有一個與BFC性質相似的概念:layout。在IE6,7中遇到的很多bug都可以通過讓元素has layout來解決,比如浮動margin雙邊距,躲貓貓,3像素間距等等。
有些元素例如table,input本身就has layout,那麼如何讓一個普通元素has layout呢?包括但不限于以下幾種方法:1.position:absolute;2.float不為none;3.display:inline-block;4.height:除auto外任意值;5.width:除auto外任意值;6.zoom:除normal外任意值;7.overflow非visible(僅限IE7)。
這也是為什麼我們會在IEhack中經常看到“height:1%”、“zoom:1”、“display:inline-block”、“overflow:hidden”這些字眼的主要原因,其實就是為了讓元素has layout嘛!
是以在IE6-7下,清除浮動除了可以使用clear:both外(::after僞元素無法使用),另一種方法就是讓父元素has layout。
關于清除浮動更多的探讨可以在一絲冰涼的部落格中看到:那些年我們一起清除過的浮動。
總結
學習任何一門語言,或者一個事物都不能得過且過,抱着前人播種後人收的思想。縱然站在巨人的肩膀上可以少走很多彎路,但是個人仍然要保持好奇心和刨根問底、質疑的精神。多想一下“為什麼”,少記一些“該這樣做”,這在CSS的學習中尤其重要。
CSS很簡單,她的出現僅僅是為了排版。CSS很複雜,一個簡單的排版往往有N種解決方案。
望諸君共勉。
(完)