CSS 佈局模塊

在衆多瀏覽器剛剛支持 CSS 的時候,我就已經開始使用它了,而且應該算是最先採用 CSS 進行頁面佈局的開發者之一了。那時候,瀏覽器之間的兼容性雖然很差,但我仍然熱衷於嘗試層出不窮的新特性。最近幾年在 CSS 領域,咱們看到了許多重大進展。其中,web 字體、漸變、陰影和媒體查詢已經成爲了咱們平常工做流的必備工具。css

然而,CSS 佈局卻發展緩慢。開發者們曾經嘗試使用 display:table 和 display:inline-block 來佈局,用來緩解絕對定位和浮動佈局所帶來的束縛。然而,這些方法並不標準,所以它們又產生了新的問題。css3

CSS 佈局的將來看起來一片大好。在這篇文章中,我將會介紹 CSS 規範中一些激動人心的佈局模塊。在將來,咱們能夠更有效地實現網格佈局,更輕鬆地建立等高列或者均勻分配內容到整個頁面。相似 Adobe 的公司每每熟悉佈局設計的細節,藉助它們的幫助來制定相關規範,咱們就能更準確地控制頁面在瀏覽器上的顯示方式,同時避免對頁面內容的影響。web

對於本文中示例,我已經在一個或多個瀏覽器上進行了測試,固然你也能夠繼續測試它們。這些佈局模塊中的一部分可能還處於發展的初期階段,其具體實現將來可能還會有變化,因此,你也能夠就相關問題反饋給制定標準的團隊。這是咱們的 web,咱們應該熱衷於參與到制定規範的工做中。算法

若是你在線上產品中使用本書中的這些技巧,那麼你要確保頁面對低版本瀏覽器用戶一樣是友好的——即便這些低版本瀏覽器並不支持相關的佈局模塊。雖然我不想花過多的時間解決瀏覽器的兼容性問題,但在每一章節的最後,我會給你一些有用的建議和提示。瀏覽器

瀏覽器前綴

本文所涉及到的大部分屬性,都會須要多個瀏覽器前綴。對於那些規範比較穩定的佈局模塊,好比多列布局和 flexbox 佈局,我會使用 Lea Verou 的 -prefix-free 腳本,從而只須要演示標準屬性,也能夠實現跨瀏覽器的兼容性。對於線上產品,我建議你要麼爲 CSS 添加瀏覽器前綴,要麼使用 CSS 預處理器將瀏覽器前綴編譯到最終的 CSS 文件中。app

對於那些很是新的佈局模塊(只被個別瀏覽器所支持,相關規範頻繁變更的佈局模塊),我會爲其添加所測試瀏覽器的前綴。在本書出版之時,經過添加特定瀏覽器前綴,其餘瀏覽器可能也已經支持相關佈局模塊了。鑑於這些佈局模塊的實驗性特徵,因此在不一樣瀏覽器上可能會有不一樣的渲染結果。應該儘量地爲其餘瀏覽器使用前綴並作相關的測試,最後在線上產品中還要加上無前綴的相關屬性。ide

多列布局

CSS3 的多列布局已經風靡多年,然而,因爲 IE 的不支持,它並無得到預期的受歡迎程度。在 IE10 支持這些特性以後,它對於響應式設計就顯得更爲有用了——很是期待它能流行起來。多列布局模塊是本書提到的全部模塊中,技術最成熟、瀏覽器支持度最高的一個模塊,因此從它開始講述 CSS 中的新佈局模塊是一個不錯的選擇。工具

多列布局使內容均勻分散到多列成爲可能,它很是相似於報紙中的「內容流動」效果。首先,你須要在文檔中選擇一個容器(container),而後聲明該容器具備多列布局,那麼瀏覽器就能實現預期的多列效果。若是你爲內容(content)指定了列數,瀏覽器就會自動計算出每一列的寬度,自動適應父級元素的尺寸;若是你指定了每一列的寬度,那麼瀏覽器就會自動計算列數,當父級元素尺寸發生變化,瀏覽器還能夠自動從新計算。佈局

示例:設置 column-width學習

.col-wrapper {
    column-width: 220px;
}

CSS佈局模塊

設置 column-width 屬性意味着要求瀏覽器儘量多地爲容器建立縱列(columns),而開發者指定的寬度則會被視爲理想寬度。你可能已經注意到了,當咱們指定單列的寬度時,實際上並無獲得預期的寬度。多列之間每每填充了空白(space),這有助於瀏覽器根據指定的寬度計算最合適的列數。CSS 多列規範中是這樣解釋的:

column-width的值指定了最理想的單列寬度。實際的單列寬度可能會更寬一些(多列之間填充了空白),或更窄一些(只有可用寬度小於指定寬度時纔會出現這種狀況)。該屬性的指定值必須大於 0。」

所以,當須要設定單列寬度時,你只需指定一個理想寬度便可,由於爲了設計的靈活性,實際寬度可能會出現一些差別。

示例:設置 column-count

你也可使用 column-count 指定所須要的列數,而後讓瀏覽器自行決定單列寬度。

.col-wrapper { 
    column-count:3; 
}

CSS佈局模塊

調節間距

在上面的例子中,你會發現多列之間並無牢牢相鄰:這是由於多列之間存在間距(gap)。在多列布局中,間距是由 column-gap 屬性控制的。若是將 column-gap 設爲 0,那麼多列之間就不會有間距,全部的文字會擁擠在一塊兒。規範中建議瀏覽器在默認樣式中爲該屬性預設 1em 的寬度。不過,若是讓多列的間距保持一致性,那麼你應該顯式地爲該屬性設定一個值。

示例:設置 column-gap 

.col-wrapper { 
    column-width: 220px; 
    column-gap: 1.5em; 
}

美化多列布局

在最新的規範中已經限制了對多列布局的美化。不過,相關的工做草案也提示說:「或許在將來的規範中會添加額外的功能。好比,容許多列中的任意一列設置不一樣的寬度和背景。」目前來講,你還不能單獨地美化多列中的某一列。

雖然無法設置單列的內外邊距、寬度和背景色,可是咱們可使用一些規則來隔離多列。實現這一佈局效果須要使用 column-rule 屬性:

  • column-rule-style
  • column-rule-width
  • column-rule-color

這些屬性的用法很是相似 border-styleborder-width 和 border-color,並且也可使用 column-rule 屬性做爲一種簡寫形式:

column-rule: [width] [style] [color];

上面的縱列屬性(column rules)將會被應用到 column-gap 上。要想修改縱列兩邊的空白間距,就須要調整 column-gap 的屬性值。若是上述縱列屬性的值大於可用間距,那麼它就會與文本區重疊——但它不會佔用任何的空間。

示例:使用 column-rule

CSS佈局模塊

單列跨度(span)

若是你想讓某一個元素延伸到全部的縱列中,那麼能夠爲該元素添加 column-span 並賦值爲 all。在下面的示例中,我要讓 h1 標題能夠延伸到全部的縱列上。

示例:強制 h1 延伸到多列

.col-wrapper h1 { 
    column-span: all; 
    padding: 0 0 .5em 0; 
}

當前的規範中 column-span 只有兩個值:all 和 none

CSS佈局模塊

多列截斷

當使用多列布局的時候,你須要控制多列截斷的方式。若是不但願某些元素被截斷到新的縱列,或者確保某個元素固定在某一列時,下面的這個屬性對你就會頗有幫助。

示例:避免在段落內和引用塊以前被截斷

.col-wrapper p { 
    break-inside: avoid; 
} 
.col-wrapper blockquote { 
    break-before: avoid; 
}

印刷和分頁媒體類型

規範指出,多列布局內部的元素不該該出如今下一頁上。若是閱讀時翻到了下一頁,而後讓用戶再返回前一頁繼續閱讀,那麼這樣的體驗就太讓人惱火了。

你能夠預設分頁時段落或者元素內部內容的佈局方式——就像控制多列截斷同樣。屬性 avoid-page 和 avoid-column 就能夠幫助你實現良好的控制。若是你容許段落進行截斷而不容許內容分頁,那麼對於上面的例子,就可使用 break-inside: avoid-page 替代 break-inside: avoid;

響應式設計

因爲多列默認就是響應式的,因此多列布局也有助於實現響應式設計。正如咱們所知,雖然能夠根據需求設定單列寬度,但本質上瀏覽器會使用本身的算法,計算出一個用於渲染的寬度。

單列內的圖片會被限制在單列範圍以內,因此使用 max-width 設置的最大寬度也被侷限在單列以內。若是你沒有爲圖片設置 max-width: 100%;,同時圖片的寬度還大於單列寬度,那麼瀏覽器就會自動裁剪掉多餘的部分。該規則一樣適用於其餘寬度大於單列寬度的元素。

示例:圖片寬度限制於單列以內

CSS佈局模塊

必定不要認爲多列布局模塊只適用於建立相似報紙的版式。下面示例中的多列布局,就包含了一系列的盒模型和圖片。

示例:盒模型和圖片

CSS佈局模塊

下面的示例演示瀏覽器視口較窄時的單列布局,無需編寫額外的代碼便可實現。

CSS佈局模塊

瀏覽器提示

當我寫下這些文字的時候,還只有幾個瀏覽器支持多列布局。所以,有時你須要添加瀏覽器前綴才能使用這些屬性,此外,在有一些狀況下某些屬性並不會生效。更多更新的瀏覽器支持信息,能夠查看 Can I Use。若是瀏覽器不支持多列布局,那麼它在解析樣式表時就會忽略相關屬性,所以能夠放心使用這些屬性。不支持多列布局的瀏覽器會將內容渲染爲單列,這種渲染結果在大多數狀況下也是能夠接受的——不建議使用膩子腳本模擬多列布局效果。

CSS Flexbox佈局

CSS 彈性盒佈局模塊,一般被稱爲 flexbox,爲咱們提供了一種新的佈局——flex 佈局。設計該佈局的初衷是爲了簡化複雜應用和頁面的佈局代碼。在本節中,我將會着重介紹一些使用 flexbox 解決的佈局問題。

均勻排列

在傳統的佈局設計中,將一組佈局元素沿座標軸均勻排列是件很麻煩的工做。若是使用浮動佈局,那麼每一個浮動元素都必須設置一個寬度,不然就會寬窄不一,此外,每每須要使用 JavaScript,才能讓全部的浮動元素均勻排列在同一行上。

Flexbox 極大簡化了這一佈局過程。在下面的示例中,我使用無序列表建立了一個導航條。

示例:flexbox 簡單用法

<nav class="mainnav"> 
    <ul> 
        <li><a href="">Introductory</a></li> 
        <li><a href="">The First Cat Show</a></li> 
        <li><a href="">Habits</a></li>

        <li><a href="">Trained Cats</a></li> 
        <li><a href="">Usefulness of Cats</a></li> 
    </ul> 
</nav>

對於這個導航條,我想實現水平均勻分佈的效果。若是咱們選擇 flexbox 佈局方式,那麼只須要添加 display:flex 屬性,並指定佈局元素的排列方式(全部元素平均排列或者除首尾元素外平均排列)。

示例:flexbox 簡單用法

nav ul{
    margin: 0;
padding: 0;
list-style: none;
display: flex;
justify-content: space-between;
}

CSS佈局模塊

在這裏,咱們將 justify-content 設置成了 space-around,這樣作的好處就是讓每個元素之間具備相同的間距,避免了溢出容器的問題。此外,在第一個元素以前和最後一個元素以後,也添加了相同的間距。

CSS佈局模塊

上面的示例使用了一些 flexbox 的默認屬性,好比這裏的佈局元素默認顯示爲水平排列。這個默認的排列效果等同於添加了 flex-direction: row 的效果。

flex-direction 屬性一共擁有四個屬性值:rowrow-reversecolumn 和 column-reverse。使用這些屬性,能夠實現水平排列、反向水平排列、垂直排列和反向垂直排列四種佈局效果。

nav ul {
    margin: 0;
    padding: 0;
    list-style: none;
    display: flex;
    justify-content: space-between;
    flex-direction: row-reverse;
}

CSS佈局模塊

使用 flexbox 的另外一個優點在於,它能夠幫你建立等高容器——即便容器內的文字不等長。align-items 的默認屬性值爲 stretch,它會根據 flexbox 內最高元素的高度,拉伸其餘佈局元素,使之等高。在個人導航示例中,若是你縮窄窗口,文字就會自適應爲多行,但仍然保持等高拉伸的佈局——從全部元素的邊框就能夠看出他們是等高的。

CSS佈局模塊

align-items 的全部屬性值:

  • flex-start
  • flex-end
  • center
  • baseline
  • stretch

爲了理解其正確的解析方式,你須要首先理解 flexbox 中的兩個軸概念:主軸和側軸,其中主軸用來控制元素的佈局方向。經過將 flex-direction 設置爲 row 或者 column,能夠指定主軸,並肯定佈局元素的排列方向:從左到右或者從上到下;第二條軸,即側軸,垂直於主軸。

若是將 flex-direction 設爲 row,那麼主軸方向就是從左到右的。設置 align-items 爲 flex-end,意味着佈局元素不會佔據佈局容器的所有高度,全部的佈局元素在底部對齊,不作等高處理。

CSS佈局模塊

多行 flexbox

在以前的這個示例中,若是咱們將瀏覽器縮窄,那麼佈局元素內的文字就會在佈局元素內拆分紅多行。究其緣由,是由於佈局元素的內容寬度超過了可用空間。一種可行的解決方案就是將佈局容器設爲 wrap(表現爲多行效果)。

在 flexbox 佈局中,使用 flex-wrap 屬性能夠控制佈局容器的多行模式,可用的屬性值包括 wrapnowrap 和 wrap-reverse。若是沒有顯式聲明該屬性值,那麼 flex-box 默認爲 nowrap

示例:佈局容器的多行模式

nav ul{ 
    margin: 0; 
    padding: 0; 
    list-style: none; 
    display: flex; 
    justify-content: space-between; align-items: stretch; flex-direction: row-reverse; 
    flex-wrap: wrap;
}

CSS佈局模塊

然而,從圖中能夠發現,相鄰佈局元素之間出現了意料以外的不規則空隙。修正這種表現的方式是爲佈局元素添加額外的佈局間距。爲佈局元素設置 flex: auto; 便可實現這一目標——在咱們的示例中,我爲 li 元素添加了該屬性。

nav li {
    border: 1px solid #999; 
    border-radius: 2px; 
    flex:auto;
    margin: 0 1em 1em 0; 
    text-align: center;
}

CSS佈局模塊

使用 flex 屬性

雖然爲佈局元素設置 flex: auto; 能夠調整它們在佈局容器內的空間排列,但該屬性的做用遠不止如此,這裏將會介紹幾種其餘的用法。

在下面的示例中,我編寫了三個塊級元素,塊級元素內部是一些關於長毛貓品種的信息。此外,我還爲塊級元素添加了公有的類名 box 和獨立的類名,便於選擇特定的塊級元素。

示例:三個塊級元素

<div class="boxes">
    <div class="box box1">
        <h2>The Angora</h2>
        <p>... </p> 
    </div>
    <div class="box box2"> 
        <h2>The Persian Cat</h2> 
        <p>... </p>
    </div>
    <div class="box box3">
        <h2>The Russian Long-haired Cat</h2>
        <p>... </p> 
    </div>
</div>

爲了讓全部的塊級元素在單行內排列,我將佈局容器,即 boxes,設爲了 flex 元素,而後爲容器內的每一個元素設置 flex: 1。設置完成後,全部的佈局元素就都具備了相同的寬度。

.boxes {
    display: flex;

    flex-direction: row;

    flex-wrap: wrap;

    align-items: stretch; 
    justify-content: space-between; 
} 
.box {
    border: 1px solid #999; 
    border-radius: 5px; 
    flex: 1;

    margin: 0 1em 1em 1em; 
    padding: 10px; 
}

CSS佈局模塊

此外,咱們可能須要讓某個佈局元素寬於其餘佈局元素,同時還要根據可用的容器空間計算各個佈局元素的寬度。示例中的第三個塊級元素擁有一個類名 box3,若是爲 box3 添加 flex 屬性並賦值爲 2,那麼相比於 flex: 1; 的佈局元素,它就會具備兩倍的寬度。

.box3 {
    flex: 2;
}

CSS佈局模塊

爲 flex 佈局元素排序

從前面的介紹中,咱們已經瞭解到 flex 佈局元素是能夠反向排列的。實際上,咱們能夠爲每一個獨立的佈局元素設置任意的排列順序,其中的關鍵,就須要用到下面介紹的 order 屬性。

經過爲每一個佈局元素設置 order 屬性,我能夠輕鬆移動 box3。只須要爲其添加 order: 2;,就能夠將這個最寬的佈局元素移動到容器中央。

.box1 {
    order: 1;
}
.box2 {
    order: 3;
}
.box3 { 
    flex: 2; 
    order: 2; 
}

CSS佈局模塊

雖然咱們更改了渲染後的佈局順序,但實際上它的 HTML 結構仍舊保持不變。這意味着你能夠根據實際需求來編寫 HTML 結構,這樣作有助於提升可用性,改善使用文本閱讀器的用戶體驗。此外,使用該屬性還能夠建立出色的佈局效果。

響應式設計

對於響應式設計,flexbox 是一種優秀的可選方案。因爲它具備包裹多行、自適應可用空間的特色,可讓咱們不費吹灰之力就建立出簡單的響應式效果。

若是你在 flexbox 中混合媒體查詢的功能,那麼就能夠建立出更復雜的佈局效果。因爲能夠按照不一樣於源碼的結構來顯示佈局元素,因此咱們可以在不一樣尺寸的屏幕上建立不一樣的佈局效果。此外,也能夠像下面的示例同樣,使用 flex-direction 來轉換佈局方向。最初,咱們可讓導航顯示爲垂直排列,當窗口寬度大於 700px時,咱們就能夠將其轉換爲水平排列。

nav ul{
    margin: 0;
    padding: 0; 
    list-style: none; 
    display: flex; 
    flex-direction: column;
    justify-content: space-between;
    align-items: stretch; 
}
@media only screen and (min-width: 700px) { 
    nav ul {
        flex-direction: row; 
    }
}

瀏覽器提示

Flexbox 是一個極佳的案例,展現了 CSS 規範在初期的演變方式。因爲 flexbox 的具體實現和最初構想之間已經發生了諸多變更,因此在 flexbox 的可用性上存在大量無效的資料。當你須要檢索有關 flexbox 的資料時,能夠查看一下 CSS Tricks 上的相關文章,便於檢驗當前資料的準確性。

當瀏覽器不支持 flexbox 時,一方面可使用 JavaScript 來模擬 flexbox 的大量特性,另外一方面你也可讓瀏覽器優雅降級,讓佈局元素呈現一種線性排列,下圖就是以前的佈局元素在瀏覽器不支持 flexbox 時的渲染效果。

CSS佈局模塊

若是你只是將 flexbox 佈局模塊應用於少許的界面元素,而不是總體佈局,那麼優雅降級爲線性排列是比較簡單的。另外一種方式是使用 Modernizr 檢測瀏覽器是否支持 flexbox,而後分別爲支持和不支持 flexbox 的狀況編寫不一樣的 CSS 代碼。

CSS 網格佈局

CSS 網格佈局模塊是由微軟提議的,目前仍在進行大量的規範化工做。該模塊的最新進展已經應用到了 Internet Explorer 10 上,因此本部分的實例演示都會基於 IE10。

網格佈局旨在解決複雜網頁的佈局問題——在該佈局提出以前,咱們只能經過元素的浮動和定位來模擬複雜佈局。網格佈局也容許開發者顯示與源碼結構不一樣的佈局結構——相似上一章節的 flexbox 佈局。我很喜歡網格佈局,但願你在閱讀完下面的示例以後也會喜歡它。

建立網格

將佈局元素包裹進網格的第一步,就是在它們的父元素上建立網格。首先須要添加 display: grid;(一般我會加上 -ms- 前綴),而後設置所需的網格行數和列數。

示例:一個簡單的網格佈局

.wrapper {
    display: -ms-grid;
    -ms-grid-columns: 200px 20px auto 20px 250px; 
    -ms-grid-rows: auto 1fr;
}

上面的 CSS 代碼在 .class 元素上建立了網格,該網格擁有五個縱列:一個 200px 寬度的側列,一個 20px 寬度的間距,一個自適應寬度的中間縱列,另外一個 20px 寬度的間距,以及最後一個 250px 寬度的縱列。因而可知,這是由兩個固定寬度的縱列和一個可變寬度的中間縱列構成的簡單佈局。

在橫列上,我將第一列設爲了 auto——它將根據內部內容自動擴展高度,將第二列設爲了 1fr1fr 準確的說是一個分數比值,在這裏意味着第二列在剩餘空間所佔的比重。因而可知,這是具備兩個橫列的佈局。

如今,咱們能夠往網格里添加一些內容了。添加內容後的結構以下:

<div class="wrapper"> 
    <nav class="mainnav"> 
        <ul>
            <li><a href="">Introductory</a></li> 
            <li><a href="">The First Cat Show</a></li> 
            <li><a href="">Habits</a></li>
            <li><a href="">Trained Cats</a></li> 
            <li><a href="">Usefulness of Cats</a></li>
        </ul> 
    </nav>
    <h2 class="subhead">Usefulness of cats</h2> 
    <article class="content">
        <p>...</p>
    </article>
    <blockquote class="quote">
        <p>....</p> 
    </blockquote>
</div>

爲了將導航定位到左側固定寬度的縱列上,將文章部分定位到中間的縱列上,將引用定位到右邊的縱列上,我又添加了以下的樣式:

.mainnav { 
    -ms-grid-column: 1; 
    -ms-grid-row: 2;
}
.subhead { 
    -ms-grid-row: 1; 
    -ms-grid-column:3;
}
.content { 
    -ms-grid-column: 3; 
    -ms-grid-row: 2;
}
.quote { 
    -ms-grid-column: 5; 
    -ms-grid-row: 2;
}

上面所作的處理就是在指定具體的內容所對應的縱列。必定要牢記,間距也是縱列,因此主內容區的是在第三列上,最右側的縱列是第五列。

CSS佈局模塊

當我嘗試理解這種網格佈局時,我發現將其設想爲傳統的表格佈局會頗有幫助,不一樣之處在於網格佈局是在 CSS 中實現的。而後,我要作的是將佈局元素放入表格單元,不過,不一樣於表格佈局,爲了適配不一樣尺寸的顯示屏幕,在 CSS 中從新定義網格結構是更加方便的。這意味着在未來,網格佈局會成爲響應式設計強有力的工具。

網格和響應式設計

如今,我要在這裏涉及一些複雜的佈局——這些佈局更具備實用性,展現網格佈局在響應式設計中的實際應用。

示例中使用的文檔結構很簡單:一個添加了 wrapper 類名的 div 標籤;五個添加了 box 類名的 div 標籤,標籤內添加了一些內容;以及一張關於貓的圖片標籤——圖片來自維多利亞時代的書籍。爲了簡單起見,我給每一個 box 元素都添加了第二個類名,便於在 CSS 中對其進行定位和檢索。

示例:一個響應式的網格佈局

<h1 class="title">Extracts from "Our Cats, by Harrison Weir"</h1> 
<div class="wrapper">
    <div class="box content1"> 
        <h2>The first cat show</h2> 
        <p> ...</p>
    </div>
    <div class="box content2">
        <h3>The Angora</h3>
        <p>... </p> 
    </div>
    <div class="box content3"> 
        <h3>The Persian Cat</h3> 
        <p>... </p>
    </div>
    <div class="box content4">
        <h3>The Russian Long-haired Cat</h3> 
        <p>...</p>
    </div>
    <div class="box picturebox">
        <figure>
            <img src="fluffy.jpg" alt="Fluffy the cat" /> 
            <figcaption>Fluffy, the cat</figcaption>
        </figure>
    </div> 
</div>

只須要使用少許基礎的 CSS 屬性作一下美化,咱們就獲得了一個以下圖所示的線性設計(linearised design)。

CSS佈局模塊

下面,須要定義網格了。我是經過給 .wrapper 添加相關的屬性實現的:

.wrapper {
    width: 90%;
    margin: 0 auto 0 auto;
    display: -ms-grid;
    -ms-grid-columns: 1fr (4.25fr 1fr)[6]; 
    -ms-grid-rows: (auto 20px)[4];
}

經過設置 display: -ms-grid;,表示了該元素內部包含一個網格佈局。經過使用一個簡寫形式的多列語法,我建立了多個縱列。將有關縱列的參數集合放入圓括號內,其後跟一個參數爲數字的中括號,這種語法表示咱們想要重複設定某種縱列類型:在這個示例中,這意味着我將這兩個縱列重複了六次。縱列之間的間距被設定爲 1 個分數單位,而縱列則擁有 4.75 個分數單位的寬度。

而後,我使用相同的語法設定了橫列,建立了一個根據內容自適應高度的橫列,其後跟着一個 20px 寬度的間隙,最後將上述的橫列格式重複了四次。

若是添加完上述的 CSS 後刷新頁面,你會發現全部的縱列都被摺疊了。這是由於全部的佈局元素都嘗試去填充第一縱列和第一橫列,咱們須要進一步爲佈局元素設定定位信息。一旦你爲某個元素聲明瞭網格信息,那麼全部的子元素就都須要在網格中進行定位。

CSS佈局模塊

爲了適配小尺寸的屏幕,我將從元素定位開始作佈局。因爲用戶使用小尺寸設備時是從上到下閱讀的,因此我會按照源碼中的內容順序來佈局,而對於使用屏幕閱讀器的用戶,我會根據內容的重要性來安排佈局順序。在分離源碼結構和佈局結構這個新領域,我無需過多擔憂視覺效果背後的源碼結構。

.content1 {
    -ms-grid-row: 1; 
    -ms-grid-column: 2; 
    -ms-grid-column-span:12;
}
.content2 { 
    -ms-grid-row:3; 
    -ms-grid-column: 2; 
    -ms-grid-column-span:5;
}
.content3 { 
    -ms-grid-row:3; 
    -ms-grid-column:8; 
    -ms-grid-column-span:6;
}
.content4 { 
    -ms-grid-row:7; 
    -ms-grid-column: 2; 
    -ms-grid-column-span:12;
}
.picturebox { 
    -ms-grid-row:5; 
    -ms-grid-column: 2; 
    -ms-grid-column-span:12;
}

這些屬性看起來都至關簡單。如今,我須要選擇具體的橫列放入合適的內容。必定要牢記橫列中間有 20px 的間距,因此咱們應該將佈局元素放入奇數橫列中。而後,我爲每一個區域設置了起始縱列和縱列跨度。到此爲止,大多數佈局元素的寬度都是等於容器寬度的,但我將其中的 content2 和 content3 分割成了兩個縱列。如今,在瀏覽器中就能夠顯示出一個簡單的佈局了。

CSS佈局模塊

接着,我要添加第一個媒體查詢了,讓佈局在瀏覽器窗口大於 700px 的寬度時發生一些改變。

@media only screen and (min-width: 700px) { 
    .wrapper {
        -ms-grid-columns: 1fr (4.25fr 1fr)[9];
        -ms-grid-rows: (auto 20px)[5]; 
    }
    .content1 {
        -ms-grid-row: 1; 
        -ms-grid-column: 2; 
        -ms-grid-column-span:17;
    }
    .content2 {
        -ms-grid-row:3; 
        -ms-grid-column:8; 
        -ms-grid-column-span:5;
    }
    .content3 {
        -ms-grid-row:3; 
        -ms-grid-column:14; 
        -ms-grid-column-span:5;
    }
    .content4 { 
        -ms-grid-row:3; 
        -ms-grid-column: 2; 
        -ms-grid-row-span: 3; 
        -ms-grid-column-span:5;
    }
    .picturebox {
        -ms-grid-row:5; 
        -ms-grid-column: 8; 
        -ms-grid-column-span:11;
    } 
}

對於較寬的瀏覽器窗口,我從新界定了網格,增長了更多的縱列和一個額外的橫列。佈局頂部的第一個內容區的寬度仍然佔滿了整個容器。不過,我將其餘的內容去分隔成了三個縱列,其中一個內容區跨越兩個橫列,另外兩個內容區只有前者高度的一半,並將圖片放在了這兩個內容區的下面。

CSS佈局模塊

最後,我使用媒體查詢,爲 940px 以及更寬的屏幕從新設計了網格佈局。

@media only screen and (min-width: 940px) { 
    .wrapper {
        -ms-grid-columns: 1fr (4.25fr 1fr)[16];
        -ms-grid-rows: (auto 20px)[3]; }
    .content1 { 
        -ms-grid-row:1;
        -ms-grid-row-span: 3; 
        -ms-grid-column: 20; 
        -ms-grid-column-span:13;
    }
    .content4, .content2, .content3 {
        -ms-grid-row:1; 
    }
    .picturebox { 
        -ms-grid-row:3;
    } 
}

此次從新界定的網格是一個基於 960 網格系統的標準網格佈局。如今,我建立的網格佈局中,包含了三個窄小的縱列和一個較寬的縱列,圖片被放在了較窄的兩個縱列下面。

CSS佈局模塊

網格佈局模塊真正的魅力在於,咱們無需改變源代碼中的標記結構,便可輕鬆變換內容在佈局中的位置。我認爲該模塊對於初次接觸它的開發者也是通俗易懂的,尤爲是對於那些和我同樣還記得表格佈局的老派開發者。

瀏覽器提示

正如本章開始所解釋的,由於網格佈局語法是由微軟提出的,因此該模塊目前只被 IE10 所支持。若是你正在開發 Windows 方面的應用程序,那麼可能已經在相關的開發環境中用到它了。我也但願看到它被更多的瀏覽器所支持。

CSS Regions

本文的最後兩章將會討論一些由 Adobe 和微軟提議的新方案,它們都頗有意思。雖然這些新方案的發展比起網格佈局來講還處於初級階段,但它們能夠建立一些難以想象的佈局效果。此外,從探究 CSS 佈局中的新特性這個角度來講,也是很是值得的。

CSS Regions 語法爲內容流建立了一種高級模型。咱們能夠經過指定文檔的特定區域,讓該區域的內容實現「流動顯示」的效果——即便指定的這些區域在文檔結構中並不相鄰。在 web 環境中,這聽起來有些怪異,不過,這種佈局經常被用於印刷設計,特別是雜誌和報紙。

CSS Regions 並無提出任何新的佈局方法,因此可使用現有的或未來會出現的方法來定位元素。

爲了演示 CSS Regions 的使用方式,最簡單的方法就是舉例說明。在編寫本書的時候,只有 Chrome Canary 版本的瀏覽器支持該佈局,並且還要保證已經開啓了 WebKit 的實驗性特性。若是你有這樣的瀏覽器,那麼就能夠把玩下面的示例代碼了。

下面就是示例的 HTML 結構。我使用了一個 article 標籤來包裹文章的全部內容,並在文檔底部添加了多個空標籤。

<div class="wrapper"> 
    <article class="main"> 
        <h2>Usefulness of cats</h2> 
        <p>...</p>
        <p>...</p>
    </article>
    <div class="region1 article-regions"></div> 
    <div class="regionwrapper">
        <div class="region2 article-regions"></div> 
        <div class="region3 article-regions"></div>
        <div class="region4 article-regions"></div> 
    </div>
    <div class="region5 article-regions"></div> </div>
</div>

article 標籤內包含了佈局前的原始內容,然後面的空標籤則充當了這些內容的容器。

首先,我須要爲原始內容的容器添加一個新的 CSS 屬性 flow-into(附加 -webkit 前綴),該屬性的值 article-thread是我爲原始內容聲明的一個名字,也能夠用任何其餘的名字。

.main { 
    -webkit-flow-into: article-thread; 
}

一旦添加了該屬性,那麼原始內容就會消失,這是由於你尚未指定它們的佈局位置。

在上面的 HTML 結構中,每一個空標籤都擁有一個 article-regions 的類名,因此我可讓它們接收原始內容。

.article-regions { 
    -webkit-flow-from: article-thread; 
}

在這裏,咱們使用了一個新的屬性 flow-from,並匹配了以前爲原始內容聲明的名字。若是如今刷新頁面,就會發現內容從新出如今頁面上了。接下來,就可讓第一個區域「流動起來了」。當內容「流動起來」以後,咱們添加 CSS 來指定流動區域。

.region1 {
    height: 10em; 
 }
.regionwrapper {
    display: flex; 
    flex-direction: row;
}
.region2 {
    flex: 1;
    padding: 10px;
    height: 40em;
    border-right: 1px dotted #ccc;
}
.region3 {
    flex: 1;
    padding: 10px;
    height: 40em;
    border-right: 1px dotted #ccc; 
    background-color: #efefef;
}
.region4 {
    flex: 1; 
    padding: 10px; 
    height: 40em;
}
.region5 {
    padding: 1em 0 0 0; 
    margin: 1em 0 0 0;
    border-top: 1px dotted #ccc;
    height: auto; 
}

如今 region1 區域已經擁有了 10em 的高度。一旦內容超過了這個高度,內容就會嘗試填充到其餘地方,因此在這裏它會流入下一個區域。接下來的三個區域經過使用 flexbox 佈局,被定位到了三個彈性縱列中,因此內容能夠「流」入這些區域。因爲這三個區域是固定高度的,當內容充滿它們以後,就會繼續「流」入最後的區域,該區域具備自適應的高度,能夠容納剩餘的全部內容。

CSS佈局模塊

若是我改變想法了,想要在內容中間插入其餘的東西,那麼我也是能夠作到的。在下面的示例中,我從 flexbox 中間的縱列上移除了 artcle-regions 類名,因此內容就不會再「流」入其中。如今我能夠爲這個縱列添加一張有關貓的圖片,並引用一句話——它們和周圍「流動的內容」並無多大關係。

CSS佈局模塊

瀏覽器提示

在本章,咱們嘗試了 CSS 模塊中很是新穎的部分,這些部分目前只在 WebKit 瀏覽器開啓實驗性特性時被支持。雖然這並非一個能夠用於線上環境的技巧,但我認爲 CSS Regions 所創造的無限多是一件激動人心的事。

CSS Exclusions

若是你曾經須要用到文字環繞圖形的效果,或者想要裁剪位於內容中央的圖形,那麼你可能會對 CSS Exclusions 和 Shapes 模塊感興趣。一個早期的、參考了浮動定位的規範,已經被當前的工做草案所取代。

咱們都很是熟悉 CSS 中的浮動,關於浮動最簡單的例子就是浮動圖片被文字環繞的效果。不過,浮動在這種場景下是受到嚴格限制的。浮動元素老是出如今頂部,當咱們將圖片浮動到左側時,文字就會環繞在它的右側和下方,沒法將圖片置於文檔的中央,實現文字的四周環繞效果,也沒法將其浮動到底部,讓文字環繞在上方和兩側。上面提到的,就是 Exclusions 和 Shapes 模塊首要解決的問題,並已經在 IE10 和開啓實驗性特性的 Webkit 瀏覽器中得到了支持,下面咱們將會看一個實例。

這個實例就是一段簡單的文字,其外層被一個類名爲 main 的 article 標籤所包裹。在 article 標籤以後,緊跟着一個 div 標籤,標籤內部是一張貓的圖片。我但願這張圖片在佈局時呈現一種文字環繞的效果。

<div class="wrapper"> 
    <article class="main">
        <h2>Usefulness of cats</h2> 
        <p>...</p>
    </article>
    <div class="exclusion">
        <img src="fluffy.jpg" alt="Fluffy the cat" />
    </div> 
</div>

首先,我要像以前同樣爲它建立一個網格。與浮動不一樣的是,Exclusion 須要被定位(所以在浮動定位前須要有個名字)。我是使用 IE10 演示該示例的,因此可使用網格佈局來實現這種定位。

我建立的是一個兩行三列的網格,並在建立後讓 article 佈局範圍覆蓋到了全部的行列上。雖然 div 標籤在源碼結構中是緊跟在 article 標籤以後的,但它會顯示在文字的上方。

.main {
    -ms-grid-column: 1; 
    -ms-grid-row: 1; 
    -ms-grid-row-span: 3; 
    -ms-grid-column-span: 3; 
    padding: 0 0 2em 0;
}
.exclusion {
    -ms-grid-row:2; 
    -ms-grid-column:2; 
    height: 160px; 
    width: 200px; 
    padding: 10px;
}

CSS佈局模塊

要建立 Exclusion,實現浮動圖片的文字環繞效果,我只須要爲 .exclusion 添加 wrap-flow 屬性便可。

.exclusion { -ms-grid-row:2; -ms-grid-column:2; height: 160px; width: 200px; padding: 10px; -ms-wrap-flow:both; }

屬性值 both 意味着文字將會環繞在 Exclusion 的兩側。

CSS佈局模塊

實現矩形的文字環繞只是 CSS Exclusions 和 Shapes 模塊的一小部分特性。在一個早期的瀏覽器實現中,既可讓文字環繞圖形的外部,也能夠將文字約束在圖形內部。若是你可使用 Chrome Canary,而且開啓了 WebKit 的實驗性特性,那麼就能夠查看由 Adobe 提供的更多示例,甚至是建立本身的實例。這些特性還算是新穎的東西,並具備必定的複雜性,雖然已經在 WebKit 上作了不少測試,依然有可能在最新的瀏覽器上發生變化。

瀏覽器提示

wrap-flow 特性對於控制文字環繞效果很是有用,它一旦被大多數的瀏覽器所支持,必定會快速流行起來。合理構建文檔的源碼結構,有助於在不支持上述特性的瀏覽器中優雅降級到另外一種佈局方案;也有助於在使用相似 Modernizr 的 JavaScript 特性檢測方式以後,提供一種可替換的定位模型。

甚至是 Shapes,一旦它被主流瀏覽器所支持,那麼就能夠考慮去使用它了。只要文字環繞對於你的設計是一種有益的、非必須的特性,毫無疑問你就能夠爲那些支持這些特性的瀏覽器添加它,達到畫龍點睛的效果——特別是當你知道訪問網站的用戶經常會使用這些瀏覽器的時候。

總結

推敲、把玩和測試這些佈局模塊是一件激動人心而又妙不可言的事情。我很是但願本文的內容可以點燃你的熱情,讓你繼續去探索 CSS 中既有和即將到來的新特性,去發現無限的可能性。

在學習這些出色的新特性時,雖然它們可能還不能用於線上實踐,雖然會有種種障礙,但對於咱們自身的職業發展將會有莫大幫助。參與這些新規範的建立和測試,並非瀏覽器開發者和大公司的專利。若是但願將來在瀏覽器中用到這些新規範,做爲網頁設計師和開發者的咱們,就應該參入到其中。

相關文章
相關標籤/搜索