1. 程式人生 > 實用技巧 >《深入解析css》—CSS基礎

《深入解析css》—CSS基礎

前言:所有內容源於基思·J·格蘭特的《深入解析css》

疊層

層疊指的就是這一系列規則。它決定了如何解決衝突。當宣告衝突時,層疊會依據三種條件解決衝突:

  • 樣式表的來源:樣式是從哪裡來的,包括你的樣式和瀏覽器預設樣式等。
  • 選擇器優先順序:哪些選擇器比另一些選擇器更重要。
  • 原始碼順序:樣式在樣式表裡的宣告順序。


1.樣式來源

  • 瀏覽器預設樣式:優先順序低
  • 你自己引入的樣式
  • !important宣告:優先順序高

2.優先順序

  • 行內樣式:可以覆蓋任何來自樣式表或者<style>標籤的樣式(除非其他聲明瞭!importent

    <div style="color:red"></div>
    
  • 選擇器:ID選擇器>類選擇器>標籤選擇器

    優先順序比較規則:選擇器ID數量多者勝;若ID數量一致,類選擇器多者勝;若以上兩者都一致,標籤選擇器多者勝。

    其他說明:
    偽類選擇器(如:hover)和屬性選擇器(如[type="input"])與一個類選擇器的優先順序相同。通用選擇器(*)和組合器(>、+、~)對優先順序沒有影響。

3.原始碼順序

如果兩個宣告的來源和優先順序相同,後出現的樣式會覆蓋先出現的樣式

總結

瀏覽器遵循三個步驟,即來源、優先順序、原始碼順序,來解析網頁上每個元素的每個屬性。如果一個宣告在層疊中“勝出”,它就被稱作一個層疊值。元素的每個屬性最多隻有一個層疊值

繼承

如果一個元素的某個屬性沒有層疊值,則可能會繼承某個祖先元素的值。

但不是所有的屬性都能被繼承,預設情況下,只有特定的一些屬效能被繼承。它們主要是跟文字相關的屬性:color、font、font-family、font-size、font-weight、font-variant、font-style、line-height、letter-spacing、text-align、text-indent、text-transform、white-space以及word-spacing;或者列表屬性:list-style、list-style-type、list-style-position以及list-style-image;表格的邊框屬性

border-collapse和border-spacing(不完全列舉)

開發者工具的使用

特殊值

  • inherit

    用繼承的方式代替一個層疊值,

    a:link{color:blue}		//全域性的網頁連結顏色
    .footer{color #666}		//頁尾的文字顏色
    .footer a{color:inherit}	//從頁尾繼承的文字顏色
    
  • initial

    撤銷作用於某個元素的樣式(每一個CSS屬性都有初始值,這種方式可以重置初始值)

    .footer a{color:initial} 
    //在大多數瀏覽器中,黑色是color屬性的初始值,所以color: initial等價於color: black
    

簡寫屬性

簡寫屬性用於同時給多個屬性賦值,比如:

  • font可以設定多種字型屬性。它指定了font-style、font-weight、font-size、font-height以及font-family。

  • background可以設定多個背景屬性:background-color、background-image、background-size、background-repeat、background-position、background-origin、background-chip以及background-attachment。

  • border可以設定:border-width、border-style以及border-color

  • border-width可以設定:上、右、下、左四個邊框寬度


覆蓋其他樣式

簡寫屬性可以省略一些值,只指定我們關注的值。但這樣做仍然會設定省略的值,即它們會被隱式地設定為初始值。

h1{font-weight:bold;}
.title{ font:32px Arial} 	//-->隱性設定了預設值font-weight:normal,故不會加粗

簡寫值的順序

簡寫屬性會盡可能包容指定的屬性值的順序。比如設定border: 1px solid black或者border: black 1px solid,兩者都會生效。但是有很多屬性的值很模糊,在這種情況下,值的順序很關鍵

  • 上、右、下、左

    當遇到像marginpadding這樣的屬性,還有為元素的四條邊分別指定值的邊框屬性時,這些屬性的值是按順時針方向,從上邊開始的。這種模式下的屬性值還可以縮寫,沒有宣告的取其對邊的值:

    padding:1em				//上右下左
    padding:1em 2em;		//上下 左右
    padding:1em 2em 1em;	//上 左右 下
    
  • 水平、垂直

    還有一些屬性只支援最多指定兩個值,這些屬性包括background-positionbox-shadowtext-shadow(嚴格來講它們並不是簡寫屬性)。這些屬性值的順序跟上方的正好相反。

    比如,padding: 1em 2em是先指定了上/下屬性值,然後才是右/左屬性值,而background-position: 25% 75%則先指定右/左屬性值,然後才是上/下屬性值

相對單位

絕對單位如畫素,如5px放在哪裡都一樣大。而像em和rem這樣的是相對單位。相對單位的值會根據外部因素髮生變化。

隨著技術的發展,加上製造商推出高清顯示器,智慧手機出現,開發人員再也無法假裝每個使用者訪問網站的體驗都能一樣。不管我們喜歡與否,都得拋棄以前那種固定寬度的欄目設計,開始考慮響應式設計
相對單位可以基於視窗大小來等比例地縮放字號,或者將網頁上的任何元素的大小都相對於基礎字號來設定


em

1em等於當前元素的字號,而2em就相當於兩倍當前元素的字號。當設定padding、height、width、border-radius等屬性時,使用em會很方便。這是因為當元素繼承了不同的字號,或者使用者改變了字型設定時,這些屬性會跟著元素均勻地縮放。

.box-small{font-size:12px}
.box-large{font-size:18px}
.box{
    padding:1em;
    border-radius:1em;
}
<div class="box box-small"></div>
<div class="box box-large"></div>

rem

當使用em給元素定義字號並且多級巢狀時,可能會發生文字縮小或放大的現象。rem可以解決這個問題。

在DOM中,根節點是所有其他元素的祖先節點。根節點有一個偽類選擇器:root,等價於型別選擇器html。rem是root em的縮寫。rem不是相對於當前元素,而是相對於根元素的單位。

:root{font-size:1em} 	//表示使用瀏覽器的預設字號
ul{font-size:.8rem}		//表示相對於根元素將字號擴大八倍

響應式面板

根據螢幕尺寸,可以用媒體查詢改變根元素的字號。這樣就能夠基於不同使用者的螢幕尺寸,渲染出不同大小的面板。

//作用在所有螢幕上,可能會被後面的覆蓋
:root{font-size:0.75em;}

//作用在寬度為800px及以上的螢幕,覆蓋前面的值
@media (min-width:800px){
    :root{font-size:0.875em;}
}

//作用在寬度為1200px及以上的螢幕,覆蓋前面的值
@media (min-width:1200px){
    :root{font-size:0.875em;}
}

如果需要讓同一個元件在頁面某些部位顯示不同的大小,可以用em來單獨縮放一個元件。

.panel{
    font-size:1rem;
    padding:1em;
}
.panel>h2{
    font-size:0.8em;
}

視口

視口指瀏覽器窗口裡網頁可見部分的邊框區域,它不包括瀏覽器的位址列、工具欄、狀態列。視口的相對單位是相對於瀏覽器視口定義的

  • vh:視口高度的1/100
  • vw:視口寬度的1/100
  • vmin:視口寬、高中較小的一方的1/100
  • vmax:視口寬、高中較大的一方的1/100

比如,100vw等同於整個視口寬度,50vw等於視口寬度的一半;

vmin有個作用:保證元素在螢幕方向變化時適應螢幕。在橫屏時,vmin取決於高度;在豎屏時,則取決於寬度。

div{
    width:90vmin;
    height:90vmin;
    background-color:red
}

calc()定義字號

calc()函式內可以對兩個及其以上的值進行基本運算。支援的運算包括:加(+)、減(−)、乘(×)、除(÷)。在下面的例子中,慢慢縮放瀏覽器,字型會平滑地縮放,0.5em保證了最小字號,1vw則確保了字型會隨著視口縮放。

:root{
    font-size:calc(0.5em+1vm)
}

無單位的數值

有些屬性允許無單位的值如:line-height、z-index、font-weight

自定義屬性

css可以自定義屬性。下面的程式碼定義了一個名叫--main-font的變數。變數名前面必須有兩個連字元--,用來跟CSS屬性區分,剩下的部分可以隨意命名。變數必須在一個宣告塊內宣告。比如這裡是在root選擇器裡,因此該變數可以在整個網頁使用:

1.宣告變數

:root{
    --main-foot:Arial
}

2.呼叫函式var()使用該變數

p{
    font-family:var(--main-foot)
}

如果剛好用了內建變數功能的CSS前處理器,比如Sass或者Less,你可能就不太想用CSS變量了。然而,新規範裡的CSS變數比任何一款前處理器的變數功能都多,因此作者傾向於稱其為“自定義屬性”,而不是變數,以強調它跟前處理器變數的區別。

var()函式接受第二個引數,指定備用值

p{
     font-family:var(--main-foot,'宋體')
}

動態改變自定義屬性

例如,可以定義一個變數為黑色、一個變數為白色;然後在某個容器中重新定義變數的顏色。那麼,在容器內部會動態解析這些變數。

<div class="panel">
  <p>zxcvbwfhs</p>
</div>

<aside class="dark">
	<div class="panel">
 	 <p>zxcvbwfhs</p>
	</div>
</aside>
:root{
    --main-bg:#fff;
    --main-color:#000
}
.panel{
    background-color:var(--main-bg);
    color:var(--main-color)
}
.dark{
    --main-bg:#333;			//在容器中從定義變數
    --main-color:#fff;
}

盒模型

元素寬度

預設盒模型

padding、border、margin是追加在內容寬度外邊的。當子元素的寬度(包括padding、border、margin)超過父容器內容寬度的100%的時候,塊級元素會自動折行。

預設盒子的寬=內容寬度

box-sizing:content-box //預設

調整盒模型

盒模型還有另一種:border-box,此時盒子的寬=內容寬度+padding+border

box-sizing:border-box

全域性設定border-box

選中頁面所有元素及偽元素

*,::before,::after{ box-sizing:border-box}

但是如果在網頁中使用了帶樣式的第三方元件,可能會有衝突,這時可以:

:root{box-sizing:border-box}
*,::before,::after{box-sizing:inherit}

給列之間加上間隔

假設有兩個同級的div:main和sidebar

.main{
    float: left;
    box-sizing: border-box;
    width: 70%;
}
.sidebar{
    float: left;
    box-sizing: border-box;
    width:30%
    padding: 1.5em;
}

可以基於百分比的外邊距留白

.sidebar{
    width:30%;
}
------------------變成:
.sidebar{
    width:29%;
    margin-left:1%
}

元素高度

普通文件流是為限定的寬度和無限的高度設計的。內容會填滿視口的寬度,然後在必要的時候折行,因此,容器的高度由內容決定

普通文件流——指的是網頁元素的預設佈局行為。行內元素跟隨文字的方向從左到右排列,當到達容器邊緣時會換行。塊級元素會佔據完整的一行。

控制溢位行為

當明確設定一個元素的高度時,內容可能會溢位容器。用overflow屬性可以控制溢位內容的行為,該屬性支援以下4個值:

  • visible:所有內容可見,即使溢位容器邊緣(預設值)
  • hidden:溢位容器內邊距邊緣的內容被裁剪,無法看見
  • scroll:容器出現滾動條,使用者可以通過滾動檢視剩餘內容
  • auto:只有內容溢位時容器才會出現滾動條

overflow-x可以控制水平方向的溢位,overflow-y控制垂直方向溢位

實現等列高

首先可以採用百分比,然而想讓百分比高度生效,必須給父元素明確定義一個高度。而且更多時候我們不確定高度,這時候可以用如下方法:

  • CSS表格佈局

    /* container容器包含main和sidebar */
    .container{
        display: table;	  		/* 1. table佈局*/
        width: 100%;				/* 2. 讓表格填充容器的寬度*/
        border-spacing: 1.5em 0;	/* 3. table佈局中,外邊距不再生效,用border-spacing實現間隔*/
    }
    
    /* 4. 在container容器外包裹消除左右邊距 */
    .wrapper{
        margin-left: -1.5em;
        margin-right: -1.5em;
    }
    
    /* 5. 給子元素設定table-cell佈局 */
    .main{
        display: table-cell;
        box-sizing: border-box;
        width: 70%;
        padding: 1.5em;
    }
    /* 給子元素設定table-cell佈局 */
    .sidebar{
        display: table-cell;
        box-sizing: border-box;
        width:30%;
        padding: 1.5em;
    }
    
  • Flex佈局

    也稱彈性容器,子元素預設等高。

    .container{
        display: flex;
    }
    .main{
        box-sizing: border-box;
        width: 70%;
    }
    .sidebar{
        box-sizing: border-box;
        width:29%;
        margin-left: 1%;
    }
    

min-height和max-height

min-height可以指定一個最小高度。此時元素至少等於你指定的高度,如果內容太多,瀏覽器就會允許元素自己擴充套件高度,以免內容溢位

同理,max-height允許元素自然地增高到一個特定界限。如果到達這個界限,元素就不再增高,內容會溢位

垂直居中

vertical-align不生效問題

vertical-align宣告只會影響行內元素或者table-cell元素。對於行內元素,它控制著該元素跟同一行內其他元素之間的對齊關係。比如,可以用它控制一個行內的圖片跟相鄰的文字對齊。對於顯示為table-cell的元素,vertical-align控制了內容在單元格內的對齊。

如果給塊級元素設定vertical-align: middle,瀏覽器會忽略這個宣告。


垂直居中指南

  • 如果可以用一個自然高度的容器,給容器加上相等的上下內邊距讓內容居中。

    div{
        background-color: #0072b0;
        color: #fff;
        padding: 4em 0;
    }
    
  • 如果容器需要指定高度或者避免使用內邊距,對容器使用display: table-cellvertical-align: middle

  • 如果可以用Flexbox, 詳見flex佈局

  • 如果容器裡面的內容只有一行文字的行內元素,設定一個大的行高,讓它等於理想的容器高度。這樣會讓容器高度擴充套件到能夠容納行高。

  • 如果知道容器和內容的高度,將內容絕對定位

  • 如果不知道內部元素的高度,用絕對定位結合變形(transform)

負外邊距

負外邊距有一些特殊用途,比如讓元素重疊或者拉伸到比容器還寬。負外邊距的具體行為取決於設定在元素的哪邊

外邊距摺疊

當頂部和底部的外邊距相鄰時,就會重疊,產生單個外邊距,數值取其中最大者。這種現象被稱作摺疊。

  • 文字摺疊:外邊距摺疊的主要原因與包含文字的塊之間的間隔相關。比如,段落<p>預設有1em的上外邊距和1em的下外邊距,當前後疊放兩個段落時,它們的外邊距不會相加產生一個2em的間距,而會摺疊,只產生1em的間隔。

  • 多個外邊距摺疊:即使兩個元素不是相鄰的兄弟節點;或用額外的div將段落包裹,只要沒有其他CSS的影響,所有相鄰的頂部和底部外邊距都會摺疊。舉個例子

    <h2>qqqqq</h2>
    <div>
        <p>aaaaaaa</p>
    </div>
    

    有三個不同的外邊距摺疊到一塊了:<h2>底部的外邊距、<div>頂部的外邊距、<p>頂部的外邊距。計算值分別是19.92px、0px、16px。因此最終間隔還是19.92px,也就是三者中最大的值。

  • 防止外邊距摺疊

    1. 對容器使用overflow: auto(或者非visible的值),防止內部元素的外邊距跟容器外部的外邊距摺疊。這種方式副作用最小。
    2. 在兩個外邊距之間加上邊框或者內邊距,防止它們摺疊。
    3. 如果容器為浮動元素、內聯塊、絕對定位或固定定位時,外邊距不會在它外面摺疊。
    4. 當使用Flexbox佈局時,彈性佈局內的元素之間不會發生外邊距摺疊。網格佈局同理。
    5. 當元素顯示為table-cell時不具備外邊距屬性,因此它們不會摺疊。

容器內元素間距

貓頭鷹選擇器:不用給網頁當前的內容固定外邊距,而是應該採取更通用的方式,不管網頁結構如何變化都能夠生效。它長這樣:* +*

下面表示body內所有元素的相鄰兄弟元素。有了這個,就不需要每次都給元素新增固定的外邊距了

body * + *{
    margin-top:1.5em
}
<div class="container">
    <div class="sidebar">
        <a href="">123</a>
        <a href="">456</a>
        <a href="">759</a>
    </div>
</div>

完整css

body * + *{
    margin-top:1.5em
}

.container{
    display: flex;
}

.sidebar{
    background-color: #ccc;
    width:20%;
    padding: 1.5em;
    box-sizing: border-box;
}
.sidebar a{
    text-align: center;
    display: block;
    padding: .5em;
    background-color: #0072b0;
    text-decoration: none;
    color: white;
    font-weight: bold;
}