前端入門3-CSS基礎

請叫我大蘇發表於2018-10-30

本篇文章已授權微信公眾號 dasu_Android(大蘇)獨家釋出

宣告

本系列文章內容全部梳理自以下四個來源:

作為一個前端小白,入門跟著這四個來源學習,感謝作者的分享,在其基礎上,通過自己的理解,梳理出的知識點,或許有遺漏,或許有些理解是錯誤的,如有發現,歡迎指點下。

正文-CSS基礎

1.結構和語法

首先需要清楚,CSS 職責是控制 HTEM 文件裡的文字內容在網頁上樣式呈現的效果,寫的每一個樣式最終是通過選擇器作用到具體的元素上面。

工作原理

css工作原理

網際網路其實都是通過網頁相互連線組成的,每個網頁都是一份 HTML 文件,因此瀏覽器與後端的首次通訊是以 HTML 文件為基準,那麼整個流程的第一步也就是解析 HTML 文件。

如果在解析 HTML 文件過程中發現有通過 <link> 標籤引用了外部的 CSS 檔案時,那麼瀏覽器會去下載相對應的 CSS 檔案。

當 HTML 文件解析完畢後會生成一個 DOM 文件結構,DOM 文件結構中記錄著每個節點的元素,各元素之間的關係,有點類似於 Android 中的 View 樹。

最後,通過 CSS 的選擇器將相對應的樣式作用到 DOM 中選擇器找到的元素節點,然後瀏覽器渲染呈現在網頁上。

結構

css結構

以上是一個 CSS 的典型結構,總共由兩部分組成:選擇器 + 樣式

{} 大括號內部的都是具體的某種樣式,可用來控制元素的背景、大小、排版位置等樣式效果。而 {} 左邊的則是選擇器,用來指定說後面跟隨的樣式列表要作用到 HTML 文件中的哪個元素上。

選擇器型別很多,規則也很多,因此會有一種現象,就是某個元素被不止一個選擇器匹配到,如果某個樣式屬性起衝突了,那麼就會按照一定的優先順序順序處理。

樣式屬性也很多,具體也後面介紹,但有一點需要先明確一下,如果使用了未知的樣式屬性,或者給某個樣式屬性賦予了無效值,那麼該樣式屬性會被視為無效,瀏覽器的 CSS 引擎會完全忽略它。

盒模型

css盒模型

跟 Android 很類似,每個元素在頁面上都是佔據一個矩形區域,也分 margin 和 padding,唯一不同的就是這裡的模型多了個 border,雖然在 Android 中也有 border 的概念,但它是在 padding 區域內的,不單獨佔據某塊區域,所以這裡需要區分一下。

因此,一個元素在頁面上的寬高就是由四個部分共同影響的了:content 區域,padding 區域,border 區域,margin 區域。

需要注意的是,上圖中的盒子模式的 box-sizing 屬性為預設值 content-box 模式。

這種模式下,width 和 height 指的只是content區域的寬高。

box-sizing 屬性的取值有:content-box, padding-box, border-box, margin-box。四種,對應的就是指明 width 和 height 表示的是包含哪些區域的寬高。

使用方式

CSS 基本結構是由選擇器和樣式屬性列表組成,那麼如何跟 HTML 文件關聯起來使用呢?一共有三種方式:

  • 內嵌樣式

使用 HTML 元素的全域性屬性 style 宣告,僅影響一個元素,除非工作環境受限,比如只允許編輯 HTML 的 body,否則強烈不推薦這種方式。

示例:

<a href="index.html" style="background: gray; color: #6a90d9">點選跳轉</a>
  • 內部樣式表

在 HTML 中的 <head> 內使用 <style> 標籤,在某些情況下很有用,比如當你不能直接修改 CSS 檔案時。

示例:

<style type="text/css">
    a {
        background: gray;
        color: #6a90d9;
    }
</style>
  • 外部樣式表

將 CSS 儲存在一個獨立的副檔名為 .css 的檔案中,並在 HTML 的 <head> 裡使用  <link> 元素中引用它,這種方法可以說是最好的,因為你可以使用一個樣式表來設定多個文件的樣式,並且需要更新 CSS 的時候只要在一個地方更新。

<link type="text/css" rel="stylesheet" href="css/nms.css">

2.選擇器

選擇器,顧名思義,就是將 css 程式碼選擇到 HTML 文件中具體的元素物件,並作用在它身上。

基本選擇器

基本選擇器其實是一些比較常用、簡單的選擇器,包括:元素選擇器、id 選擇器、class 選擇器、屬性選擇器、組合選擇器。這些在第一篇前端入門1-基礎概念中已經介紹過了,這裡不就詳細說了。

基本選擇器規則很簡單,選擇器基本就是一兩個條件,滿足了即可匹配上,如 a.class,p#id 等,即使有稍微經過組合,但仍舊不復雜,但有些應用場景下需要通過複雜的規則,即需要滿足多個條件下才能匹配上。

屬性選擇器

在第一篇中介紹的屬性選擇器其實是最基本用法的一種,而它還支援其他很多規則的用法,如下:

[attr] 選擇定義attr屬性的元素,不管屬性的取值具體是什麼
[attr=”val”] 選擇定義attr屬性,且屬性值為val的元素
[attr^=”val”] 選擇定義attr屬性,且屬性值以字串val打頭的元素
[attr$=”val”] 選擇定義attr屬性,且屬性值以字串val結尾的元素
[attr*=”val”] 選擇定義attr屬性,且屬性值包含字串val的元素
[attr~=”val”] 選擇定義attr屬性,且屬性值具有多個值,其中一個為字串val的元素。
[attr|=”val”] 選擇定義attr屬性,且屬性值為連字元(-)分割的多個值,其中第一個為字串val的元素。

也就是說,屬性選擇器不僅可以用來匹配那些具有指定屬性的元素,還可以進一步根據不同屬性值來匹配。

並集選擇器

結構:<選擇器>, <選擇器>

並集選擇器是通過 逗號將不同選擇器組合使用的一種選擇器,這種情況下,各個選擇器之間是沒有任何關係,都是相互獨立的,就是他們具有相同的樣式屬性表而已。

這只是一種簡便寫法的用法而已,具有相同樣式屬性表的不同再複製貼上,可以直接通過 ,逗號將不同選擇器分開即可。只有 HTML 文件中的元素滿足其中一個選擇器即可。

示例:

a, h1, span, div {
    background-color: black;
}

上述示例中有四個選擇器含有同樣的樣式屬性,HTML 文件中只要滿足其中一個選擇器即可被匹配到。

後代選擇器

結構:<第一個選擇器> <第二個選擇器>

多個選擇器之間通過空格分隔開的話表示這是一個後代選擇器,也就是說,需要先滿足第一個選擇器的前提下,在第一個選擇器匹配到的元素的後代元素中去匹配第二個選擇器。

這裡的後代包括了子孫後代。

示例:

p span {
    background-color: black;
}

<span>第一個span</span>
<p>第二個<span>span</span></p>

以上示例中,選擇器要匹配的元素是位於 p 元素的後代元素中的 span 元素,因此第一個 span 元素就不符合規則,而第二個 span 則會被匹配到。

兒子選擇器

結構:<第一個選擇器> > <第二個選擇器>

兒子選擇器是多個選擇器之間通過 > 右箭頭符號連線,表示的是在滿足第一個選擇器的前提下,從它匹配到的元素的直接子元素中尋找第二個選擇器。

跟後代選擇器的區別就在於它只能在直接子元素中匹配第二個選擇器。

示例:

p > span {
    background-color: black;
}

<span>第一個span</span>
<p>第二個<span>span</span></p>
<p><div>第三個<span>span</span></div></p>

第一個 span 元素不是 p 元素的後代,第二個 span 元素是 p 元素的直接子元素,第三個 span 元素是 p 元素的孫子元素,因此只有第二個 span 元素滿足規則被匹配到。

兄弟選擇器

結構:<第一個選擇器> + <第二個選擇器>

兄弟選擇器是多個選擇器之間通過 + 加號連線。表示的是,在滿足第一個選擇器的前提下,從它匹配到的元素的緊跟著的位於同一層級的下一個元素,看該元素是否符合第二個選擇器。

也就是說,兄弟選擇器,兩個選擇器所匹配的元素要求,位於同一層級,且相鄰。

示例:

p + a {
    background-color: #6a90d9;
}

<a>第一個a</a>
<p>第二個<a>a</a></p>
<a>第三個a</a>
<a>第四個a</a>

上述示例中,同時滿足位於同一層級,且相鄰,且需要先滿足第一個選擇器的前提下,還滿足第二個選擇器這四個條件的 a 元素就是第三個 a 元素了。

普通兄弟選擇器

結構:<第一個選擇器> ~ <第二個選擇器>

普通兄弟選擇器,是多個選擇器之間通過 ~ 波浪符號連線。表示的是滿足第一個選擇器的前提下,從它匹配到的元素後,去尋找位於同一層級,且在該元素後面的所有滿足第二個選擇器的元素。

兄弟選擇器只匹配相鄰的一個元素,而普通兄弟選擇器則是可以匹配位於元素後面的所有符合第二個選擇器的元素。

示例:

p ~ a {
    background-color: #6a90d9;
}

<a>第一個a</a>
<p>第二個<a>a</a></p>
<a>第三個a</a>
<a>第四個a</a>

同時滿足同層級,且在 p 元素後面的兄弟元素有兩個,第三個 a 元素和第四個 a 元素,因此這裡可以匹配到這兩個元素。

偽選擇器

選擇器的目的就是為了匹配到 HTML 文件中的滿足條件的元素,然後將樣式屬性作用在元素上。

元素是什麼,在基礎一節中有介紹過,元素其實就是包含了標籤以及文字內容的整塊內容。因此被選擇器匹配到的元素,都是直接將 CSS 樣式作用到整個元素上,也就是作用到整個文字內容上。

那麼,如果有一些需求並不是直接去匹配 HTML 文件中的具體元素,而是指定了一些狀態、行為,然後讓瀏覽器動態去根據當前情況選擇符合這些狀態、行為的元素。

或者有一些需求是並不想將 CSS 樣式作用到整個元素上,而是隻作用到元素標記的文字內容的某一部分。

這個時候,這種選擇器就稱作偽選擇器,因為它有區別於普通選擇器的行為

偽選擇器總共分成兩種:偽元素選擇器,偽類選擇器

偽元素選擇器

當偽選擇器最終將 CSS 作用的物件並不是整個元素,而是滿足條件的元素標記的文字內容的某一部分時,稱偽元素選擇器。

偽元素選擇器不多,如下:

::first-line 匹配滿足條件的元素標記的文字內容的首行部分
::first-letter 匹配滿足條件的元素標記的文字內容的首字母部分
:before 在滿足條件的元素之前插入生成的內容
:after 在滿足條件的元素之後插入生成的內容

偽元素選擇器的用法基本都是和其他選擇器組合使用,比如 p::first-line 表示匹配 p 元素標記的文字內容的首行部分。

而 :before 和 :after 與之前的選擇器都不大一樣,因為之前介紹的選擇器作用都只是用於匹配選擇 HTML 文件中的元素或文字內容而已。但這兩個偽元素選擇器會生成內容,並插入到匹配到元素的文字內容中去。

因此,它們的基本用法通常都是這樣:

a:before {
    content: "在文字內容之前插入";
}
a:after {
    content: "在文字內容之後插入";
}

有一種應用場景很適合使用這兩種偽元素選擇器,當需要對列表動態的生成複雜的編號規則時,可以結合 :before 和 counter() 使用。在 CSS 中也是可以使用一些內建的方法功能。

偽類選擇器

當不是通過 HTML 文件中元素的一些基本性質,比如 id,class,標籤名,屬性這些基本特徵來匹配這些元素時,就可以稱作偽類選擇器。

偽類選擇器是通過滿足一些指定狀態、行為下來匹配元素的一種選擇器,比如滿足是否獲取焦點等等。

偽類選擇器相對來說,比較多,如下:

:first-child 選擇元素的第一個子元素
:last-child 選擇元素的最後一個子元素
:only-child 選取元素的唯一一個子元素
:only-of-type 選取屬於父元素的特定型別的唯一子元素
:nth-child(n) 選取元素的第n個子元素
:nth-last-child(n) 選取元素的倒數第n個子元素
:nth-of-type(n) 選取屬於父元素的特定型別的第n個子元素
:nth-last-of-type(n) 選取屬於父元素的特定型別的倒數第n個子元素
:enabled 選取啟用狀態的元素
:disable 選取被禁用狀態的元素
:checked 選取所有選中的核取方塊和單選按鈕元素
:default 選取預設的元素
:valid :invalid 選取基於輸入驗證判定的有效或者無效的input元素
:in-range :out-of-range 選取被限定在指定範圍之內或之外的input元素
:required :optional 根據是否允許使用required屬性選取input元素
:link 選取未訪問的連結元素
:visited 選取使用者已訪問的連結元素
:hover 選取滑鼠指標懸停的元素
:active 選取當前被使用者啟用的元素,這通常意味著使用者即將點選該元素
:focus 選取獲得焦點的元素
:not(<選擇器>) 否定選擇,(如選擇所有不匹配<選擇器>的元素)
:empty 選取不包含任何子元素或文字的元素
:lang(<語言>) 選取lang屬性為指定值的元素
:target 選取URL片段識別符號指向的元素

一些偽類選擇器看下說明應該就清楚怎麼使用,不明白的再具體去查詢相關文件即可。

3.層疊演算法

由於一個元素通常會被多個選擇器命中,而這些選擇器又有可能是通過不同方式作用到元素上,因此這裡存在了兩種場景下的優先順序問題,但請記住,只有當作用到同一個元素上的樣式屬性起了衝突時才會存在優先順序問題。

如果不同選擇器作用到同一個元素上,但它們各自的樣式屬性列表中沒有重複的,那就不存在衝突,也就不存在優先順序問題,都會一起合併作用到元素上。

場景1:不同使用方式的優先順序

CSS 有三種使用方式,另外瀏覽器也有預設樣式,因此這些構成了一個優先順序順序:

  1. 元素內嵌樣式(全域性屬性 style 定義的樣式)
  2. 文件內嵌樣式(style 標籤定義的樣式) 和 外部樣式(link 標籤引入的外部 CSS 檔案)
  3. 瀏覽器中的使用者樣式
  4. 瀏覽器中的預設樣式

以上優先順序從高到低,同層級之間,如果存在衝突的樣式屬性的話,以文件中最後出現的屬性為準,採用覆蓋規則。

場景2:不同選擇器之間的優先順序

當作用到同一個元素上的不同選擇器存在樣式屬性衝突時,優先以場景1考慮優先順序,如果不存在場景1的情況,即起衝突的選擇器在場景1中處於同一層優先順序,那麼才會考慮不同選擇器之間的優先順序。

  1. id 選擇器
  2. class 選擇器,屬性選擇器,偽類選擇器
  3. 元素選擇器,偽元素選擇器

以上優先順序從高到低,同層級之間,如果存在衝突的樣式屬性的話,以文件中最後出現的屬性為準,採用覆蓋規則。

但,有時候,使用的是組合選擇器,那麼這時候就需要依靠一定的演算法來計算出誰的優先順序高了,這個演算法叫做層疊演算法:

通過對以上不同選擇器賦予某個數值來計算整個組合選擇器的最終數值,然後比較大小。

比如,上面三個優先順序的選擇器中,1優先順序的表示100,2優先順序的表示10,3優先順序的表示1,以此來計算一個組合選擇器的數值大小。

通常來說,組合選擇器不會過於離譜,長達十幾個選擇器的組合,因此以上述賦予每個優先順序的數值足夠覆蓋絕大多數場景。

示例:

層疊演算法

h1,和 #indentifier 都只是簡單選擇器,不通過這種層疊演算法計算也行。

h1 + p::first-letter 和 li > a[href*=”zh-CN”] > .inline-warning 這種比較複雜的組合選擇器,就可以根據賦予每一層級優先順序對應的數值來進行計算,最終根據數值大小比較誰的優先順序高。

這種賦予不同優先順序某個具體數值具現化的思想叫做層疊演算法,通常是用於比較複雜的組合選擇器時。

但實際開發中,很少會需要用到層疊演算法,掌握場景1和場景2下簡單的優先順序分辨理論基礎足夠了。實際開發過程中,沒必要這麼複雜,藉助開發工具或者執行檢視下效果就可以確認誰的優先順序高低了。


大家好,我是 dasu,歡迎關注我的公眾號(dasuAndroidTv),如果你覺得本篇內容有幫助到你,可以轉載但記得要關注,要標明原文哦,謝謝支援~
dasuAndroidTv2.png

相關文章