《深入解析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,兩者都會生效。但是有很多屬性的值很模糊,在這種情況下,值的順序很關鍵。
-
上、右、下、左
當遇到像
margin
、padding
這樣的屬性,還有為元素的四條邊分別指定值的邊框屬性時,這些屬性的值是按順時針方向,從上邊開始的。這種模式下的屬性值還可以縮寫,沒有宣告的取其對邊的值:padding:1em //上右下左 padding:1em 2em; //上下 左右 padding:1em 2em 1em; //上 左右 下
-
水平、垂直
還有一些屬性只支援最多指定兩個值,這些屬性包括
background-position
、box-shadow
、text-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-cell
和vertical-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,也就是三者中最大的值。 -
防止外邊距摺疊
- 對容器使用overflow: auto(或者非visible的值),防止內部元素的外邊距跟容器外部的外邊距摺疊。這種方式副作用最小。
- 在兩個外邊距之間加上邊框或者內邊距,防止它們摺疊。
- 如果容器為浮動元素、內聯塊、絕對定位或固定定位時,外邊距不會在它外面摺疊。
- 當使用Flexbox佈局時,彈性佈局內的元素之間不會發生外邊距摺疊。網格佈局同理。
- 當元素顯示為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;
}