佈局(layout)#
- 確定內容的大小和位置的算法
- 依據元素、容器、兄弟節點和內容等信息來計算
CSS 基礎框盒模型介紹 - CSS(層疊樣式表) | MDN (mozilla.org)
當對一個文檔進行佈局(lay out)時,瀏覽器的渲染引擎會根據標準之一的 CSS 基礎框盒模型(CSS basic box model),將所有元素表示為一個個矩形的盒子(box)。CSS 決定這些盒子的大小、位置以及屬性(例如顏色、背景、邊框尺寸…)。
每個盒子由四個部分(或稱區域)組成,其效用由它們各自的邊界(Edge)所定義(原文:defined by their respective edges,可能意指容納、包含、限制等)。如圖,與盒子的四個組成區域相對應,每個盒子有四個邊界:內容邊界 Content edge、內邊距邊界 Padding Edge、邊框邊界 Border Edge、外邊框邊界 Margin Edge。
width#
指定 content box 寬度,可取值為長度、百分數、auto 等,百分數是相對於 content box 的寬度。
height#
指定 content box 高度可取值為長度、百分數、auto 等,百分數是相對於 content box 的高度。weight/height 都需注意的若使用百分比則其 content box 需指定寬度 / 高度否則不生效。
padding#
指定四個方向上的內邊距。其百分比是相對於容器寬度,說明見 padding - CSS(層疊樣式表) | MDN (mozilla.org)
- 當只指定一個值時,該值會統一應用到全部四個邊的內邊距上。
- 指定兩個值時,第一個值會應用於上邊和下邊的內邊距,第二個值應用於左邊和右邊。
- 指定三個值時,第一個值應用於上邊,第二個值應用於右邊和左邊,第三個則應用於下邊的內邊距。
- 指定四個值時,依次(順時針方向)作為上邊,右邊,下邊,和左邊的內邊距。
margin#
指定四個方向上的外邊距。其百分比是相對於容器寬度,說明見margin - CSS(層疊樣式表) | MDN (mozilla.org)
- 當只指定一個值時,該值會統一應用到全部四個邊的外邊距上。
- 指定兩個值時,第一個值會應用於上邊和下邊的外邊距,第二個值應用於左邊和右邊。
- 指定三個值時,第一個值應用於上邊,第二個值應用於右邊和左邊,第三個則應用於下邊的外邊距。
- 指定四個值時,依次(順時針方向)作為上邊,右邊,下邊,和左邊的外邊距。
margin collapse:外邊距重疊 - CSS(層疊樣式表) | MDN (mozilla.org)。相鄰的兩個元素之間的外邊距重疊,會在垂直方向上發生邊界折疊,挑選最大邊界範圍留下。
border#
指定邊框,border-width 指定寬度、border-style 指定類型(實線 / 虛線)、border-color 指定邊框顏色。通常直接將三者結合簡寫為 border ,MDN 描述見border - CSS(層疊樣式表) | MDN (mozilla.org)
- border 巧用:製作三角形
- 首先四個邊框設置了不同的顏色。可以發現邊角是由斜線切開的。
- 那麼當容器高度和寬度為 0 的時候,可以看到如圖
- 那如果將其他的邊框顏色設為透明(transport)可以發現,製造了一個紅色的三角形出來。
- 首先四個邊框設置了不同的顏色。可以發現邊角是由斜線切開的。
box-sizing#
box-sizing - CSS(層疊樣式表) | MDN (mozilla.org)
在 CSS 盒子模型的默認定義裡,對一個元素所設置的
width
與height
只會應用到這個元素的內容區。如果這個元素有任何的border
或padding
,繪製到螢幕上的盒子寬度和高度會加上設置的邊框和內邊距值。這意味著當你調整一個元素的寬度和高度時需要時刻注意到這個元素的邊框和內邊距。當我們實現響應式佈局時,這個特點尤其煩人。
box-sizing 屬性可以被用來調整這些表現:
content-box
是默認值。如果你設置一個元素的寬為 100px,那麼這個元素的內容區會有 100px 寬,並且任何邊框和內邊距的寬度都會被增加到最後繪製出來的元素寬度中。border-box
告訴瀏覽器:你想要設置的邊框和內邊距的值是包含在 width 內的。也就是說,如果你將一個元素的 width 設為 100px,那麼這 100px 會包含它的 border 和 padding,內容區的實際寬度是 width 減去 (border + padding) 的值。大多數情況下,這使得我們更容易地設置一個元素的寬高。
overflow#
overflow - CSS(層疊樣式表) | MDN (mozilla.org)
CSS 屬性 overflow 定義當一個元素的內容太大而無法適應 塊級格式化上下文 時該做什麼。它是
overflow-x
和overflow-y
的 簡寫屬性 。
將其設置為 auto,則當內容過多的時候會顯示滾動條,否則不顯示。而為使 overflow
有效果,塊級容器必須有一個指定的高度(height
或者max-height
)或者將white-space
設置為nowrap
。
塊級元素#
塊級元素 - HTML(超文本標記語言) | MDN (mozilla.org)
塊級元素佔據其父元素(容器)的整個水平空間,垂直空間等於其內容高度,通常瀏覽器會在塊級元素前後另起一個新行。
- 常見的有 body、article、div、main、section、h1-h6、p、ul、li
- display: block
行級元素#
行內元素 - HTML(超文本標記語言) | MDN (mozilla.org)
一個行內元素只佔據它對應標籤的邊框所包含的空間
行級元素和其他行級元素一起,不使用盒模型中的 width、height 屬性
-
常見的有 span、em、strong、cite、section、code 等
-
display: inline
說到 display 屬性,其說明display - CSS(層疊樣式表) | MDN (mozilla.org):
display
屬性可以設置元素的內部和外部顯示類型 display types。元素的外部顯示類型 outer display types 將決定該元素在流式佈局中的表現(塊級或內聯元素);元素的內部顯示類型 inner display types 可以控制其子元素的佈局(例如:flow layout,grid 或 flex)。
- block 塊級盒子
- inline 行級盒子
- inline-block 本身是行級,可以被放在行級盒子中,可以設置寬高,作為一個整體不會被拆散成多行。
- none 排版時被完全忽略
常規流(Normal Flow)#
- 根元素、浮動和絕對定位的元素會脫離常規流,其他元素都在常規流之內(in-flow)。常規流中的盒子,在某種排版上下文中參與佈局。
- 行級排版上下文、塊級排版上下文、Table 排版上下文、Flex 排版上下文、Grid 排版上下文……
行內格式化上下文(Inline formatting context)#
行內格式化上下文(Inline formatting context) - CSS(層疊樣式表) | MDN
行內格式化上下文是一個網頁的渲染結果的一部分。其中,各行內框(inline boxes)一個接一個地排列,其排列順序根據書寫模式(writing-mode)的設置來決定:
- 對於水平書寫模式,各個框從左邊開始水平地排列
- 對於垂直書寫模式,各個框從頂部開始水平地排列
在下面給出的例子中,帶黑色邊框的兩個 (
<div>
) 元素組成了一個塊級格式化上下文(block formatting context),其中的每一個單詞都參與一個行內格式化上下文中。水平書寫模式下的各個框水平地排列,垂直書寫模式下的各個框垂直地排列。
-
只包含行級盒子的容器會創建一個 IFC,IFC 中排版規則如下
- 盒子在一行內水平擺放,當一行放不下時會換行顯示。
text-align
決定一行內盒子的水平對齊vertical-align
決定一個盒子在行內的垂直對齊- 避開 浮動 元素
-
一個段落實際上是一系列行框的集合,這些行框在塊的方向上排列。
-
一個行內框(inline box)被分割到多行中時, margins, borders, 以及 padding 的設定均不會在斷裂處生效。 下例中有一個 (
<span>
) 元素,它包裹了一系列單詞,佔據了兩行。可以看見在斷裂處,<span>
的 border 同樣發生了斷裂。
塊級格式化上下文(Block Formatting Context)#
- Block Formatting Context(BFC)
- 盒子從上到下擺放
- BFC 內的垂直 margin 會合併(見前文 margin 中的 margin collapse,外邊距重疊)
- BFC 內盒子的 margin 則不會與外面的合併
- BFC 不會與浮動元素重疊
FlexBox#
-
一種新的排版上下文
-
可以控制子級盒子的:
- 擺放流向 (flex-direction)
- 默認(
row
):由左往右 → row-reverse
:由右往左←column
:由上到下 ↓column-reverse
:由下到上↑
- 默認(
- 擺放順序
- 盒子高度和寬度
- 水平與垂直方向的對齊(嚴格來說,主軸和交叉軸方向上的對齊,見
justify-content
和align-items
) - 是否允許折行(
wrap
、nowrap
、wrap-reverse
) - 其他還有 flex 元素上的屬性(
flex-grow
、flex-shrink
、flex-basis
)等
- 擺放流向 (flex-direction)
-
flex 子項會創建一個 BFC
重點再講一下主軸和交叉軸的對齊,以默認的由右往左排列(row),其主軸為水平軸,交叉軸為垂直軸。其中主軸(justify-content)的對齊方式有以下幾種(初始值為 flex-start ):
- flex-start 在主軸開始的地方對齊
- flex-end 在主軸結束的地方對齊
- center 在主軸上居中對齊
- space-between 在主軸上兩端對齊,中間穿插空間
- space-around 在主軸上兩邊也加上空白,保持元素佔用大小不變
- space-evenly 兩邊與中間的空白大小相同
交叉軸的對齊方式如下(初始值為 stretch):
- flex-start:在交叉軸開始的地方對齊
- flex-end:在交叉軸結束的地方對齊
- center:在交叉軸上居中對齊
- stretch:在交叉軸上,拉伸元素以適應容器
- baseline:兩邊與中間的空白大小相同
如果想給 flex 中的某個元素搞特殊,那麼可以給他設置一個 align-self 屬性,如圖
order 可以設置元素們在佈局時的順序
那如果網頁拉伸或者縮小,flex 容器中的內容會如何變呢?
-
可以通過設置 flex-grow 在有剩餘空間的時候控制伸展能力,flex-shrink 在剩餘空間不足的時候控制收縮。
-
flex-grow
屬性可以按比例分配空間。如果第一個元素flex-grow
值為 2, 其他元素值為 1,則第一個元素將佔有 2/4, 另外兩個元素各佔有 1/4。 -
flex-shrink
與flex-grow
屬性一樣,可以賦予不同的值來控制 flex 元素收縮的程度 —— 給flex-shrink
屬性賦予更大的數值可以比賦予小數值的同級元素收縮程度更大。 -
flex-basis
沒有伸展或者收縮時的基礎長度
關於 flex 佈局,之前在 codepen 看到過一個演示項目,可以了解其每個屬性的相應作用,強烈推薦自己多試試:Flexbox playground (codepen.io)
Grid 佈局#
Grid - 術語表 | MDN (mozilla.org)
-
display:grid 會使元素生成一個塊級的 Grid 容器
-
可以使用 grid-template 相關屬性將容器劃分為網格
grid-template-rows
基於 網格行 的維度,去定義網格線的名稱和網格軌道的尺寸大小grid-template-columns
該屬性是基於 網格列. 的維度,去定義網格線的名稱和網格軌道的尺寸大小- 可以定義
minmax(min, max)
,這是一個來定義大小範圍的屬性,大於等於 min 值,並且小於等於 max 值。如果 max 值小於 min 值,則該值會被視為 min 值。最大值可以設置為網格軌道系數值fr
,但最小值則不行 - 也可以用單位
fr
來定義上述網格軌道大小的彈性系數。 每個定義了fr
的網格軌道會按比例分配剩餘的可用空間。當外層用一個minmax()
表示時,它將是一個自動最小值 (即minmax(auto, <flex>)
) - 想要元素跨越多行 / 多列?
- grid line 網格線
- grid area 網格區域
- 使用 grid-template-columns-start/grid-template-columns-end 等,可簡寫為 grid-area;
照著課上寫的一個小 demo:Grid (codepen.io), 也算是一個直觀的例子了。
- 首先將容器設置為設置為一個 4 行 2 列的 grid
#container {
width: 300px;
height: 500px;
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr 1fr;
}
- 然後將 A 這個元素,設置從第 1 個網格行線開始到第 3 個網格行線,即佔兩行,列同理佔兩列,如圖
.a {
grid-row-start: 1;
grid-column-start: 1;
grid-row-end: 3;
grid-column-end: 3;
}
可簡寫為:
.a {
grid-area:1/1/3/3;
}
如圖,可以發現 A 佔據了兩行兩列
- 那麼再進行一些更改,將 a 改為 2-4 行 / 列即佔據了第 2、3 行 / 列,b 改為 1-3 行 / 列即佔據了第 1、2 行 / 列
.a {
grid-area:2/2/4/4;
}
.b {
grid-area:1/1/3/3;
}
浮動(float)#
早期的時候,圖文環繞利用 float 實現,現在只需了解即可。詳細的還是看float - CSS(層疊樣式表) | MDN (mozilla.org)
-
浮動允許文本和行內元素環繞它。具有浮動屬性的元素會從網頁的正常流動 (文檔流) 中移除
-
當一個元素浮動之後,它會被移出正常的文檔流,然後向左或者向右平移,一直平移直到碰到了所處的容器的邊框,或者碰到另外一個浮動的元素
-
要注意的就是如果使用浮動後,想要接下來的元素強制移至任何浮動元素下方,則須使用clear屬性
position 定位#
position
屬性用於指定一個元素在文檔中的定位方式。top
,right
,bottom
和 left
屬性則決定了該元素的最終位置。
position 有如下幾種定位類型:
- static:默認值,非定位元素
- relative:相對自身原本位置偏移,不脫離文檔流
- absolute:絕對定位,相對非 static 祖先元素定位
- fixed:相對於視口絕對定位
相對定位 (relative)#
position
- 在常規流中佈局
- 相對於自己本該在的地方進行偏移(top、left、bottom、right)
- 流內其他元素當它未偏移一樣照原樣佈局
絕對定位 (absolute)#
position
- 脫離常規流
- 相對於最近的非 static 祖先定位
- 比如一個圖標,要為它做一個角標,則將圖標設置為 position,再將其 position 設置為 absolute 進行偏移即可實現。
- 不會對流內元素佈局造成影響
建議及感想#
- 充分利用MDN 和 World Wide Web Consortium (W3C) CSS 規範
- 保持好奇心,善用瀏覽器的開發者工具
- 持續學習,CSS 新特性還在不斷出現
也算是給自己 CSS 學習的一個梳理,關於以上佈局,主要還是多用,多查,在實踐中成長,用多了自然而然的就記住了,然後平時看到感興趣的前端項目也要進行學習,看看優秀的項目是如何進行佈局的。