一篇全面的CSS布局學習指南 [譯]

引言

無論你是剛接觸CSS,還是其它技術棧經驗豐富的開發人員,想要了解最新的布局技術。這篇文章覆蓋了你需要知道的最新的CSS技術。

在過去的幾年間,CSS布局已經顯著的改變了我們開發前端網站的方式。我們現在可以用CSS中各種布局方法來開發我們的網站,這就意味著我們需要經常選擇哪種方式進行布局。在這篇文章中,我會介紹各種布局的基本使用方式和方法。

無論你是CSS新手困惑如何選擇最恰當的布局方法,或者你是使用其他技術棧經驗豐富的開發者想要了解最新的CSS布局,這篇文章都不容錯過。當然,我不會將各種布局的細枝末節都放在這里,那樣的話就是一本書而不是一篇文章。我會對各種布局做一個基本概述,同時也會給大家提供一個鏈接進行進一步學習。

1 正常文檔流(Normal Flow)

如果你打開一個沒有用任何CSS來改變頁面布局的網頁,那么網頁元素就會排列在一個正常流(normal flow)之中。在正常流中,元素盒子(boxes)會基于文檔的寫作模式(writing mode)一個接一個地排列。這就意味著,如果你的寫作模式是水平方向的(句子是從左到右或從右到左書寫),正常流會垂直地一個接一個排列頁面的塊級元素。

當然,如果你是在一個垂直方向的寫作模式下,句子是垂直方向書寫的,那么塊級元素會水平方法排列。

Block and Inline Directions change with Writing Mode.

正常流是一種最基礎的布局:當你為文檔應用了CSS、創建了某些CSS布局,你其實是讓這些塊做了一個正常文檔流之外的“事”。

1.1 通過頁面結構來發揮正常文檔流的優勢

通過確保你書寫的頁面具有良好的頁面結構(well-structured manner),你可以最大程度利用正常流所帶來的優勢。試想一下,如果瀏覽器中沒有正常流,那么你創建的元素都會堆積在瀏覽器的角上。這就意味著你必須指定所有的元素的布局方式。而不是瀏覽器以一種可讀的方式顯示我們的內容。

有了正常流,即使CSS加載失敗了,用戶仍然能閱讀你的頁面內容;同時,一些不使用CSS的工具(例如一些閱讀器)會按照元素在文檔中的位置來讀取頁面內容。從可用性(accessibility)角度來看,這無疑是非常有幫助的,同時也讓開發者輕松了一些。如果你的內容順序和用戶預期的閱讀順序一致,你就不需要為了將元素調整到正確的位置而進行大量的布局調整。當你繼續讀下去會發現,使用新的布局方式是如何讓頁面布局事半功倍的。

因此,在思考如何布局之前,你需要思考下文檔結構,以及你希望用戶以何種順序來閱讀文檔中的內容。

1.2 脫離正常文檔流

一旦你有了一個結構良好的頁面,你就需要去決定如何利用它并將它變為我們需要的布局結構。這會涉及到脫離正常文檔流(moving away from normal flow),即本文后續的部分內容。我們有許多布局“利器”可以使用,其中第一個就是float,它是一個描述什么是脫離正常文檔流的非常好的例子。

2 浮動(Floats)

浮動可以將盒子(box)移動到左側或右側,同時讓內容環繞其展示。

要讓一個元素進行浮動,需要為該元素設置一個值為leftrightfloat屬性,默認值為none。

.item {
    float: left;
}

值得強調的是,當你使某個元素浮動并讓文字環繞它時,內容的line box被截斷了。如果你讓一個元素浮動,同時為緊跟著的包含文本的元素設置一個背景色,你會發現背景色會出現在浮動元素下方。

The background color on the content runs under the float

如果你想要在浮動元素和環繞的文本之間創建邊距,你需要給浮動元素設置外邊距。在文本元素上設置外邊距只會讓其相對于容器縮進。例如在下面這個例子中,你就需要為左側浮動的圖片設置右邊距和下邊距。

<div class="container">
  <div class="item"></div>
  <p>Pea horseradish azuki bean lettuce avocado asparagus okra. Kohlrabi radish okra azuki bean corn fava bean mustard tigernut jícama green bean celtuce. </p>
  <p>Grape silver beet  collard greens avocado quandong fennel gumbo black-eyed pea watercress potato tigernut corn groundnut. Chickweed okra pea winter purslane coriander yarrow sweet pepper radish garlic brussels sprout groundnut summer purslane earthnut pea tomato spring onion azuki bean gourd. Gumbo kakadu plum komatsuna black-eyed pea green bean zucchini gourd winter purslane silver beet rock melon radish asparagus spinach.</p>
</div>
body {
  padding: 20px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

p {
  margin: 0 0 1em 0;
}

.container {
  width: 500px;
  border: 5px solid rgb(111,41,97);
  border-radius: .5em;
  padding: 10px;
}

.item {
  width: 100px;
  height: 100px;
  float: left;
  margin: 0 20px 20px 0;
  background-color: rgba(111,41,97,.3);
}

2.1 清除浮動

一旦你對一個元素應用了浮動,所有接下來的元素都會環繞它直到內容處于它下方且開始應用正常文檔流。如果你想要避免這種情況,可以手動去清除浮動。

當你不想要某個元素受到其之前的浮動元素影響時,為其添加clear屬性即可。使用left值可以清除左浮動效果,right值為右浮動,both則會清除左右浮動。

.clear {
    clear: both;
}

但是,當你發現在容器內有了一個浮動元素,同時容器文本內容過短時就會出現問題。文本盒子會被繪制在浮動元素下,然后接下來的部分會以正常流繪制在其后。

The box around the text does not clear the float

為了避免這種情況,我們需要為容器中某個元素應用clear屬性。我們可以在容器最后添加一個空元素并設置clear屬性。但是在某些情況下可能無法使用這種方式(例如一些CMS系統生成的頁面)。因此,最常見的清除浮動的hack方案是:在容器內添加一個CSS偽元素,并將其clear屬性設置為both。

<div class="container">
  <div class="item"></div>
  <p>Pea horseradish azuki bean lettuce avocado asparagus okra.</p>

</div>
body {
  padding: 20px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

p {
  margin: 0 0 1em 0;
}

.container {
  width: 500px;
  border: 5px solid rgb(111,41,97);
  border-radius: .5em;
  padding: 10px;
}

.item {
  width: 100px;
  height: 100px;
  float: left;
  margin: 0 20px 20px 0;
  background-color: rgba(111,41,97,.3);
}

.container::after {
  content: "";
  display: table;
  clear: both;
}

2.2 塊級格式化上下文(Block Formatting Context)

清除浮動的另一個方法是在容器內創建BFC。一個BFC元素完全包裹住了它內部的所有元素,包括內部的浮動元素,保證浮動元素不會超出其底部。創建BFC的方式有很多種,其中最常用的一種清除浮動的方式是為元素設置除visible(默認)之外的overflow屬性值。

.container {
    overflow: auto;
}

像上面這樣使用overflow一般情況下是有效的。然而,在某些情況下,這可能會帶來一些陰影的截斷或是非預期的滾動條。同時它也使你的CSS變得不那么直觀:設置overflow是因為你想要展示滾動條還是僅僅為了獲取清除浮動的能力呢?

為了使清除浮動的意圖更加直觀,并且避免BFC的負面影響,你可以使用flow-root作為display屬性的值。display: flow-root做的唯一的一件事就是去創建一個BFC,因此可以避免其他創建BFC方法帶來的問題。

.container {
    display: flow-root;
}

2.3 浮動的傳統用法

在新的布局方式出現以前,float經常會被用來創建多欄布局。我們會給一系列元素設置寬度并且將它們一個接一個進行浮動。通過為浮動元素設置一些精細的百分比大小可以創建類似網格的效果。

我不建議在當下仍然過度地使用這種方法。但是,在現有的網站中,這種方式仍然會存在許多年。因此,當你碰到一個頁面里面到處是float的應用,可以確定它就是用的這種技術。

2.4 關于浮動與清除浮動的其他閱讀資料

3 定位(Positioning)

想要把一個元素從正常流中移除,或者改變其在正常文檔流中的位置,可以使用CSS中的position屬性。當處于正常文檔流時,元素的position屬性為static。在塊級維度上元素會一個接一個排列下去,當你滾動頁面時元素也會隨著滾動。

當你改變元素的position屬性時,通常情況下你也會設置一些偏移量來使元素相對于參照點進行一定的移動。不同的position值會參照不同的參照點。

3.1 相對定位(relative postioning)

如果一個元素具有屬性position: relative,那么它偏移的參照位是其原先在正常文檔流中的位置。你可以使用top、left、bottom和right屬性來相對其正常流位置進行移動。

.item {
    position: relative;
    bottom: 50px;
}

注意,頁面上的其他元素并不會因該元素的位置變化而受到影響。該元素在正常流中的位置會被保留,因此你需要自己去處理一些元素內容覆蓋的情況。

<div class="container">
  
  <p>Pea horseradish azuki bean lettuce avocado asparagus okra. Kohlrabi radish okra azuki bean corn fava bean mustard tigernut jícama green bean celtuce. </p>
  
  <div class="item"></div>
  <p>Grape silver beet  collard greens avocado quandong fennel gumbo black-eyed pea watercress potato tigernut corn groundnut. Chickweed okra pea winter purslane coriander yarrow sweet pepper radish garlic brussels sprout groundnut summer purslane earthnut pea tomato spring onion azuki bean gourd. Gumbo kakadu plum komatsuna black-eyed pea green bean zucchini gourd winter purslane silver beet rock melon radish asparagus spinach.</p>
</div>
body {
  padding: 20px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

p {
  margin: 0 0 1em 0;
}

.container {
  width: 500px;
  border: 5px solid rgb(111,41,97);
  border-radius: .5em;
  padding: 10px;
}

.item {
  width: 100px;
  height: 100px;
  background-color: rgba(111,41,97,.3);
  position: relative;
  bottom: 50px;
}

3.2 絕對定位(absolute postioning)

給一個元素設置position: absolute屬性可以將其完全從正常流中移除。其原本占據的空間也會被移除。該元素會相對于其包裹元素進行定位。

因此,當你為某個元素設置position: absolute時,首先發生的變化是該元素會定位在視口的左上角。你可以通過設置top、left、bottom和right偏移量屬性來將元素移動到你想要的位置。

.item {
    position: absolute;
    top: 20px;
    right: 20px;
}

通常情況下你并不希望元素相對于視口進行定位,而是相對于容器元素。在這種情況下,你需要為包裹容器元素設置一個除了默認static之外的值。

由于給一個元素設置position: relative并不會將其從正常流中移除,所以通常這是一個不錯的選擇。如果你相對于父元素設置偏移量,那么元素就會相對于這個絕對定位的元素進行偏移。

<div class="container">
  
  <p>Pea horseradish azuki bean lettuce avocado asparagus okra. Kohlrabi radish okra azuki bean corn fava bean mustard tigernut jícama green bean celtuce. </p>
  
  <div class="item"></div>
  <p>Grape silver beet  collard greens avocado quandong fennel gumbo black-eyed pea watercress potato tigernut corn groundnut. Chickweed okra pea winter purslane coriander yarrow sweet pepper radish garlic brussels sprout groundnut summer purslane earthnut pea tomato spring onion azuki bean gourd. Gumbo kakadu plum komatsuna black-eyed pea green bean zucchini gourd winter purslane silver beet rock melon radish asparagus spinach.</p>
</div>
body {
  padding: 20px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

p {
  margin: 0 0 1em 0;
}

.container {
  width: 500px;
  border: 5px solid rgb(111,41,97);
  border-radius: .5em;
  padding: 10px;
  position: relative;
}

.item {
  width: 100px;
  height: 100px;
  background-color: rgba(111,41,97,.3);
  position: absolute;
  top: 20px;
  left: 20px;
}

3.3 固定定位(fixed positioning)

大多數情況下,position: fixed的元素會相對于瀏覽器窗口定位,并且會從正常文檔流中被移除,不會保留它所占據的空間。當頁面滾動時,固定的元素會留在相對于瀏覽器窗口的位置,而其他正常流中的內容則和通常一樣滾動。

.item {
    position: fixed;
    top: 20px;
    left: 100px;
}

當你想要一個固定導航欄一直停留在屏幕上時這會非常有效。和其他的position值一樣,這也可能會造成一些元素被遮擋,需要小心保證頁面內容的可讀而不會被固定元素遮擋。

<div class="container">
  
  <p>Pea horseradish azuki bean lettuce avocado asparagus okra. Kohlrabi radish okra azuki bean corn fava bean mustard tigernut jícama green bean celtuce. </p>
  
  <div class="item"></div>
  <p>Grape silver beet  collard greens avocado quandong fennel gumbo black-eyed pea watercress potato tigernut corn groundnut. Chickweed okra pea winter purslane coriander yarrow sweet pepper radish garlic brussels sprout groundnut summer purslane earthnut pea tomato spring onion azuki bean gourd. Gumbo kakadu plum komatsuna black-eyed pea green bean zucchini gourd winter purslane silver beet rock melon radish asparagus spinach.</p>
  
   <p>Grape silver beet  collard greens avocado quandong fennel gumbo black-eyed pea watercress potato tigernut corn groundnut. Chickweed okra pea winter purslane coriander yarrow sweet pepper radish garlic brussels sprout groundnut summer purslane earthnut pea tomato spring onion azuki bean gourd. Gumbo kakadu plum komatsuna black-eyed pea green bean zucchini gourd winter purslane silver beet rock melon radish asparagus spinach.</p>
  
   <p>Grape silver beet  collard greens avocado quandong fennel gumbo black-eyed pea watercress potato tigernut corn groundnut. Chickweed okra pea winter purslane coriander yarrow sweet pepper radish garlic brussels sprout groundnut summer purslane earthnut pea tomato spring onion azuki bean gourd. Gumbo kakadu plum komatsuna black-eyed pea green bean zucchini gourd winter purslane silver beet rock melon radish asparagus spinach.</p>
</div>
body {
  padding: 20px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

p {
  margin: 0 0 1em 0;
}

.container {
  width: 500px;
  border: 5px solid rgb(111,41,97);
  border-radius: .5em;
  padding: 10px;
  position: relative;
}

.item {
  width: 100px;
  height: 100px;
  background-color: rgba(111,41,97,.3);
  position: fixed;
  top: 20px;
  left: 20px;
}

為了使一個固定定位的元素不相對于視口進行定位,你需要為容器元素設置transform、perspective、filter三個屬性之一(不為默認值none)。這樣固定的元素就會相對于該塊級元素偏移,而非視口。

3.4 STICKY 定位

設置position: sticky會讓元素在頁面滾動時如同在正常流中,但當其滾動到相對于視口的某個特定位置時就會固定在屏幕上,如同fixed一般。這個屬性值是一個較新的CSS屬性,在瀏覽器兼容性上會差一些,但在不兼容的瀏覽器中會被忽略并會退到正常的滾動情況。

.item {
    position: sticky;
    top: 0;
}
<div class="container">
  
  <p>Pea horseradish azuki bean lettuce avocado asparagus okra. Kohlrabi radish okra azuki bean corn fava bean mustard tigernut jícama green bean celtuce. </p>
  
  <div class="item"></div>
  <p>Grape silver beet  collard greens avocado quandong fennel gumbo black-eyed pea watercress potato tigernut corn groundnut. Chickweed okra pea winter purslane coriander yarrow sweet pepper radish garlic brussels sprout groundnut summer purslane earthnut pea tomato spring onion azuki bean gourd. Gumbo kakadu plum komatsuna black-eyed pea green bean zucchini gourd winter purslane silver beet rock melon radish asparagus spinach.</p>
  
   <p>Grape silver beet  collard greens avocado quandong fennel gumbo black-eyed pea watercress potato tigernut corn groundnut. Chickweed okra pea winter purslane coriander yarrow sweet pepper radish garlic brussels sprout groundnut summer purslane earthnut pea tomato spring onion azuki bean gourd. Gumbo kakadu plum komatsuna black-eyed pea green bean zucchini gourd winter purslane silver beet rock melon radish asparagus spinach.</p>
  
   <p>Grape silver beet  collard greens avocado quandong fennel gumbo black-eyed pea watercress potato tigernut corn groundnut. Chickweed okra pea winter purslane coriander yarrow sweet pepper radish garlic brussels sprout groundnut summer purslane earthnut pea tomato spring onion azuki bean gourd. Gumbo kakadu plum komatsuna black-eyed pea green bean zucchini gourd winter purslane silver beet rock melon radish asparagus spinach.</p>
</div>
body {
  padding: 20px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

p {
  margin: 0 0 1em 0;
}

.container {
  width: 500px;
  border: 5px solid rgb(111,41,97);
  border-radius: .5em;
  padding: 10px;
  position: relative;
}

.item {
  width: 100px;
  height: 30px;
  background-color: rgba(111,41,97,.3);
  position: sticky;
  top: 0;
  width: 100%;
}

3.5 關于定位(positioning)的其他閱讀資料

4 彈性布局(Flex Layout)

彈性盒子(Flexbox)布局是一種為一維布局而設計的布局方法。一維的意思是你希望內容是按行或者列來布局。你可以使用display: flex來將元素變為彈性布局。

.container {
    display: flex;
}

該容器的直接子元素會變為彈性項(flex item),并按行排列。

<div class="container">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
</div>
body {
  padding: 20px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

* {box-sizing: border-box;}

p {
  margin: 0 0 1em 0;
}

.container {
  width: 500px;
  border: 5px solid rgb(111,41,97);
  border-radius: .5em;
  padding: 10px;
  display: flex;
}

.item {
  width: 100px;
  height: 100px;
  padding: 10px;
  background-color: rgba(111,41,97,.3);
  border: 2px solid rgba(111,41,97,.5);
}

4.1 彈性盒子的軸(axes)

在上面的例子中,我們會稱彈性項在行內是從起始位置開始排列,而不是說它們是左對齊。這些元素會按行排列是因為默認的flex-direction值為row,row代表了文本的行文方向。由于我們工作的環境是英文(中文也是如此),一種自左向右的語言,行的開始位置就是在左邊,因此我們的彈性項也是從左邊開始的。因此flex-direction的值被定義為彈性盒子的主軸(main axis)。

交叉軸(cross axis)則是和主軸垂直的一條軸。如果你的flex-direction是row并且彈性項是按照行內方向排列的,那么交叉軸就是塊級元素的排列方向。如果flex-direction是column那么彈性項就會以塊級元素排列的方向排布,然后交叉軸就會變為row。

如果你習慣于從主軸與交叉軸的角度來使用彈性盒子,那么一切會變得非常簡單。

4.2 方向和次序

彈性盒子模型讓我們可以通過為flex-direction屬性設置row-reverse或column-reverse值來改變主軸上彈性項的方向。

<div class="container">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
</div>
body {
  padding: 20px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

* {box-sizing: border-box;}

p {
  margin: 0 0 1em 0;
}

.container {
  width: 500px;
  border: 5px solid rgb(111,41,97);
  border-radius: .5em;
  padding: 10px;
  display: flex;
  flex-direction: row-reverse;
}

.item {
  width: 100px;
  height: 100px;
  padding: 10px;
  background-color: rgba(111,41,97,.3);
  border: 2px solid rgba(111,41,97,.5);
}

當然,你也可以通過order屬性來改變某一個彈性項的順序。但是要特別注意,這可能會給那些通過鍵盤(而非鼠標或觸屏)訪問你的網站的用戶帶來一些麻煩,因為按tab按鈕選擇元素的順序是頁面內元素在源碼中的順序而非顯示順序。你可以閱讀之后的“顯示和文檔順序”部分來了解更多相關內容。

4.3 一些Flex的屬性

這些flex的屬性是用來控制彈性項在主軸上空間大小的。這三個屬性是:

  • flex-grow
  • flex-shrink
  • flex-basis

通??梢允褂盟鼈兊暮唽懶问剑篺lex。第一個值代表flex-grow,第二個是flex-shrink,而第三個則是flex-basis。

.item {
    flex: 1 1 200px;
}

flex-basis會為彈性項設置未拉伸和壓縮時的初始大小。在上面的例子中,大小是200px,因此我們會給每個項200px的空間大小。但是大多數情況下容器元素大小不會正好被分為許多200px大小的項,而是可能有一些不足或剩余空間。flex-grow和flow-shrink屬性允許我們在容器過大或過小時控制各項的大小。

如果flex-grow的值是任意的正數,那么彈性項會被允許拉伸來占據更多的空間。因此,在上面的例子中,當各項被設為200px后,所有多余的空間會被每個彈性項平分并填滿。

如果flex-shrink的值為任意的正數,那么當彈性項被設置了flex-basis后,元素溢出容器時會進行收縮。在上面這個CSS的例子中,如果容器空間不足,每個彈性項會等比例縮放以適應容器的大小。

flex-grow和flex-shrink的值可以是任意的正數。一個具有較大flex-grow值的彈性項會在容器有剩余空間時拉伸更大的比例;而一個具有更大flex-shrink值的項則會在容器空間不足時被壓縮的更多。

<div class="container">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
</div>
body {
  padding: 20px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

* {box-sizing: border-box;}

p {
  margin: 0 0 1em 0;
}

.container {
  width: 500px;
  border: 5px solid rgb(111,41,97);
  border-radius: .5em;
  padding: 10px;
  display: flex;
}

.item {
  flex: 1 1 0;
  width: 100px;
  height: 100px;
  padding: 10px;
  background-color: rgba(111,41,97,.3);
  border: 2px solid rgba(111,41,97,.5);
}

.container :first-child {
  flex: 2 1 0; 
}

理解這些屬性是理解如何使用彈性布局的關鍵,下面列出的一些資源會幫助我們進一步學習其中的細節。當你需要在容器的一個維度上拉伸或者壓縮一些元素時,你可以考慮使用彈性盒子模型。如果你發現你正嘗試在行和列兩個維度上排列你的內容,你需要的是網格模型(grid),這時彈性盒子模型很可能不是最合適的工具了。

4.4 關于彈性盒子布局的其他閱讀資料

5 網格布局(grid layout)

CSS網格布局(grid layout)是一種用來進行二維布局的技術。二維(two-dimesional)意味著你希望按照行和列來排布你的內容。和彈性盒子類似,網格布局也需要設置一個display值。你可以為容器元素設置display: grid,并且使用grid-template-columns和grid-template-rows屬性來控制網格中的行與列。

.container {
    display: grid;
    grid-template-columns: 200px 200px 200px;
    grid-template-rows: 200px 200px;
}

上面這段CSS會創建一個行列元素大小固定的網格。不過這也許并不是你希望的。默認值為auto,你可以認為這代表了“對于內容格子足夠大”。如果你沒有指定行(row track)的大小,所有添加進來的行內容大小都會被置為auto。一種常用的模式是為網格制定列寬度,并允許網格按需添加行。

你可以使用任意的長度單位或時百分比來設置行與列,同時你可以使用為網格系統所創造的新的單位——fr。fr是一種彈性單位,它可以指定網格容器內的空間被如何劃分。

網格會替你計算與分配空間,你不需要去計算元素的百分比去適應容器大小。在下面這個例子中,我們使用fr來創建網格的列,這使得網格的列可以自適應。同時我們還使用了grid-gap來保證元素間的間距(關于網格內元素與的間距會在“對齊”這一部分詳細介紹)。

<div class="container">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5<br>has more content.</div>
</div>
body {
  padding: 20px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

* {box-sizing: border-box;}

p {
  margin: 0 0 1em 0;
}

.container {
  width: 500px;
  border: 5px solid rgb(111,41,97);
  border-radius: .5em;
  padding: 10px;
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-gap: 20px;
}

.container > div {
  padding: 10px;
  background-color: rgba(111,41,97,.3);
  border: 2px solid rgba(111,41,97,.5);
}

和Flexbox布局中的flex-grow和flex-shrink一樣,fr單位也是用來處理可用空間的分配問題。fr的值越高意味著在行列中可以獲得更高比例的空間。你也可以即使用fr單位又使用絕對長度單位。在計算fr單位長度之前,將從可用空間中減去其他長度單位所需的空間。

<div class="container">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5<br>has more content.</div>
</div>
body {
  padding: 20px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

* {box-sizing: border-box;}

p {
  margin: 0 0 1em 0;
}

.container {
  width: 500px;
  border: 5px solid rgb(111,41,97);
  border-radius: .5em;
  padding: 10px;
  display: grid;
  grid-template-columns: 1fr 2fr 100px;
  grid-gap: 20px;
}

.container > div {
  padding: 10px;
  background-color: rgba(111,41,97,.3);
  border: 2px solid rgba(111,41,97,.5);
}

5.1 關于網格的一些術語

網格系統總是有兩個軸:inline axis表示頁面中文字的文字排列的方向,block axis表示頁面中塊級元素的排列方向。

一個被設置為display: grid的元素就是所謂的網格容器。在網格容器中會有網格線(grid line),網格線就是你在指定grid-template-columns和grid-template-rows時網格中行列所生成的。網格中的最小單位(也就是被四條網格線截取生成的區域)被成為網格單元格(grid cell),進一步的,由若干個單元格組成的矩形區域被成為網格區域(grid area)。

網格線在行列之間
行列在網格線之間
網格單元是網格中最小的單位,網格區域是一個或多個網格單元組成的矩形區域

5.2 網格的自動排列規則

一旦你創建了網格,那么網格容器的直接子元素就會開始將它們自己一個一個地放置在網格的單元格中。子元素的放置是依據網格的自動排列規則(auto-placement rule)。這些規則確保了網格內元素是被安排在各個空的單元格中,而不會彼此遮蓋。

網格中任何沒有被進行定位的直接子元素都會根據自動排列規則進行放置。在下面這個列子中,我讓每三個元素中的第一個占據兩行,但仍然從起始行開始去自動排列。

<div class="container">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
  <div>6</div>
  <div>7</div>
  <div>8</div>
  <div>9</div>
</div>
body {
  padding: 20px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

* {box-sizing: border-box;}

p {
  margin: 0 0 1em 0;
}

.container {
  width: 500px;
  border: 5px solid rgb(111,41,97);
  border-radius: .5em;
  padding: 10px;
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-gap: 20px;
}

.container > div {
  padding: 10px;
  background-color: rgba(111,41,97,.3);
  border: 2px solid rgba(111,41,97,.5);
}

.container > div:nth-child(3n+1) {
  grid-row-end: span 2;
  background-color: rgba(193,225,237,.3);
  border: 2px solid rgba(193,225,237,.5);
}

5.3 基于行/列的基本定位方法

最簡單的布局元素的方法就是基于行列的布局方法,只要告訴瀏覽器從哪一行到哪一行進行合并就可以了。例如,現在又一個3行2列的表格,我們可以從第一行到第三行,第一列到第三列放置一個元素,這樣他就總共覆蓋4個網格單元,占用2行2列。

.item {
    grid-column-start: 1;
    grid-column-end: 3;
    grid-row-start: 1;
    grid-row-end: 3;
}

這些屬性可以用縮寫來表示:grid-column和grid-row,其中起一個值代表起始值,第二個值代表結束值。

.item {
    grid-column: 1 / 3;
    grid-row: 1 / 3;
}

你也可以讓網格項(grid item)占據同一個單元格。支持一些內容間會覆蓋的設計。網格項會像通常網頁中的元素那樣疊起來,在html源碼中下面的網格項會疊在其他元素上面。你仍然可以用z-index來控制它的堆疊順序。

<div class="container">
  <div class="one">1</div>
  <div class="two">2</div>
  <div class="three">3</div>
  <div class="four">4</div>
  <div class="five">5</div>
</div>
body {
  padding: 20px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

* {box-sizing: border-box;}

p {
  margin: 0 0 1em 0;
}

.container {
  width: 500px;
  border: 5px solid rgb(111,41,97);
  border-radius: .5em;
  padding: 10px;
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-gap: 20px;
}

.container > div {
  padding: 10px;
}

.one {
  grid-column: 1 / 4;
  grid-row: 1;
  background-color: rgba(111,41,97,.3);
  border: 2px solid rgba(111,41,97,.5);
}

.two {
  grid-column: 1 / 3;
  grid-row: 2;
  background-color: rgba(111,41,97,.3);
  border: 2px solid rgba(111,41,97,.5);
}

.three {
  grid-column: 2 / 4;
  grid-row: 2 / 5;
  background-color: rgba(193,225,237,.3);
  border: 2px solid rgba(193,225,237,.5);
}

.four {
  grid-column: 1;
  grid-row: 4 ;
  background-color: rgba(193,225,237,.3);
  border: 2px solid rgba(193,225,237,.5);
}

.five {
  grid-column: 3 ;
  grid-row: 4 / 5;
  background-color: rgba(111,41,97,.3);
  border: 2px solid rgba(111,41,97,.5);
}

5.4 通過命名區域來定位元素

你可以通過命名區域(named areas)來定位網格中的元素。要是用這種方式,你需要給每個元素一個名字,然后通過grid-template-areas屬性的值來描述布局方式。

.item1 {
    grid-area: a;
}

.item2 {
    grid-area: b;
}

.item3 {
    grid-area: c;
}

.container {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr 1fr;
    grid-template-areas: 
     "a a b b"
     "a a c c";
}

使用這種方式有幾個需要注意的點。如果你想要合并一些單元格作為你的網格項,你需要重復元素的名字。網格區域需要能形成一個完整的矩形 —— 每個單元格都需要被填入一個值。如果你想要空出某些單元格,那就需要使用.這個值。例如在下面的CSS里我將最右下角的單元格留空。

.container {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr 1fr;
    grid-template-areas: 
     "a a b b"
     "a a c .";
}

下面是demo示例

<div class="container">
  <div class="one">1</div>
  <div class="two">2</div>
  <div class="three">3</div>
  <div class="four">4</div>
  <div class="five">5</div>

</div>
body {
  padding: 20px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

* {box-sizing: border-box;}

p {
  margin: 0 0 1em 0;
}

.container {
  width: 500px;
  border: 5px solid rgb(111,41,97);
  border-radius: .5em;
  padding: 10px;
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-auto-rows: minmax(50px, auto);
  grid-gap: 20px;
  grid-template-areas: 
    "a a a"
    "b c c"
    ". . d"
    "e e d"
}

.container > div {
  padding: 10px;
  background-color: rgba(111,41,97,.3);
  border: 2px solid rgba(111,41,97,.5);
}

.one {
  grid-area: a;
}

.two {
  grid-area: b;
}

.three {
  grid-area: c;
}

.four {
  grid-area: d;
}

.five {
  grid-area: e;
}

5.5 關于網格布局的其他閱讀資料

這片文章只包括了CSS網格布局的一些初步內容,其中還有非常多的內容值得學習,下面的一些資料可以幫助你進一步學習。一些組件或整個頁面的布局都可以使用網格。如果你需要在兩個維度進行布局,網格布局是一個不錯的選擇 —— 不論需要布局的區域的大小。

  • CSS Grid Layout,” Web technology for developers, MDN web docs, Mozilla
  • Grid by Example,” Everything you need to learn CSS Grid Layout, Rachel Andrew
  • Grid Garden,” A fun interactive game to test and improve your CSS skills
  • Layout Land,” Jen Simmons, YouTube

我(作者)在Smashing Magazine也寫一些文章來幫助你深入理解各種網格的概念:

6 顯示順序和文檔順序(visual and document order)

在文章的最開始,我建議你以從上到下的閱讀順序來組織你的文檔順序,這樣會有助于可讀性和CSS的布局方式。從我們關于彈性盒子和CSS網格的簡短介紹來看,你可以發現用這些布局方法可能會極大地改變頁面展示的元素在文檔中的順序。這可能會導致一個隱含的問題。

在一些非可視化的應用場景中,瀏覽器會遵循文檔源碼來進行使用。因此,屏幕閱讀器會讀取文檔的順序,此外使用鍵盤tab鍵來瀏覽的用戶訪問文檔的順序是基于源碼的順序,而不是元素展示的順序。許多屏幕閱讀器的用戶并非完全失明,他們可能在使用屏幕閱讀器的同時也能夠看到這些元素在文檔的哪個部分。在這些情況下,當與源碼進行對比時,這種混亂的頁面展現可能會令人充滿迷惑。

當你改變了元素在文檔中原來的順序時,一定確保知道自己在做什么。如果你發現你自己正在CSS中重新排序你的元素,你應該去回頭看看是否要重新組織你的頁面元素。你可以通過使用tab訪問來測試一下你的頁面。

6.1 關于顯示順序和文檔順序的其他閱讀資料

7 盒模型的生成(box generation)

你寫在網頁里的任何東西都會生成一個盒子(box),這篇文章討論的所有東西其實都是如何能夠使用CSS來按照你的設計布局這些盒子。然而,在某些情況下,你可能根本不想創建一個盒子。有兩個display的屬性值會幫你處理這種情況。

7.1 不生成盒子或內容(display: none)

如果你希望元素以及它所有的內容(包括所有子元素)都不會生成,你可以使用display: none。這樣元素就不會被展示,并且不會保留其本該占有的空間。

.item {
    display: none;
}

7.2 不生成該元素,但是生成其所有子元素(display: contents)

display: content是display的一個新的屬性值。為一個元素應用display: content屬性會導致其自身的盒子不生成但所有的子元素都會照常生成。這有什么用呢?試想一下,如果你希望一個彈性布局或網格布局中的非直接子元素能應用這些布局,這就會非常有用。

在下面這個例子里,第一個彈性項包含了兩個子元素,由于它被設為display: contents,它的盒子不會生成并且它的兩個子元素會成為彈性項,并被當作彈性盒子容器的直接子元素來布局。

<div class="container">
  <div class="item">
    <div class="subitem">A</div>
    <div class="subitem">B</div>
  </div>
  <div class="item">2</div>
  <div class="item">3</div>
</div>
body {
  padding: 20px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

* {box-sizing: border-box;}

p {
  margin: 0 0 1em 0;
}

.container {
  width: 500px;
  border: 5px solid rgb(111,41,97);
  border-radius: .5em;
  padding: 10px;
  display: flex;
}

.item {
  flex: 1 1 200px;
  padding: 10px;
  background-color: rgba(111,41,97,.3);
  border: 2px solid rgba(111,41,97,.5);
}

.subitem {
  padding: 10px;
  background-color: rgba(193,225,237,.3);
  border: 2px solid rgba(193,225,237,.5);
}

.container .item:first-child {
  display: contents;
}

7.3 關于box generation的其他閱讀資料

8 對齊

在以前,要實現對齊往往會用到一些很"tricky"的方式,并且能夠使用的方法也非常有限。隨著CSS盒模型對齊(box alignment module)的出現,這一切都發生了變化。你將會使用它來控制網格容器與彈性盒子容器中的對齊。未來其他的各種布局方法都會應用這些對齊屬性。盒模型對齊(box alignment specification)規范中的一系列詳細屬性如下:

  • justify-content
  • align-content
  • place-content
  • justify-items
  • align-items
  • place-items
  • justify-self
  • align-self
  • place-self
  • row-gap
  • column-gap
  • gap

由于不同的布局模型有不同的特性,因此用于不同布局模型的對齊屬性會有一些表現上的差異。讓我們來看看在一些簡單的網格與彈性布局中對齊是如何工作的。

align-items和justify-items屬性相對是align-self和justify-self屬性的一種批量形式。這些屬性會控制與元素在其網格區域(grid area)中的對齊情況。

<div class="container">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div class="special">5</div>
</div>
body {
  padding: 20px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

* {box-sizing: border-box;}

p {
  margin: 0 0 1em 0;
}

.container {
  width: 500px;
  border: 5px solid rgb(111,41,97);
  border-radius: .5em;
  padding: 10px;
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-auto-rows: minmax(100px, auto);
  grid-gap: 20px;
  align-items: center;
  justify-items: start;
}

.special {
  grid-column: 2 / 4;
  align-self: end;
  justify-self: end;
}

.container > div {
  padding: 10px;
  background-color: rgba(111,41,97,.3);
  border: 2px solid rgba(111,41,97,.5);
}

align-content和justify-content屬性則會對網格中的行/列(tracks)進行對齊控制(網格容器中需要在排列完行/列元素后有多余的空間)。

<div class="container">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
</div>
body {
  padding: 20px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

* {box-sizing: border-box;}

p {
  margin: 0 0 1em 0;
}

.container {
  width: 500px;
  height: 300px;
  border: 5px solid rgb(111,41,97);
  border-radius: .5em;
  padding: 10px;
  display: grid;
  grid-template-columns: 100px 100px 100px;
  grid-auto-rows: minmax(100px, auto);
  grid-gap: 20px;
  align-content: space-between;
  justify-content: end;
}

.container > div {
  padding: 10px;
  background-color: rgba(111,41,97,.3);
  border: 2px solid rgba(111,41,97,.5);
}

在彈性盒子中,align-items和align-self用來解決交叉軸上的對齊問題,而justify-content則用于解決主軸上空間的分配。

<div class="container">
  <div>1</div>
  <div>2</div>
  <div class="special">3</div>
  <div>4</div>
</div>
body {
  padding: 20px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

* {box-sizing: border-box;}

p {
  margin: 0 0 1em 0;
}

.container {
  width: 500px;
  height: 300px;
  border: 5px solid rgb(111,41,97);
  border-radius: .5em;
  padding: 10px;
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
}

.special {
  align-self: stretch;
}

.container > div {
  padding: 10px;
  background-color: rgba(111,41,97,.3);
  border: 2px solid rgba(111,41,97,.5);
}

在交叉軸上,把彈性行(flex line)和額外空間包裹在彈性容器中之后,你就可以使用align-content了。

<div class="container">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
</div>
body {
  padding: 20px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

* {box-sizing: border-box;}

p {
  margin: 0 0 1em 0;
}

.container {
  width: 500px;
  height: 300px;
  border: 5px solid rgb(111,41,97);
  border-radius: .5em;
  padding: 10px;
  display: flex;
  flex-wrap: wrap;
  align-content: space-between;
}

.container > div {
  flex: 1 1 200px;
  padding: 10px;
  background-color: rgba(111,41,97,.3);
  border: 2px solid rgba(111,41,97,.5);
}

下面的一些鏈接更細節地討論了各類布局方法中的盒模型對齊。花些時間去理解對齊的工作原理是非常值得的,它對理解彈性盒子、網格布局以及未來的一些布局方法都會很有幫助。

8.1 行/列的間隔

一個多欄布局具有column-gap屬性,到目前位置,網格布局具有grid-column-gap、grid-row-gap和grid-gap。這些現在都被從grid標準中刪除而被添加進盒模型對齊中了。與此同時,grid-的前綴屬性被重命名為column-gap、row-gap和gap。瀏覽器會將帶有前綴的屬性換為新的重命名屬性,所以如果你在目前的代碼中使用兼容性更好的老名字也不用擔心。

重命名意味著這些屬性也能被應用于其他布局方法,一個明顯的備選就是彈性盒子。雖然目前沒有瀏覽器支持盒子模型中的gap屬性,但是在未來我們應該可以使用column-gap和row-gap來創建彈性項目元素間的間距。

8.2 關于box generation的其他閱讀資料

9 多欄布局(多列布局)

多欄布局(multi-column layout)是一種支持創建多欄的布局類型,如同報紙上那樣。每一塊都被分割成欄(column),你會按照塊方向在欄中往下讀然后會在回到下一欄的頂部。然而用這種方式閱讀在網頁內容中并不總是有效,因為人們并不想去讓滾動條滾動來、滾動去地去閱讀。當需要展示少部分內容、折疊一組復選框或者其他一些小的UI組件時會非常有用。

當展示一組高度不同的卡片或產品時多欄布局也非常有用。

9.1 設置欄的寬度

要設置一個最佳的欄寬,并通知瀏覽器依此寬度展示盡可能多的欄可以使用下面的CSS:

.container {
    column-width: 300px;
}

這會創建盡可能多的300px的欄,所有剩下的空間會被所有欄共享。因此,除非空間被劃分為300px時沒有剩余,否則你的欄會比300px稍多一些。

9.2 設置欄的數目

除了設置寬度,你可以使用column-count來設置欄的數目。在這種情況下,瀏覽器會將空間均分給你需要的數目的欄。

.container {
    column-count: 3;
}

如果你同時添加了column-width和column-count,那么column-count屬性會作為一個最大值限制。在下面的代碼里,欄會被添加直到達到三個,此時任何額外的空間都會被分給三欄,即使空間足夠成為一個額外的新欄。

.container {
    column-width: 300px;
    column-count: 3;
}

9.3 間距和欄規則

你無法為單個欄盒子添加外邊距和內邊距,需要用column-gap屬性來設置間距。如果你不具體指定column-gap的值,它會默認為1em來防止欄間碰撞。這和其他布局方法中column-gap的行為不一樣,其他布局中默認為0。你可以在間距上使用任意的長度單元,包括0(如果你不希望有欄間距)。

column-rule屬性讓你有能力向兩欄間添加規則。它是column-rule-width、column-rule-color和column-rule-style的簡寫形式,可border行為類似。注意,一個規則自身不會占用任何空間。它會占據在間距的頂部,從而增加或減少那些你設置column-gap的規則與內容間的空間。

div class="container">
  <p>Pea horseradish azuki bean lettuce avocado asparagus okra. Kohlrabi radish okra azuki bean corn fava bean mustard tigernut jícama green bean celtuce. </p>
  <p>Grape silver beet  collard greens avocado quandong fennel gumbo black-eyed pea watercress potato tigernut corn groundnut. Chickweed okra pea winter purslane coriander yarrow sweet pepper radish garlic brussels sprout groundnut summer purslane earthnut pea tomato spring onion azuki bean gourd. Gumbo kakadu plum komatsuna black-eyed pea green bean zucchini gourd winter purslane silver beet rock melon radish asparagus spinach.</p>
</div>
body {
  padding: 20px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

* {box-sizing: border-box;}

p {
  margin: 0 0 1em 0;
}

.container {
  width: 500px;
  border: 5px solid rgb(111,41,97);
  border-radius: .5em;
  padding: 10px;
  column-width: 120px;
  column-gap: 20px;
  column-rule: 4px dotted #000;
}

9.4 允許元素橫跨多欄

你可以使用column-span屬性讓多欄容器內的元素橫跨多欄,類似通欄。

h3 {
    column-span: all;
}

當column-span出現時,多欄容器分欄會在這個元素上放停下,因此,容器里的內容會在元素上方形成多欄樣式,然后在橫跨元素(spanning element)的下方形成一組新的欄盒子(column box)。

<div class="container">
  <p>Pea horseradish azuki bean lettuce avocado asparagus okra. Kohlrabi radish okra azuki bean corn fava bean mustard tigernut jícama green bean celtuce. </p>
  <h2>Veggies!</h2>
  <p>Grape silver beet  collard greens avocado quandong fennel gumbo black-eyed pea watercress potato tigernut corn groundnut. Chickweed okra pea winter purslane coriander yarrow sweet pepper radish garlic brussels sprout groundnut summer purslane earthnut pea tomato spring onion azuki bean gourd. </p>
</div>
body {
  padding: 20px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

* {box-sizing: border-box;}

p {
  margin: 0 0 1em 0;
}

.container {
  width: 500px;
  border: 5px solid rgb(111,41,97);
  border-radius: .5em;
  padding: 10px;
  column-width: 120px;
  column-gap: 20px;
  column-rule: 4px dotted #000;
}

.container h2 {
  column-span: all;
  background-color: rgba(193,225,237,.6);
  border:2px solid rgba(193,225,237,.6);
  margin: 1em 0;
  padding: .5em;
}

你只可以使用column-span: all或column-span: none,并不能讓元素橫跨某幾個欄(非通欄)。在文章寫作時,Firefox還不支持column-span屬性。

9.5 關于多欄布局的其他閱讀資料

10. 碎片化(Fragmentation)

多欄布局是碎片化(fragmentation)的一個例子,頁面內容會被拆分成欄。這和打印時內容被分到不同頁非常類似。這個過程是碎片化規范(Fragmentation specification)處理的。這個規范包括了一些幫助控制內容切分的屬性。

例如,如果你有一組置于多欄中的卡片,并且你想確??ㄆ粫唤貫閮砂敕值讲煌臋?,你可以使用break-inside屬性的avoid值??紤]瀏覽器兼容性的因素,你也可能會想使用遺留的page-break-inside屬性。

.card {
    page-break-inside: avoid;
    break-inside: avoid;
}

如果你想在heading元素后禁止斷行,你可以使用break-after屬性。

.container h2 {
    page-break-after: avoid;
    break-after: avoid;
}

這些屬性可以被用在打印樣式或多欄樣式中。在下面的例子里,在多欄容器中的三個段落被拆分到了三欄之中。我為p元素設置了break-inside: avoid,這意味著每個多欄會在自己的欄中結束(即使這會使各欄長度不同)。

<div class="container">
  <p>Pea horseradish azuki bean lettuce avocado asparagus okra. Kohlrabi radish okra azuki bean corn fava bean mustard tigernut jícama green bean celtuce. </p>
  <p>Grape silver beet  collard greens avocado quandong fennel gumbo black-eyed pea watercress potato tigernut corn groundnut. Chickweed okra pea winter purslane coriander yarrow sweet pepper radish garlic brussels sprout</p>
  
  <p>Groundnut summer purslane earthnut pea tomato spring onion azuki bean gourd. Gumbo kakadu plum komatsuna black-eyed pea green bean zucchini gourd winter purslane silver beet rock melon radish asparagus spinach.</p>
</div>
body {
  padding: 20px;
  font: 1em Helvetica Neue, Helvetica, Arial, sans-serif;
}

* {box-sizing: border-box;}

p {
  margin: 0 0 1em 0;
}

.container {
  width: 500px;
  border: 5px solid rgb(111,41,97);
  border-radius: .5em;
  padding: 10px;
  column-width: 120px;
  column-gap: 20px;
  column-rule: 4px dotted #000;
}

.container p {
  page-break-inside: avoid;
  break-inside: avoid;
}

10.1 關于碎片化的其他閱讀資料

11 如何選擇布局類型?

大多數的網頁會混合使用多種布局類型。各布局規范都準確定義了它們之間是如何相互作用的。例如,你可能會在網格布局的網格項中使用彈性布局。一些彈性容器可能具有定位屬性或浮動。這些規范根據最優的布局方式已經包含了布局模型的混合使用。在這篇指南中,我嘗試概述了這種布局類型的基本使用方式,來幫助你了解實現一個效果可能的最好方法。

然而,別害怕去運用多種方式來實現布局設計。擔心你的選擇會不會造成實際問題的情況比你想象中要少很多。所以請在開始就組織好你的文檔結構,并且注意你文檔內容的可視展示順序。剩下的大部分工作就是在瀏覽器中試試你的布局方式是否符合預期。

原文:Getting Started With CSS Layout,感謝作者Rachel Andrew。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 本文仍舊轉載于阮一峰老師 一、概述 網格布局(Grid)是最強大的 CSS 布局方案。 它將網頁劃分成一個個網格,...
    blossom_綻放閱讀 524評論 0 0
  • 原文地址 注:此文是我翻譯的第一篇技術文章。適合有一定CSS原生網格布局使用經驗的開發者(讀前需要先去了解一下原生...
    我不叫沒耐性閱讀 762評論 0 2
  • 簡介 CSS Grid布局 (又名"網格"),是一個基于二維網格布局的系統,旨在改變我們基于網格設計的用戶界面方式...
    咕咚咚bells閱讀 2,542評論 0 4
  • 相信大部分前端小伙伴已經有過使用 Grid 布局的體驗,一定是美滋滋。Flex 布局和 Grid 布局作為 CSS...
    藍線閱讀 3,810評論 0 3
  • 朋友圈每天都會曬出各種各樣的美食,精美的蛋糕,筋道的面皮,花樣繁多,讓你不由感慨,高手在民間。 當然,我們也不例外...
    趙粉溫閱讀 552評論 1 3