網頁是由不同內容塊構成的:標題、段落、鏈接、列表、圖片、視頻,等等。
1.定位
定位並不適合總體布局,因為它會把元素拉出頁面的正常流。
- 元素的初始定位方式為靜態定位(
static
),即塊級元素垂直堆疊。 - 把元素設置為相對定位(
relative
),然后可以相對於其原始位置控制該元素的偏移量,同時又不影響其周圍的元素。 - 絕對定位(
absolute
)支持精確定位元素,相對於其最近的定位上下文。 - 固定定位(
fixed
)的定位上下文為瀏覽器視口。
1.1 絕對定位
1.1.1 絕對定位的應用場景
絕對定位非常適合創建彈出層、提示和對話框這類覆蓋於其他內容之上的組件。
如果沒有顯式聲明元素大小,那么絕對定位元素的大小由自身包含內容的多少來決定。如果相對於定位上下文的各個邊聲明偏移量,那么元素會被拉伸以滿足設定的規則。
<header class="photo-header">
<img src="images/big_spaceship.jpg" alt="An artist’s mockup of the ”Dragon” spaceship">
<div class="photo-header-plate">
<h1>SpaceX unveil the Crew Dragon</h1>
<p>Photo from SpaceX on <a href="https://www.flickr.com/photos/spacexphotos/16787988882/">Flickr</a></p>
</div>
</header>
.photo-header {
position: relative;
}
.photo-header-plate {
position: absolute;
right: 4em;
bottom: 4em;
left: 4em;
/* 省略 */
}
1.1.2 定位與z-index
z-index
是堆疊元素的次序。
靜態定位(static
)以外的元素會根據它們在代碼樹中的深度依次疊放。就像打撲克發牌一樣,后發的牌會壓在先發的牌上面。它們的次序可以通過z-index
來調整。
設置了z-index
的元素,只要值是正值,就會出現在沒有設置z-index
的元素上方。尚未設置z-index
的元素在z-index
值為負的元素上方。
堆疊上下文:所有z-index
不是auto的定位元素都會在這個上下文中排序。
堆疊上下文是由特定屬性和值創建的。
在一個堆疊上下文內部,無論z-index
值多大或多小,都不會影響其他堆疊上下文。
設置小於1的opacity
值也可以觸發新的堆疊上下文。
2.水平布局
通常,頁面會隨內容增加沿垂直方向擴展。后來添加的任何塊容器(div
、article
、h1
~h6
,等等)都會垂直堆放起來,因為塊級元素的寬度是自動計算的。
2.1 使用浮動
很多CSS布局會用到的一種基本技術:讓浮動的元素構成一行中的列。
figure {
float: right;
max-width: 50%;
}
因為瀏覽器對浮動的支持極為普遍,所以浮動也成為了各種水平布局中的常用技術。
2.2 行內塊布局
<p class="author-meta">
<!-- image from Jeremy Keith on Flickr: https://flic.kr/p/dwFRgH -->
<img class="author-image" src="images/author.jpg" alt="Arthur C. Lark">
<span class="author-info">
<span class="author-name">Written by Arthur C. Lark</span>
<a class="author-email" href="mailto:arthur.c.lark@example.com">arthur.c.lark@example.com</a>
</span>
</p>
.author-image,
.author-info {
display: inline-block;
/* 將這個行內塊的垂直中心點與這行文本x高度的中心點對齊。 */
vertical-align: middle;
}
.author-name,
.author-email {
display: block;
}
對於每個塊都占據確切寬度的水平布局而言,空白是一個突出的問題。
.navbar ul {
/* 省略 */
list-style: none;
padding: 0;
font-size:0;
}
.navbar li {
text-transform: uppercase;
display: inline-block;
text-align: center;
width: 25%;
/* 使用box-sizing: border-box 確保每一項的邊框及內邊距都包含在各自25%的寬度以內。 */
box-sizing: border-box;
font-size:1rem;
}
.navbar li a {
display: block;
text-decoration: none;
line-height: 1.75em;
padding: 1em;
}
HTML源代碼中的換行符被渲染成了空白符。
把包含元素的font-size
設置為0,從而讓每個空格的寬度為0。
使用表格顯示屬性實現布局:
.navbar ul {
display: table;
table-layout: fixed;
width: 100%;
height: 100px; /* 結合vertical-align: middle使用以實現垂直對齊 */
}
.navbar li {
display: table-cell;
width: 25%;
vertical-align: middle; /* 垂直對齊 */
}
表格行中每一列的寬度有兩種算法。
- 默認情況下,瀏覽器會使用"自動"算法。根據自身單元格內容所需的寬度來決定整個表格的寬度。
- "固定"表格布局(
table-layout:fixed
)。列寬由表格第一行的列決定。
3.Flexbox
Flexbox是CSS提供的用於布局的一套新屬性。這套屬性包含針對容器(彈性容器,flex container)和針對對其直接子元素(彈性項,flex item)的兩類屬性。
Flexbox已經得到主流瀏覽器新版本的廣泛支持。
3.1 理解Flex方向:主軸與輔軸
Flexbox可以針對頁面中某一區域,控制其中元素的順序、大小、分布及對齊。這個區域的盒子默認沿水平方向排列(這個排列方向稱為主軸)。
與主軸垂直的方向稱為輔軸。
Flexbox布局中最重要的尺寸是主軸方向的尺寸(主尺寸):水平布局時的寬度或垂直布局時的高度。
.navbar ul {
display: flex; /* 默認flex-direction: row */
}
導航條的鏈接項水平排列,而且根據各自的內容進行了收縮適應。
所有鏈接項集中在左側,是從左到右書寫的語言環境下的默認行為。我們可以使用flex-direction
設置為row-reverse
,那么所有鏈接項就會集中到右側。
如果不指定大小,Flex容器內的項目會自動收縮。也就是說,一行中的各項會收縮到各自的最小寬度。
對Flex的子項指定值為auto
外邊距:
.navbar li:first-child {
margin-right: auto;
}
3.2 對齊與空間
Flexbox對子項的排列有多種方式。沿主軸的排列叫排布(justification),沿輔軸的排列則叫對齊(alignment)。
用於指定排布方式的屬性是justify-content
,其默認值是flex-start
,表示按照當前文本方向排布(向左對齊)。
Flexbox不允許指定個別項的排布方式。
.navbar ul {
justify-content: flex-end; /* 向右對齊 */
}
默認情況下,Flex子項會沿輔軸方向填滿Flex容器。
控制輔軸對齊的屬性align-items
,其默認值是stretch
(拉伸)。也就是說,子項默認拉伸,以填滿可用空間。
.navbar ul {
align-items: flex-start;
min-height: 100px;
}
我們還可以使用align-items: baseline
將子項中文本的基線與容器基線對齊。
除了同時對齊所有項,還可以在輔軸上指定個別項的對齊方式。
.navbar ul {
align-items: flex-end;
min-height: 100px;
}
.navbar li:first-child {
align-self: flex-start; /* 指定個別項的對齊方式 */
margin-right: auto;
}
Flex中的垂直對齊:
<div class="flex-container">
<div class="flex-item">
<h2>Not so lost in space</h2>
<p>This item sits right in the middle of its container, regardless of the dimensions of either.</p>
</div>
</div>
.flex-container {
height: 100%;
display: flex; /* 將容器設置為flex。 */
background-color: #12459e;
}
.flex-item {
max-width: 25em;
padding: 2em;
margin: auto; /* 容器中的各項的自動外邊距會擴展相應方向的空間。 */
background-color: #fff;
}
Flex容器中有多個元素的垂直對齊:
<p class="author-meta">
<img class="author-image" src="images/author.jpg" alt="Arthur C. Lark">
<span class="author-info">
<span class="author-name">Written by Arthur C. Lark</span>
<a class="author-email" href="mailto:arthur.c.lark@example.com">arthur.c.lark@example.com</a>
</span>
</p>
.author-meta {
display: flex;
align-items: center; /* 垂直對齊 */
justify-content: center; /* 水平排布 */
}
.author-name,
.author-email {
display: block;
}
3.3 可伸縮的尺寸
Flexbox支持對元素大小的靈活控制。這一點既是實現精確內容布局的關鍵,也是迄今為止Flexbox中最復雜的環節。
Flex的意思是“可伸縮”,體現在3個屬性中:
flex-basis
(控制主軸方向上的“首選”大小,默認值為auto
。)flex-grow
(彈性系數 ,默認為0。)flex-shrink
(彈性系數,默認為1。)
使用flex
簡寫屬性一次性設置flex-grow
、flex-shrink
和flex-basis
屬性,值以空格分隔:
.navbar li {
flex: 1 0 0%; /* flex: flex-grow flex-shrink flex-basis */
}
flex-grow: 1
中的1表示占整體的“幾份”。
簡寫法中的flex-basis
必須帶單位,因此這里要么加百分號,要么就寫成0px
。
把flex-basis
的值設置為0,那在這一步就不會給項目分配空間了。這種情況下,容器內部的全部空間都會留到第二步再分配(這里第二步使用flex-grow: 1
來確定具體項目的尺寸)。
當項目寬度總和超過容器寬度時,Flexbox會按照flex-shrink
屬性來決定如何收縮它們:
每個項目先用自己的flex-shrink
乘以自己的flex-basis
,然后再用乘積除以每一項的flex-shrink
與flex-basis
的乘積之和,最后再拿得到的比例系數去乘以超出的寬度,從而得到該項目要收縮的空間數量。
推薦閱讀:flex - CSS(層疊樣式表) | MDN
3.4 Flexbox布局
Flexbox支持讓內容排布到多行或多列。
<ul class="tags">
<li><a href="/Binary_planet">Binary planet</a></li>
<li><a href="/Carbon_planet">Carbon planet</a></li>
<--! 還有更多··· -->
</ul>
.tags {
display: flex;
flex-wrap: wrap; /* 允許折行 */
margin: 0;
padding: 1em;
list-style: none;
}
.tags li {
display: inline-block; /* 行內塊 */
margin: .5em;
}
相關閱讀:行內元素和塊元素以及行內塊元素的特點
折行與方向:
.tags {
/* 省略 */
flex-direction: row-reverse; /* 從右向左排布 */
}
.tags {
/* 省略 */
flex-direction: row-reverse; /* 從右向左排布 */
flex-wrap: wrap-reverse; /* 向上折行 */
}
多行布局中可伸縮的大小:
.tags li {
flex: 1 0 auto;
}
稍微縮小一點瀏覽器窗口,就會導致最后一個標簽折行。
使用max-width
限制可伸縮的范圍。
.tags li {
flex: 1 0 auto;
max-width: 14em;
}
在多行布局中,我們可以相對於容器來對齊行或列。
.tags {
display: flex;
flex-wrap: wrap;
align-content: stretch; /* 默認值 */
min-height: 300px;
}
align-content: stretch
表示每一行都會拉伸以填充自己應占的容器高度。
3.5 列布局與個別排序
Flexbox的order
屬性:默認情況下,每個項目的order
值都為0,意味着按照它們在源代碼中的順序出現。
<div class="article-teaser">
<h2>The Dragon and other spaceships</h2>
<div class="article-teaser-text">
<p>There are actual spaceships, flying in space right now, probably. For example, there’s the International
Space Station, which is a spaceship of sorts. Well, actually it’s a space station, which is even cooler!</p>
</div>
<img src="images/medium_spaceship.jpg" alt="The Dragon spaceship in orbit around Earth.">
<p class="article-teaser-more">
<a href="/spaceships">Read the whole Spaceship article</a>
</p>
</div>
.article-teaser {
display: flex;
flex-direction: column;
}
.article-teaser img {
order: -1; /* order的值比較小的元素先出現。 */
}
order的值不一定要連續,而且正、負值都可以。只要是可以比較大小的數值,相應的項就會調整次序。
3.6 嵌套的Flexbox布局
<div class="article-teaser-group">
<div class="article-teaser">
<h2>The Dragon and other spaceships</h2>
<div class="article-teaser-text">
<p>There are actual spaceships,
flying in space right now, probably. For example, there’s the International Space Station, which is
a spaceship of sorts. Well, actually it’s a space station, which is even cooler!</p>
</div>
<img src="images/medium_spaceship.jpg" alt="The Dragon spaceship in orbit around Earth.">
<p class="article-teaser-more">
<a href="/spaceships">Read the whole Spaceship article</a>
</p>
</div>
<div class="article-teaser">
<!-- 省略 -->
</div>
</div>
.article-teaser-group {
display: flex;
}
.article-teaser {
display: flex;
flex-direction: column;
/* 省略 */
}
.article-teaser-more {
margin-top: auto;
}
Flexbox的bug與提示:
- 圖片、視頻,以及其他帶有固定寬高比的對象,在作為可伸縮項時可能會有問題。解決方案是給這些對象加個包裝元素,讓包裝元素作為可伸縮項。
- Flex的可伸縮項具有所謂的“隱性最小寬度”。
參考資料: