什麼是 CSS?

前言

做爲程序員,技術的落實與鞏固是必要的,所以想到寫個系列,名爲 why what or how 每篇文章試圖解釋清楚一個問題。css

why what or how 的第二章,什麼是 CSShtml

釋義

CSS - Cascading Style Sheets,層疊樣式表程序員

CSS 也算是一種標記語言,其內容做爲瀏覽器的輸入,瀏覽器會解析其文本內容,做爲 HTML 附加的樣式信息,用以修飾標籤。bootstrap

標記語言,一類以固定的形式描述文檔結構或是數據處理細節的語言,通常爲純文本形式,其內容做爲其餘程序的輸入。

樣式表你們都很清楚,記錄樣式信息的表格,以鍵值對的形式存在,格式以下數組

p {
    font-size: 10px;
}

那麼何爲層疊呢?層疊的意義是什麼?瀏覽器

層疊,字面意思:層層疊加,咱們知道 HTML 的頁面結構是樹狀的,不一樣標籤的層級嵌套最終組合造成了頁面,那麼從另外一個角度來看,頁面的結構就是一層一層的,以下圖所示sass

html-tree

html 爲最底層,body 位於 html 層之上,headernavarticleasidefooter 這些標籤位於 body 之上,section 位於 article 之上,標籤的堆疊就造成了網頁結構,那麼這關 CSS 什麼事?less

先拋出一個問題:若是說 article 標籤表明一篇文章,那麼其內部的文字大小,樣式,排版是否是應該一致?ide

是!那麼樣式進行層疊的意義也在於此,只要我給 article 標籤固定的樣式,那麼 article 內部的標籤就會(部分)繼承這個默認的樣式信息,層級結構表明了節點間的關係,那麼就有了父子級的區別,也就有了繼承的關係。佈局

那有的朋友就會問了?如今的 CSS 不就是這樣的嗎?這不是默認的行爲?

CSS 確實如此,但剛開始爲 HTML 進行修飾的樣式規則卻並不是如此,CSS 只是在衆多規則中,最終成爲標準的那一個。

歷史

  1. 1991 - 1993 年,各類瀏覽器相繼出現,但每一個都實現了本身制定樣式規則,網頁呈現由用戶控制,樣式沒有統一的規定。
  2. 1993 年,Mosaic 瀏覽器採用增長新種類的 HTML 標籤實現樣式的表達,以知足設計師的要求,<FONT></FONT> 之類表明樣式的標籤開始出現。
  3. 1994 年,Håkon W Lie 提出層疊 HTML 樣式表(Cascading HTML Style Sheets),CSS 的雛形出現。
  4. 1995 年,W3C 創建,W3CCSS 很感興趣,爲此專門組織了一次討論會。
  5. 1996 年,CSS 語法完成,發佈了 CSS1.0 ,但因爲當時主流的瀏覽器並不支持(每家都有本身的樣式寫法),而且當時主流的方式爲 HTML 的樣式標籤,所以 CSS 等幾年後才流行起來。
  6. 1997 年,W3C 組織了專門管 CSS 的工做組。
  7. 1998 年,瀏覽器市場份額被微軟公司的 IE4 和網景公司的 Netscape Navigator 兩大瀏覽器巨頭所佔據。IE4 率先實現了 CSS 1.0 但因爲不重視,致使規範實現不完善,bug 不少。因爲不一樣瀏覽器支持的標準不一致,網頁設計人員不得不爲 IENetscape Navigator 分別設計一套網頁。民間設計人員團體 網頁標準計劃(WaSP) 發動水軍將 W3C 的建議宣揚爲標準,並批評還未加盟 W3C 標準的業界廠商。
  8. 1998 年,W3C 組織出版 CSS2.0 網頁標準計劃的 7 位成員成立了 CSS武士團(CSS Samurai),指出 Opera 瀏覽器和 IE 瀏覽器在支持 CSS 方面存在的諸多問題。Opera 公司着手解決了問題,但微軟並未解決。他們同時也勸說其餘瀏覽器開始支持 CSS 標準。
  9. 1999 年,W3C 開始制定 CSS3 標準。
  10. 2003 年,Dave Shea 推出了一個名爲 CSS禪意花園("CSS Zen Garden") 的站點,向人們展現出僅經過應用不一樣頁面樣式規則,就能夠實現對網頁藝術風格的面目一新。
  11. 2006 - 2009年, DIV+CSS 佈局逐步取代缺少靈活性的傳統表格佈局,無表格網頁設計成爲網頁內容佈局的主流方案。
  12. 2009 - 至今CSS3 標準已部分公佈,但仍未所有制訂完畢,瀏覽器廠商也逐步跟進,W3C 官方將這些不一樣的特性分門別類,稱爲 modules,不在沿用 CSS3.0 的版本號,而是將單獨的 module 分別命名,每一個 module 也有不一樣的版本號。
  13. ...

CSS 從標準制定,到最終有瀏覽器開始實現,至少間隔了 5 年的時間,而 CSS 的上位也由民間組織推進,到瀏覽器廠商最終採納。直到目前,咱們還能在 HTML 中使用相似 <FONT></FONT> 之類表明樣式的標籤,也是歷史遺留下來的產物,但 HTML5 的推出,規範了 HTML 標籤是做爲網頁的結構,CSS 做爲網頁的樣式信息,所以那些表明樣式的標籤已經被規範所移除,咱們也應該少用甚至不用。

CSS 在衆多的樣式規則中脫穎而出,其實和 IE4 的成功有這很大的關係,IE 系列最早實現了 CSS1.0 標準,能夠說是在與 Netscape Navigator 戰爭中勝利的因素之一,甚至不少的 CSS3 屬性背後也有着 IE 的影子,但後來 IE 系列的落寞很大程度上是由於它的不做爲。

語法 or 結構

一條 CSS 規則的結構以下:

┌─────── 選擇規則 ──────┐   ┌────────── 聲明塊 ──────────┐
p + p > span:first-child    {
                                ┌──────  CSS 屬性 ───────┐
                                font-size   : 10px       ;
                                └─ 屬性名 ─┘ └─ 屬性值 ─┘
                            }

由兩部分組成,選擇器與聲明塊。

  • 選擇規則:用於匹配具體 HTML 中符合要求的標籤
  • 聲明塊:用於設置符合要求標籤的樣式

一條選擇規則有兩部分組成,選擇器與鏈接符,上面例子中,pspan:first-child 屬於選擇器,而 +> 這些符號屬於鏈接符。

一個聲明塊由多條 CSS 屬性組成,屬性分爲兩部分,屬性名與屬性值,以 : 分隔,以 ; 結尾,一條屬性規定了標籤的一個樣式。

選擇規則

選擇規則,意如其名,用於選擇 HTML 文檔中的標籤,那麼如何進行選擇的呢?選擇規則分爲兩部分,咱們分開介紹

  • 選擇器

選擇器用於選擇 HTML 頁面中存在的標籤。選擇器分爲幾大類,以下:

選擇器類型 含義
元素選擇器(elementname 選擇對應標籤
類選擇器(.classname 選取具備對應類名的標籤
ID 選擇器(#idname 選取具備對應 ID 的標籤
通配選擇器(* 選取全部標籤
屬性選擇器([屬性名=值] 選取有相應規則屬性的標籤
僞類選擇器 選取僞類規定的標籤

屬性選擇器有多種寫法,以下:

寫法 含義
[attr] 選取帶 attr 屬性的標籤
[attr=value] 選取 attr 屬性值爲 value 的標籤
[attr~=value] 選取 attr 屬性中有 value 單詞(單詞不與其餘字母相連)存在的標籤
[attr|=value] 選取 attr 屬性爲 value 或以 value- 開頭的標籤
[attr^=value] 選取 attr 屬性以 value 開頭的標籤
[attr$=value] 選取 attr 屬性以 value 結尾的標籤
[attr*=value] 選取 attr 屬性中含有 value 的標籤

注: 屬性選擇器寫法,如 [attr=value] 其後均可以跟 i,好比 [attr=value i] 表明在匹配時,忽略 value 的大小寫。

經常使用僞類,以下

寫法 含義
:active 選中被用戶激活的標籤
:hover 選中被鼠標懸浮的標籤
:visited 選中已訪問過的連接
:focus 選中獲取到焦點的標籤
:first-child 選中一組兄弟標籤中的第一個標籤
:last-child 選中一組兄弟標籤中的最後一個標籤
:first-of-type 選中一組兄弟標籤中其類型的第一個標籤
:last-of-type 選中一組兄弟標籤中其類型的最後一個標籤
:not(X) 選中不被 X 選擇器選中的全部標籤
:nth-child(an+b) a b爲固定值,n 爲任意天然數,選中一組兄弟標籤中第 an+b 個元素
:nth-last-child(an+b) 同上規則,從後往前匹配
:nth-of-type(an+b) 同上規則,從前日後找,匹配相同類型的標籤
:nth-last-of-type(an+b) 同上規則,從後往前匹配
:only-child 若是父標籤中只有一個子元素則選中該子標籤
:only-of-type 若是父標籤中只有一個該類型的子元素則選中該子標籤
  • 鏈接符(符號用引號引發)

鏈接符規定了選擇器該如何進行組合,爲了方便解釋,我會將符號取一個名字,最終的選擇規則表明的含義只需按順序從前日後讀便可。

符號 名字 含義
''(無) 而且 選擇器疊加
',' 或者 選擇器共用
' '(空格) 後代選擇
'>' 內第一級 子元素選擇
'+' 以後的第一個 相鄰兄弟選擇
'~' 以後的全部 兄弟選擇

給幾個例子

  1. p.class1
  2. p,div
  3. p .class1
  4. p > .class1
  5. p + .class1
  6. p ~ .class1

咱們順起來念:

  1. 選中 p 而且帶有 class1 類名的標籤。
  2. 選中 p 標籤或者 div 標籤。
  3. 選中 p 標籤內的帶有 class 類名的標籤。
  4. 選中 p 標籤內第一級帶有 class 類名的標籤。
  5. 選中 p 標籤以後的第一個帶有 class 類名的標籤。
  6. 選中 p 標籤以後的全部帶有 class 類名的標籤。

針對於複雜的選擇規則的編寫,好比在 bootstrap 中有這樣一段:

.btn-group > .btn-group:not(:first-child):not(:last-of-type) > .btn {
  border-radius: 0;
}

表明的意義是什麼呢?

按照順序念:選中帶有 btn-group 類名標籤內第一級帶有 btn-group 類名而且不是第一個子元素而且不是最後一個子元素標籤內第一級帶有 btn 類名的標籤。

對應的 html 以下:

<span class="btn-group">
    <span class="btn">按鈕1</span>
    <span class="btn-group">
        <span class="btn">按鈕2</span>
        <span class="btn">按鈕3</span>
        <span class="btn">按鈕4</span>
    </span>
    <span class="btn">按鈕5</span>
</span>

選中的標籤爲按鈕2/3/4。

咱們從該條規則的意義來理解這條規則:btn-group 中的 btn-group 下的 btn 不該該有圓角(在中間時)。由於正常的按鈕都是帶圓角的,而放在按鈕組中的按鈕其實只要左右兩邊的按鈕帶上圓角就好,這時候就須要經過特殊的手段來吧這些要去除圓角的元素給選擇,並去掉圓角。

接着咱們在看咱們翻譯出來的內容,是否是不那麼繞了呢?

最後在提一段 bootstrap 中的樣式規則,你們一塊兒翻譯翻譯吧

.btn-group > .btn-group:last-of-type:not(:first-child) > .btn:first-child {
  border-bottom-left-radius: 0;
  border-top-left-radius: 0;
}

選擇器的內容到此爲止,接下來就要談談聲明塊中的 CSS 屬性了。

樣式類別(屬性)

CSS 中樣式分不少種,按照樣式效果進行區別,大體能夠分爲以下幾類

大類 做用 表明屬性
字體 控制字體的顯示效果 font-* color text-transform text-decoration text-shadow
文字排版 控制文字的排版 text-align text-align-last text-indent text-overflow line-height word-spacing letter-spacing
背景 控制元素背景顯示 background-*
佈局 控制元素的佈局行爲 flex 系列屬性 grid 系列屬性
文檔流相關 控制元素在文檔流中的位置 position top left bottom right z-index float clear
列表 控制列表的行爲 list-*
盒模型 控制元素大小 width height padding border margin box-sizing
動畫 & 過渡 控制元素動畫 transition-* transform animation-* @keyframes

該篇僅介紹 CSS 是什麼,而不解釋 CSS 有什麼,因此不過於深究這些屬性的具體內容,能夠經過查看 CSS參考來了解。

屬性的繼承

開篇咱們就提到了,CSS 爲層疊樣式表,層疊表明的意思爲屬性的繼承。

這個繼承能夠簡單的總結爲一句話:

父級標籤的字體樣式和文章排版樣式會被子標籤所繼承,也就是說子標籤不用寫這些屬性,就擁有了這些屬性。

幾個特殊值

CSS 中有幾個特殊的屬性值,須要特別關注一下:

  1. unset - 若是該屬性爲繼承屬性則使用繼承值,不是則使用瀏覽器默認值
  2. initial - 使用初始化的值,也就是瀏覽器默認值
  3. inherit - 使用繼承值

權重

因爲相同的標籤能夠由不一樣的選擇規則所選中,那麼這時候就出現了一個狀況,若是有多個選擇規則同時選中了同一個元素,而且同時設置了相同屬性,那麼標籤最終是要按照哪條規則定義的屬性來顯示?

不一樣 CSS 規則對同一個標籤設置了相同屬性, CSS 選擇規則權重最高的規則會覆蓋權重低的樣式設置。

何爲權重,通過上面的介紹,CSS 設置標籤的樣式有以下幾種

  • 直接寫在標籤 style 屬性上
  • ID 選擇器
  • 類名選擇器
  • 僞類
  • 標籤選擇器
  • 通配符

從上到下,選擇器的權重依次遞減,就像是一樣是一張紙幣,100 的紙幣表明的比 10 塊的紙幣大,可是與紙幣不一樣的是,權重高的永遠比權重低的優先級要高,無論低權重的選擇器有幾個。

除去 style 的方式咱們用一個數組來表明選擇規則的權重。

[0, 0, 0, 0, 0]

從左到右爲:ID 選擇器類名選擇器僞類標籤選擇器通配符,數組的初始值全爲 0 ,咱們能夠變看選擇規則來肯定最終數組,好比那個很複雜的 btn 選擇:

.btn-group > .btn-group:not(:first-child):not(:last-of-type) > .btn {
  border-radius: 0;
}

從左到右,每出現一個選擇器,就將對應的數組內的數組加一,那麼上條規則最終的數組以下:

[0, 3, 2, 0, 0]

這時,有的朋友可能會問了,僞類選擇有 4 個啊,怎麼是 2 ?這裏須要注意的是::not 僞類僅帶有取反的意思,並不增長權重。

那麼權重該如何比較?

簡單的來講,從前日後比,誰比誰先大,誰的權重高。相信寫一段比較程序你們就瞭解了:

function compare(weight1, weight2){
    for(let i = 0; i < 5; i++){
        if(weight1[i] !== weight2[i]){
            if(weight1[i] > weight2[i]){
                console.log('參一權重大');
            }else{
                console.log('參二權重大');
            }
            return;
        }
        
    }
}

那麼 style 所規定的樣式權重如何?

style 樣式所規定的權重,比 ID 選擇器 的權重還要高。

那麼咱們想要在 CSS 文件中修改 style 所規定的樣式該怎麼辦?

使用 !important 修飾特定的樣便可。以下所示
p {
    color: red !important;
}

那麼 p 標籤的字體顏色即爲紅色,即便設置了 style 也沒用。

總結一下:權重等級由高到低爲:!important > style > 選擇規則。就像是老大哥說東小弟不敢說西,權重也是絕對服從上一級的。

所以爲了不出現尷尬的情況,請慎重使用 !important

預編譯

CSS 發展到如今,人們發現 CSS 雖然含有層疊的含義,可是寫法倒是一維的,就好比文檔結構以下的一個網頁:

<article>
    <p>這是一段文字</p>
</article>

咱們要在 articlep 標籤上設置樣式,看起來是這樣的:

article {
    font-size: 14px;
}

article p {
    color: red;
}

因爲樣式規則按照一條一條的形式進行編寫,看起開就是一維,標籤的層級結構不能在其中體現,若是這樣寫那就行了:

article {
    font-size: 14px;
    p {
        color: red;
    }
}

從樣式編寫上就說明了層級結構,p 標籤所繼承的樣式明瞭,可是瀏覽器又僅能識別一維的樣式編寫,那該如何讓瀏覽器認識該結構呢?

預編譯器因運而生,經常使用的 css 預編譯器有:sasslessstylus等,這些預編譯器須要特定的語法,但都支持二維的寫法。

那麼這些個預編譯幹了什麼?

很簡單的一句話,將符合預編譯器語法的文件轉化爲 css 文件。

一樣的這些預編譯器的語法,這裏不過多介紹,提供幾個網站供你們查閱:

CSS Modules 的見解

我是在 2019 年寫下這篇文章,爲什麼要特意的聲明時間,是由於一個東西的出現:CSS Modules,咱們須要好好來了解了解。

何爲 CSS Modules ,官方解釋以下:

CSS files in which all class names and animation names are scoped locally by default.

翻譯過來就是:

CSS 的類名和動畫名字都在一個命名空間下。

不懂?寫個例子。

如下爲僞源碼:

// test.css
.box{
    color:red;
}
import style from 'test.css'

function Test(){
    return (<div class={style.box} />)
}

如下爲僞輸出:

<div class="_styles__box_34682763478"></div>

_styles__box_34682763478 就是在加了命名空間後的類名,這樣構建出的代碼就不會出現相同類名被覆蓋的問題。

總的來講, CSS Modules 作了一件時,混淆了 class 類名、 id 和動畫名。

這時就有一些開發站出來講,這個東西好啊,我不再用去想類名該如何取才能不致使衝突了。冷靜下來先考慮這幾個問題:

  1. 雖然不會衝突了,但若是你想覆蓋類名該怎麼辦?
  2. 是否能接受編譯慢的問題?
  3. 樣式名會隨着文件的位置或文件內容改變,是否能接受這種變化?
  4. 頁面上是否須要用到大量 JavaScript DOM API?若是是,那麼經過樣式名選取變的不可靠。
  5. 當使用了 CSS Modules 後項目中是否出現了極多的 :global 若是是,那要仔細思考下,不用 CSS Modules 成本是否更低?

如下是問題對應的一些場景

問題一:你引用了團隊中其餘人寫的組件,但須要你本身修改(覆蓋)一些樣式,而其餘人也是用 CSS Modules 編寫樣式,所以他的類名是不固定的,你該如何去覆蓋這個組件中標籤的樣式?

  • 通知組件編寫者修改樣式?要是通用組件咋辦?
  • 讓他用固定樣式?那用 CSS Modules 的意義在於哪?

問題三四:當你程序須要使用 DOM API 但經過 CSS Modules 生成的樣式名會隨着文件的位置或內容改變,這樣程序就變得不可靠,固然這個問題有辦法解決

  • js 中也用 CSS Modules 的命名,只不過調試變得些許困難
  • js 中使用的樣式名與 CSS Modules 進行區分,jsCSS Modules 使用兩套樣式單獨的樣式

那麼接下來講說個人使用體驗,或者說我以爲好的使用體驗

  1. 項目中 CSS Modules 和原始的 CSS 一同使用。
  2. CSS Modules 僅使用在組件內部,項目中依然使用公共樣式。
  3. CSS Modules 僅使用在一些與結構無關的但又很差命名的標籤上,這些標籤通常也不會被 js 所選擇。
  4. CSS Modules 混淆採用和文件位置相關的命名空間產生方式,而不根據文件內容。
  5. 一旦某個樣式是跨組件通用就不用 CSS Modules ,經過項目規定的命名空間在原始 CSS 文件中定義。
  6. 開發 UI 庫或公共組件,不用 CSS Modules

總的來講就是一個原則,CSS Modules 用在非共用,無所謂命名以及非跨組件通用的標籤上,這些標籤能夠認爲是組件的內部狀態,不會被外部影響或修改。

也不知道多年之後 CSS Modules 是否真的解決了編譯慢的問題(至少個人電腦上是),CSS Modules 原理上還是傳統的 CSS 編寫方式,只不過它混淆了名稱,並添加了映射,可是之後的發展會如何呢?我不知道,但我會持續的關注它。

總結

慣例以問句開篇,用問句來結尾

  1. CSS 的層疊體如今哪?
  2. CSS 選擇規則分爲那兩部分,每部分都如何組成?
  3. 列一列選擇器,並分個類?
  4. 常見屬性都有哪些?
  5. 預編譯器是幹什麼用的?
  6. CSS Modules 是什麼?
  7. 談談對 CSS Modules 的見解吧。

最後,其實本篇還想談談佈局和文檔流的內容,但篇幅過長,也涉及到了 HTML ,因此就打算將佈局單獨出來,之後會有如何進行網頁佈局的單篇,已經記錄,但願你們持續關注。

參考

最後的最後

該系列全部問題由 minimo 提出,愛你喲~~~

相關文章
相關標籤/搜索