CSS內容布局


網頁是由不同內容塊構成的:標題、段落、鏈接、列表、圖片、視頻,等等。

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.水平布局

通常,頁面會隨內容增加沿垂直方向擴展。后來添加的任何塊容器(divarticleh1~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-growflex-shrinkflex-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-shrinkflex-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的可伸縮項具有所謂的“隱性最小寬度”。

參考資料:

  • 菜鳥教程
  • w3school
  • 《精通CSS》— [英] 安迪·巴德、[瑞典] 埃米爾·比約克隆德


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM