上一節《css知多少(3)——樣式來源與層疊規則》介紹了樣式的五種來源,我們們再通過一張圖回顧一下。
對於上面的三層,我們們大概都比較熟悉了。下面的兩層中,使用者自定義樣式一般也就是改一改字號大小和字型樣式,也沒甚好說的。而最有的說的就是瀏覽器的預設樣式。
不同瀏覽器的預設樣式多少有些區別,特別是老版本的瀏覽器之間,現在高階瀏覽器越來越向統一的標準靠攏,對前端程式猿來說是一件好事情。雖然有些許差異,但是絕大部分還是相同的,我先把程式碼貼上出來 ,具體的解讀我們們慢慢道來(只說重點,比較容易的或者不常用的就不說了)。
![](https://i.iter01.com/images/86153736c3d440f2e7d2df2432d97112d2ef05f0cb7522cf2307c3de9447249a.gif)
1 html, address, 2 blockquote, 3 body, dd, div, 4 dl, dt, fieldset, form, 5 frame, frameset, 6 h1, h2, h3, h4, 7 h5, h6, noframes, 8 ol, p, ul,center, 9 dir, hr, menu, pre{ display: block} 10 /* 以上按照block顯示,沒有規定的則按照預設的inline顯示 */ 11 12 li { display: list-item} 13 /* 程式猿常用的display值是:inline/block/inline-block,很少用到 list-item 14 list-item到底是什麼樣的顯示效果,可以通過例子驗證。。。。 15 第一,你可以不用ul-li,而用其他標籤實現list-item的效果 16 第二,要意識到,瀏覽器對待html只是把它當作一個dom樹,至於顯示成什麼效果,是通過瀏覽器預設的css實現的,即樣式全部通過css設計,和html無關 */ 17 18 head { display: none} 19 table { display: table } 20 /* display:table 和 block 最大的區別在於:包裹性。 提到包裹性,就不得不提一下float和absolute*/ 21 22 tr { display: table-row} 23 thead { display: table-header-group} 24 tbody { display: table-row-group} 25 tfoot { display: table-footer-group} 26 col { display: table-column} 27 colgroup { display: table-column-group} 28 td, th { display: table-cell; } 29 /* 與table相關的其他display值,研究的意義不大,但是table-cell值得一說。 30 table-cell是多列布局的最新解決方案,比使用float更加有效(不相容IE6、7) 31 實際上table-cell是要依賴其他table相關的display,但是瀏覽器會為我們做這些工作,不必手動填寫 */ 32 33 caption{ display: table-caption} 34 th { font-weight: bolder; text-align: center} 35 /* 標題預設設定了粗體和文字居中 */ 36 37 caption{ text-align: center} 38 body { margin: 8px; line-height: 1.12} 39 /* 不同瀏覽器的margin不一樣,所以要設定【 *{margin:0} 】 40 line-height:1.12 針對英文沒問題,但是中文看起來很彆扭 41 另外,1.12是一個相對值(即1.12em),與文字有關的距離設定最好用相對值*/ 42 43 h1{ font-size: 2em; margin: .67em 0} 44 h2{ font-size:1.5em; margin: .75em 0} 45 h3{ font-size: 1.17em; margin: .83em 0} 46 h4, p, 47 blockquote, ul, 48 fieldset, form, 49 ol, dl, dir, 50 menu { margin:1.12em 0} 51 /* em是相對單位,1em就是一單位,瀏覽器預設的一單位是16px, 52 可以通過 body{font-size:20px} 來修改一單位的值 53 p的字型大小是1em,h1是2em,h2是1.5em,等等 54 另外,與文字相關的距離值,最好用相對單位,例如 line-height:1.4; margin:.5em等等,這樣做的好處就是當自定義了1em的絕對px時,line-height也會跟著變 */ 55 56 /* 注意,如果我們自己寫css【 * {margin:0} 】,可以把p、h1、h2等標籤的margin覆蓋掉 57 我們都知道,*選擇器的權重是最低的,但是它卻能覆蓋掉標籤選擇器,說明瀏覽器已經在這裡面做了手腳 58 瀏覽器沒有讓預設樣式和使用者自定義樣式“公平競爭”,而是優先使用者自定義樣式 */ 59 60 h5{ font-size: .83em; margin: 1.5em 0} 61 h6{ font-size: .75em; margin: 1.67em 0} 62 h1, h2, h3, h4, 63 h5, h6, b, 64 strong { font-weight: bolder} 65 /* 這裡可以看到哪些標籤文字是加粗的 */ 66 67 blockquote { margin-left: 40px; margin-right: 40px} 68 i, cite, em, 69 var, address { font-style: italic} 70 /* 這裡可以看到哪些標籤是斜體 */ 71 72 pre, tt, code, 73 kbd, samp { font-family: monospace} 74 pre{ white-space: pre} 75 button, textarea, 76 input, object, 77 select { display:inline-block; } 78 /* 不知道inline-block是什麼樣子的?或者不知道inline-block有什麼特性? 79 在這裡看看哪些標籤是inline-block,就知道inline-block的用處了 80 具體inline-block的用途,我們會在後面詳細介紹,此處只是點出來 */ 81 82 big { font-size: 1.17em} 83 small, sub, sup { font-size: .83em} 84 sub{ vertical-align:sub} 85 sup { vertical-align: super} 86 table { border-spacing: 2px; } 87 thead, tbody, 88 tfoot { vertical-align: middle} 89 td, th { vertical-align: inherit } 90 s, strike, del { text-decoration: line-through} 91 hr {border: 1px inset} 92 /* 為什麼<hr/>預設是那麼個難看的樣子,特別是IE下,這就是罪魁禍首 */ 93 94 ol, ul, dir, 95 menu, dd { margin-left: 40px} 96 ol {list-style-type: decimal} 97 /* ul 和 ol 在預設情況下都會有一篇左邊的間距,在這裡可以看到為何會有間距,以及間距的具體大小是多少。 98 */ 99 100 ol ul, ul ol, 101 ul ul, ol ol { margin-top: 0;margin-bottom: 0} 102 u, ins { text-decoration: underline} 103 br:before {content: "A"} 104 /* ????????????? */ 105 :before, :after { white-space: pre-line } 106 /* <br/>為何能實現換行?瀏覽器得到html的br標籤,只會解析成一個dom節點而已, 107 而“換行”這一功能是通過這裡實現的????? */ 108 109 center{text-align: center} 110 abbr, acronym { font-variant: small-caps; letter-spacing: 0.1em} 111 :link, :visited { text-decoration: underline} 112 :focus {outline: thindottedinvert} 113 114 /* Begin bidirectionality settings (do not change) */ 115 BDO[DIR="ltr"] { direction: ltr; unicode-bidi: bidi-override} 116 BDO[DIR="rtl"] { direction: rtl; unicode-bidi: bidi-override} 117 118 *[DIR="ltr"] { direction: ltr; unicode-bidi: embed} 119 *[DIR="rtl"] { direction:rtl; unicode-bidi: embed} 120 /* 這些標籤或屬性都不常用 */ 121 122 @media print{ 123 h1{ page-break-before:always} 124 h1, h2, h3, 125 h4, h5, h6{ page-break-after: avoid} 126 ul, ol, dl { page-break-before: avoid} 127 /* 對於列印頁面時的設定,不常用 */ 128 129 /* 以下都是按照標籤選擇器來的,標籤選擇器比類、id選擇器的權重都低。 130 所以,使用者自定義的樣式,無論是用標籤、類還是id,都能覆蓋預設的標籤選擇器 */
1.理念上的轉變
在解讀程式碼之前,我先把我看瀏覽器預設樣式最大的體會給大家說一下,這個是非常重要的。就是要先從理念上重新認識html和css。
以前我都是認為瀏覽器自身本來就認識各種html標籤,並且會根據規則設定標籤的樣子,例如p是block顯示,ul有margin-left,h1粗體顯示……以前以為這些標籤預設的顯示方式和css無關,是瀏覽器自己乾的,css設定網頁樣式是載入之後又渲染的。
現在知道這種想法是錯誤的。其實瀏覽器載入了html之後只為一件東西——dom樹,瀏覽器把html變為dom樹結構,就完成了對html的結構化。至於後來對檢視的渲染,p是block、br換行,那是整合了css之後的事情。而瀏覽器整合css又是另一個路線,和解析html是分開的。這裡的“css”就包含了瀏覽器預設樣式。
可以結合下圖理解(第二節的圖):
一句話,瀏覽器將載入的html變為dom樹,但是此時沒有任何顯示樣式。所以顯示的樣式,都是css定義的,瀏覽器只會通過css來渲染檢視樣式。
——多好的設計:指責單一,開放封閉!
2.block元素
為何預設情況下p、h1、ul、div都是block顯示,就是這裡定義的。所以,不要再說div天生就是block——這句話應該換成:瀏覽器預設樣式天生規定了div是block——所以才導致了div是block!是預設樣式規定的,不是瀏覽器的核心規定的。
沒有設定block的元素,預設為inline顯示。
3. display: list-item
我們在使用display時,常用的值一般是:inline/block/inline-block,用不到list-item。那這裡的list-item到底有什麼作用?我們不妨親自試一試:
看到沒有,出現了ul-li中的效果了吧,如果再加一個margin-left是不是就跟ul-li一樣了?
所以,ul-li為什麼會預設顯示成那種樣子?——list-item才是“罪魁禍首”。
4. diplay:table
先給出一個快速思考題:<table>和<div>在容器尺寸上最大區別是什麼(只是容器尺寸,不考慮內容區別)?請在兩秒鐘內說出答案。
答案是——div寬度和父容器相同,table寬度根據內容而定——即table具有“包裹性”。
舉一個例子:
上圖中,第一個div預設是block,寬度撐滿整個頁面。第二個div設定了display:table,寬度根據內容而定。這就是“包裹性”。而提到“包裹性”,又不得不讓我想到float和absolute。具體怎樣這裡無法細說,後面的文章會詳細講到,有興趣的可以先查著。
各位思考一下,你們做的專案中,哪些地方想要這種“包裹性”,而不是寫死寬度或者用js計算寬度?如果想不到,我給大家截個圖提醒一下。如下圖:
5. display: table-cell
上面的截圖中,我們看到了眼花繚亂的好多display,而且都是和table相關的。從字面意思上我們能看出,這是瀏覽器為了渲染一個完整的表格,而需要的許多顯示方式(PS:看似一個簡單的表格,渲染規則就這麼多,這就提醒我們思考問題的嚴謹性和邏輯性)。
這裡的大部分都是我們一直都不會用到的,用不到的瞭解即可,沒必要深究。但是這個table-cell我們卻能用得到,而且是用它來幹一件很重要的事情——多列布局。
多列布局在css中有多重要就不用我說了吧,傳統模式下大家都使用float來解決這一問題,但是float寫出來的東西程式碼複雜,寬度調整不靈活,瀏覽器相容性有問題。所以才有了新方案——table-cell,注意,IE6、7不行!
簡單舉個例子:
記得我剛學html時候,不會用div + css做多列布局,我就用table做多列布局。而今,你可以用table-cell,像用table一樣做多列布局,做出來的效果和table做出來的效果是一模一樣的。
6. body樣式
在body中,定義了兩個樣式,如上圖。
第一,在預設情況下,頁面中的文字不會直接頂到瀏覽器的邊框,這就是因為預設樣式為body設定了margin的緣故。這裡需要注意個問題,不同瀏覽器為body設定的margin值可能不一樣,因此大家都知道在css中用 *{margin:0} 來解決這一相容性問題。
之前已經提到過,*選擇器的級別要低於body標籤選擇器,但是*{margin:0}依然有效的原因,就是瀏覽器偷偷的做了優先順序的手腳。如果在正常情況下,*選擇器在遇到標籤選擇器時,是不會起作用的,及時它是“後載入”的。例如:
第二,瀏覽器預設樣式還為body設定了line-height,line-height這個值1.12是對英文比較友好,中文狀態下就顯得有點擁擠。Line-height是具有繼承性的,在body中設定了,body下面所有的文字都會繼承生效。
另外注意,這裡的line-height: 1.12是一個相對值,即是文字高度的1.12倍。看到這裡,我們在寫line-height的時候,也一定要注意使用相對值,不要使用絕對值。如下:
上圖是編寫line-height的三種形式,大家覺得哪種形式最好?區別是什麼?
- 情況1:永遠按照文字的1.4倍計算,不管文字的高度如何,可適應任何變化;
- 情況2:永遠按照1.4em計算,隨著em的值改變,不管文字高度如何(此時文字高度可能已經通過絕對的px值該表了大小,而不是隨em改變的);
- 情況3:就是25px,絕對的。
相信看到這裡大家會發現,通過一個line-height我能能窺探到的道道有很多。如果大家看懂了這三種情況,從軟體設計和系統擴充套件的角度說,當然我們都會選擇第一種。
7. em和px
大家在設定文字高度或者與文字有關的距離,如p的margin、line-heigt(上文剛講完,不再贅述),會用em還是用px?——反正我之前不熟悉css時候,都是用px。因為px是固定大小,一目瞭然。——當然,它也不利於擴充套件。
因此,我們推薦大家用em。而且瀏覽器的預設樣式也建議我們這樣書寫:
如上圖,它設定了h1字型大小2em、縱向margin是0.67em,h2字型大小1.5em、縱向大小0.75em……p的縱向margin是1.12em,字型大小1em(上圖中沒有,但在整個檔案中有)
em是什麼?——em是一個瀏覽器識別的長度單位,但是它不是絕對的、固定的,而是相對的。大家都知道px是一個絕對的長度單位制,它永遠不會改變。瀏覽器預設情況下令1em === 16px。現在你知道為何p預設是16px了吧。而且你還知道了h1是p高度的兩倍,h2是p高度的1.5倍……(你知道的越來越多了。。。)
當然,我們可以通過css修改1em的值。
由於font-size和margin都是通過em來定義的,當em被修改時,不管字型大小修改,margin值也會跟著修改。這就是em好用之處!
從現在開始,與字型大小有關的css,全部都用em!
8. 粗體和斜體
上圖中,標註了在整個html中,哪些元素設定了粗體/斜體。重點還是一個思維轉換的問題:h1不是天生的粗體,而是設定了font-weight:bolder的樣式而已……
這裡需要提一句題外話:<b>和<strong>有啥區別?<i>和<em>有啥區別?——不知道的話自己去查查吧,看到許多面試題考這個。
9. inline-block
我相信最初學習使用inline-block的朋友都有一個困惑:inline-block到底是個啥?這時候如果你非常勤奮好學的話,你就去網上查資料,然後做各種實驗。——精神可嘉,行為不可取。
學習還是有捷徑的。看看瀏覽器預設樣式告訴你的捷徑:button、input就是inline-block!這樣以點播你就會一下子明白,最起碼能給你一個很好的形象的概念。看看button和input的表現,你就知道inline-block是什麼樣子了:
能被父容器居中、能設定高度寬度和margin、不會像table或div那樣佔一正行……——這就是inline-block——記得這是瀏覽器預設樣式告訴你的。
10. <br>樣式的疑問??
這裡我提出自己的一個疑問。如上圖,瀏覽器預設樣式中,對br是這樣設定的。
- 這裡的br:before{content:”A”},” A”並沒有顯示出來啊?
- <br>的換行到底是誰導致的,是css還是瀏覽器?
希望知道答案的朋友,不吝賜教,給我和大家分享一下,謝謝了。
11. 總結
大家看著是不是很過癮?反正我寫著是挺過癮的,雖然打字、寫程式碼、畫圖很累,不過很有成就感——再有你們的鼓勵就更好啦!
首先,我覺得瀏覽器預設樣式非常重要,所有詳細解讀其中的重點,希望能給大家帶來一些啟發。沒有解讀到的就是一些比較容易理解的,或者不常用的(例如列印的樣式設定),可以直接去看看原始碼。
其次,這裡面也包含了我的一個疑問,很慚愧沒有看明白。即便是一時半會兒解決不了,給別人分享一下,讓你知道了一個疑問,對你來說,應該也是一個收穫。
---------------------------------------------------------------
本系列的目錄頁面:http://www.cnblogs.com/wangfupeng1988/p/4325007.html
-------------------------------------------------------------------------------------------------------------
學習作者教程:《前端JS高階面試》《前端JS基礎面試題》《React.js模擬大眾點評webapp》《zepto設計與原始碼分析》《json2.js原始碼解讀》
也歡迎關注我的開源專案——wangEditor,簡潔易用的web富文字編輯器
-------------------------------------------------------------------------------------------------------------