你可能不知道的 CSS —— CSS規範閱讀分享

本文基於 CSS 2.1 規範中文版整理。css

使用瀏覽器 Chrome 70 進行測試。html

前言

也許有人會說,都快 2019 年了怎麼還讀 CSS2.1 規範。一方面,如今最新的 CSS (core) 規範是 CSS2.2(如下截圖來自 www.w3.org/TR/CSS/ ),又由於 CSS2.1 有中文的版本,而且和 CSS2.2 規範差別性不是很大,基於偷懶的目的最終選擇閱讀了 CSS2.1 規範。 前端

img

記得面試的時候,面試官說 「你的 JavaScript 掌握得比大多數人好不少,但你的 CSS 還須要再增強」。今年六月畢業後,我正式成爲一名前端工程師,閱讀 CSS 規範也所以進入本身今年的 TODO list 中。面試

先後花了兩個月的零散時間,在上週我終於完成了閱讀,對 CSS 的理解也稍微更系統全面了一些。在本身閱讀的過程當中,有些感受是你們日常容易忽視,但有可能用到或是自己比較有趣的小知識點,便以此爲主題,在此基礎上適當擴展,整理了一篇文章和你們分享。算法

只要一杯咖啡的時間,一塊兒來回顧一下規範裏那些可能不太能引發你注意的地方吧。瀏覽器

閱讀愉快,請多指教。bash

關鍵字、屬性和標識符

以 - 或 _ 開頭的關鍵字和屬性名是爲特定供應商擴展保留的。markdown

CSS 中標識符只能包含字符 [a-zA-Z0-9]、ISO10646 字符中 U+00A0 及以後的字符,以及 - 和 _,不能以 1 個數字、2 個連字符、或者後面跟着數字的連字符開頭。前端工程師

這也意味着,選擇器能夠是中文的(雖然並不推薦)。ide

<style>
.中文 {
    color: red;
}
</style>
....
<p class="中文">這是一段中文選擇器文本。</p>
複製代碼

此時,<p> 標籤內的文字將變爲紅色。

@import

用戶代理必須忽略全部出如今塊內部,或者在除 @charset@import 規則外任何沒法忽略的語句後面的 @import 規則。

這也意味着,@import 規則必須先於除@charset 和其它的 @import 規則外的全部規則。

@import "subs.css"
h1 { color: blue; }
@import "list.css"
複製代碼

上述代碼中,第二個 @import 語句是非法的,解析器將會忽略這條規則。

另外,@import 規則能夠加上媒體查詢類型,表示只在知足某個媒體類型時引入樣式表。

@import "landscape.css" screen and (orientation:landscape)
複製代碼

編碼和 @charset

當一個樣式表被嵌進其它文檔時,好比 HTML 中的 style 元素或者 style 屬性,樣式表會共享整篇文檔的字符編碼。

若是一個樣式表處於一個獨立文件中,則按下列順序(從最高優先級到最低)肯定樣式表的字符編碼:

  1. HTTP 協議中 Content-type 字段的 charest 參數
  2. 文件的 BOM 編碼或 @charset
  3. <link charset=""> 或者來自連接機制的其它元數據
  4. 要引入的樣式表或者文檔的字符集
  5. 假定爲 UTF-8

使用 @charset 規則的編寫者必須把該規則放在樣式表的開頭,前面不容許有任何字符。用戶代理必須忽略任何不在樣式表開頭的 @charset 規則。

:first-letter 僞元素

:first-letter 僞元素選擇一個塊的第一行(第一個格式化行塊)的第一個字母(或數字),若是這一行中在它前面沒有跟着任何其它內容(例如圖片或者 inline table)的話。表格單元或者inline-block 元素的首字母不能做爲其祖先元素的首字母。

<style>
.description:first-letter {
    color: white;
}
</style>

<p class="description">「some text」</p>
<p class="description">some text</p>
<p class="description"><img src="" />some text</p>
複製代碼

實際效果如圖:

img

:before 與 :after 僞元素

:before:after 僞元素會從文檔樹中它們附着的元素上繼承全部可繼承的屬性。對於不可繼承的元素,將取其初始值。

用法示例:

p { color: red; display: block; }
p:before { content: 'T'; }
複製代碼

如上例,此時,:before 僞元素將呈現紅色。由於 display 屬性不可繼承,將取其初始值 inline

擴展:僞元素的單冒號和雙冒號

CSS3 選擇器草案中區分了僞元素和僞類(CSS-Selectors Level 4),僞類仍以一個引號開頭,僞元素則以兩個引號開頭。對於 CSS1 和 CSS2 中存在的 :before:after:first-line:first-letter 僞元素,用戶代理必須同時支持它們單引號和雙引號的形式,對於其它新引入的僞類,用戶代理將不支持其單引號的形式。

選擇器與層疊

選擇器中,文檔語言元素名的大小寫敏感性取決於文檔語言,例如在 HTML 中元素名是大小寫不敏感的,而在 XML 中元素名是大小寫敏感的。

層疊順序

樣式表可能有 3 種不一樣的來源:編寫者、用戶和用戶代理(如瀏覽器)。

爲了找出一個元素或屬性組合的值,用戶代理必須按照下列(步驟)排序:

  1. 找出目標媒體類型下,全部適用於該元素和目標屬性的聲明
  2. 根據重要性(@important)規則和來源排序,優先級從低到高爲:
    • 用戶代理聲明
    • 用戶常規聲明
    • 編寫者常規聲明
    • 編寫者重要聲明
    • 用戶重要聲明
  3. 相同重要性和來源的規則根據選擇器的特殊性(specificity)排序,更特殊的選擇器將重寫通常的。僞元素和僞類被分別算做常規元素和類
  4. 最後,根據指定順序排序:若是兩個聲明的權重,來源和特殊性都相同,後製定的生效。@import 引入的樣式表中的聲明被認爲在樣式表自身的全部聲明以前

計算選擇器的特殊性(specificity)

一個選擇器的特殊性(a-b-c-d)根據下列規則計算(a到d權重依次遞減):

  • 若是聲明來自一個 style 屬性而不是一條選擇器樣式規則,算1,不然就是0(=a)
  • 計算選擇器中 ID 屬性的數量(=b)
  • 計算選擇器中其它屬性和僞類的數量(=c)
  • 計算選擇器中元素名和僞元素的數量(=d)
* {} /*a=0, b=0, c=0, d=0*/
li {} /*a=0, b=0, c=0, d=1*/
.description {} /*a=0, b=0, c=1, d=0*/
*[rel=up] {} /*a=0, b=0, c=1, d=0*/
#element {} /*a=0, b=1, c=0, d=0*/
style="" /*a=1, b=0, c=0, d=0*/
複製代碼

也就是說,儘管 #p123[id=p123] 選中的對象相同,但ID 選擇器比屬性選擇器擁有更高的特殊性。

補充

以前看過一些博客,在提到層疊的特殊性的時候,用 1000, 100, 10, 1 的權重去描述上述的 a-b-c-d 的計算方式。實際上這並不許確。咱們能夠經過簡單的實驗推翻上述的說法。

以下例,咱們定義了類名爲 zerodiv,裏面嵌套了十層 div,最內的一層指定了 id 爲last。若是按照10倍遞增的算法,嵌套十一層的 class 的特殊性爲 110,使用一個 id 的特殊性爲 100,背景呈現黑色。若是按照 a-b-c-d 的算法,使用前者的特殊性爲 0-0-11-0,後者特殊性爲 0-1-0-0,背景將呈現紅色。

經過觀察連用十一個 class 和一個 id 的表現,便可得出結論。

<style> #last { background: red; } .zero .one .two .three .four .five .six .seven .eight .nine .ten { background: black; height: 100px; width: 100%; } </style>
<div class="zero">
    <div class="one">
        <div class="two">
            <div class="three">
                <div class="four">
                    <div class="five">
                        <div class="six">
                            <div class="seven">
                                <div class="eight">
                                    <div class="nine">
                                        <div class="ten" id="last"></div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
複製代碼

如圖所示,背景呈現紅色,因此 1000, 100, 10, 1 的計算方式是不許確的。

img

不過,因爲實現上的問題,可能會存在有限多個 class 優先級比一個 id 高的狀況。張鑫旭在12年分享過一篇《有趣:256個class選擇器能夠幹掉1個id選擇器》。主要是由於寫這篇文章的時候有些瀏覽器使用了8位計數器對 class 的數量進行計算,當 class 達到256個時因爲發生進位將會出現權重比 id 高的狀況。以後的瀏覽器使用了更高位數的計數器,理論上仍可能存在邊界值,但將很難達到。

content 中的 attr 屬性

content: attr(X)
複製代碼

attr(X)函數返回一個字符串,字符串的值爲該選擇器選中對象的 X 屬性的值。若是該對象沒有 X 屬性,則返回一個空字符串。

用法示例:

p:after { content: ", " attr(data-name); }
複製代碼
<p data-name="Thorn">Hello</p>
複製代碼

此時將會渲染出 「Helo, Thorn」。

計數器

計數器使用大小寫敏感的標識符。自動編號經過 counter-incrementcounter-reset 屬性控制。

若是給同一個計數器指定了屢次 counter-reset 或者 counter-increment 的值,計數器的每次重置或遞增會按指定的順序處理。

/* 第二個 section 省略了重置的值,會被置默認值 0, section 將先重置爲 2,最終重置爲 0 */
h1 { counter-reset: section 2 section; }

/* 第一個 section 省略了遞增的值,會被置默認值 1, section 先遞增 1, 再遞增 2, 至關於遞增 3*/
h1 { counter-increment: section section 2; }
複製代碼

另外,counter-reset 屬性遵循層疊原則,若是要同時重置兩個計數器,它們必須同時指定。

h1 { counter-reset: section 0 image 0; }

/* 下面的寫法會發生層疊致使只有一個計數器生效 */
h1 { counter-reset: section 0; }
h1 { counter-reset: image 0; }
複製代碼

嵌套計數器與做用域

計數器是自嵌套的,若是重置一個位於後代元素或僞元素的中的計數器,則會自動建立一個新的計數器實例。計數器的做用域從文檔中具備 「counter-reset + 該計數器」 的第一個元素開始,包括該元素的後代和後續兄弟及其後代,但不包括處於同名計數器做用域中的任何元素。

<style>
ol {
    counter-reset: section;
    list-style-type: none;
}
li:before {
    counter-increment: section;
    content: "第" counters(section, ".") "章";
}
</style>
<ol>
    <li>item</li>   <!--第1章-->
    <li>            <!--第2章-->
        <ol>
            <li>item</li> <!--第2.1章-->
        </ol>
    </li>
    <li>item</li>   <!--第3章-->
</ol>
複製代碼

效果如圖所示

img

display:none 的元素中的計數器

一個 display 值設置爲 none 的元素不會讓計數器遞增或重置,沒法生成的僞元素也不會讓計數器遞增或重置,然而 visibility 被設置 hidden 的元素會讓計數器遞增或重置。

列表

一個具備display: list-item 的元素會爲該元素的內容生成一個主塊盒,還可能生成一個標記盒做爲可視化指示,說明該元素是一個列表項。

background 屬性只適用於主盒,外部的標記盒是透明的。(不過,若是將 list-style-position 的值設置爲 inside 的話,因爲標記盒的背景是透明的,主盒設置的背景將會透過來,視覺上也至關於同時給主盒和標記盒加上了背景)。

背景

根據盒模型,背景指的是內容,內邊距和邊框區的背景。邊框顏色和樣式能夠經過邊框屬性來設置,而外邊距老是透明的。

<style>
.transparent-border {
    border: 10px solid rgba(0, 0, 0, 0);
    color: white;
    background: blue;
}
</style>

<p class="transparent-border">將 border 的顏色設置爲透明時,背景的顏色將透過來。</p>
複製代碼

img

背景屬性是不可繼承的,但由於 background-color 的初始值爲 transparent,父級盒的背景將透過來。

另外,當同時設置 background-image 屬性和 background-color 屬性時,若是圖像可用則將被渲染在背景色之上。這也意味着,在圖像的透明部分,背景色是可見的。

輪廓(outline

outlineborder 的區別:

  • outline 不佔空間,顯示或隱藏不會致使重排或者溢出
  • outline 能夠不是矩形的
  • 全部方向的 outline 都相同,與 border 相比,不存在 outline-topoutline-left 屬性
  • 若是元素被拆分紅了多行,與 border 相比,outline 在行框的開始或者結束出不是斷開的,而是總會盡可能徹底鏈接起來(效果以下圖)
  • 由於 outline 不影響格式化,它可能會與頁面上的其餘元素重疊

img

outline-widthbackground-width 接受相同的值(hidden 除外)。

outline-stylebackground-style 接受相同的值(hidden 除外)。

outline-colorbackground-color 接受相同的值。此外 outline-color 還能夠設置爲 invert,用來對屏幕的像素取反色(但不是全部瀏覽器都支持該屬性)。

默認樣式

在不指定字體大小的狀況下,標題字號略粗於常規字體,h4 的字體大小和常規字體大小相同,h5h6 字體略小於常規字體。

h1, h2, h3, h4, h5, h6 { font-weight: bolder; }
h1 { font-size: 2em; margin: .67em 0; }
h2 { font-size: 1.5 em; margin: .75em 0; }
h3 { font-size: 1.17em; margin: .83em 0; }
h4 { margin: 1.12em 0; }
h5 { font-size: .83em; margin:1.5em 0; }
h6 { font-size: .75em; margin: 1.67em 0; }
複製代碼

image
相關文章
相關標籤/搜索