五. 網(wǎng)格布局
CSS的網(wǎng)格布局是一種二維的,基于網(wǎng)格的前端布局技術(shù),完全改變了設(shè)計(jì)用戶界面的方式。從布局發(fā)展的過程來看,從一開始基于tables,到float,再到positioning和inline-block,這些方法中充斥著大量的奇技淫巧,但連最基本的居中定位都做的不好。flex布局是一種很強(qiáng)大的基于軸線布局的一維布局方式,而網(wǎng)格布局則真正做到了基于行列單元格的二維布局,實(shí)際上flex搭配grid能工作的很好。網(wǎng)格布局與media query相結(jié)合同樣也能通過寥寥數(shù)行代碼實(shí)現(xiàn)響應(yīng)式設(shè)計(jì)。
網(wǎng)格布局將網(wǎng)頁劃分為不同的網(wǎng)格,通過組合不同網(wǎng)格做出各種各樣的布局。以前通過復(fù)雜css框架達(dá)成的效果現(xiàn)在瀏覽器內(nèi)置了,所以稱它為2019年必學(xué)的新布局方法,但目前瀏覽器的支持還存在一定問題,但以后會(huì)越來越好。
5.1 基本概念
同樣地,在網(wǎng)格布局中只要給html元素增加了相應(yīng)的display屬性,該元素就變成網(wǎng)格容器。而容器的直接子元素被稱為項(xiàng)(item),注意是直接子元素,因?yàn)閐isplay屬性不可繼承。網(wǎng)格布局還有一些專門的術(shù)語:行和列,網(wǎng)格線,網(wǎng)格軌道(track)和網(wǎng)格區(qū)域,下面來一一介紹。
5.1.1 行和列
在網(wǎng)格布局中,水平區(qū)域稱之為行,垂直區(qū)域稱之為列。單元格是行和列的交叉區(qū)域。

5.1.2 網(wǎng)格線
網(wǎng)格布局中的重要概念,分為水平網(wǎng)格線和垂直網(wǎng)格線,用于根據(jù)網(wǎng)格線定位位置。

5.1.3 網(wǎng)格軌道(grid track)
網(wǎng)格軌道是兩相鄰網(wǎng)格線之間的區(qū)域。

5.1.4 網(wǎng)格區(qū)域
網(wǎng)格區(qū)域是4條網(wǎng)格線之間包圍的區(qū)域,由1個(gè)或多個(gè)單元格構(gòu)成。

5.2 容器屬性
用display屬性可以將元素定義為網(wǎng)格容器,并給它所包含的內(nèi)容創(chuàng)建一個(gè)網(wǎng)格布局的上下文環(huán)境:
.container {
display: grid | inline-grid;
}
grid代表塊級(jí)網(wǎng)格,inline-grid代表行內(nèi)級(jí)網(wǎng)格,后者表示該容器本身體現(xiàn)為行內(nèi)元素,但內(nèi)容卻是網(wǎng)格布局的。開啟網(wǎng)格布局之后,接下來我們來看看如何對(duì)布局內(nèi)容進(jìn)行精細(xì)化調(diào)整。
5.2.1 行高和列寬
grid-template-rows和grid-template-columns分別用于定義行高和列寬。值表示網(wǎng)格大小,值之間的空格表示網(wǎng)格線。語法格式如下:
.container {
grid-template-columns: <track-size> ... | <line-name> <track-size> ...;
grid-template-rows: <track-size> ... | <line-name> <track-size> ...;
}
比如,定義一個(gè)3行5列的網(wǎng)格布局最后一行和中間一列使用auto關(guān)鍵字來表示由瀏覽器自己決定長(zhǎng)度:
.container {
grid-template-columns: 40px 50px auto 50px 40px;
grid-template-rows: 25% 100px auto;
}

上圖中的每條網(wǎng)格線都得到了自動(dòng)命名的4個(gè)名稱。但我們可以使用方括號(hào)指定每一根網(wǎng)格線的名字,方便以后的引用。網(wǎng)格布局允許同一根線有多個(gè)名字,比如[fifth-line row-5],給上面的布局重新定義一下網(wǎng)格線名稱,可以這么寫:
.container {
grid-template-columns: [first] 40px [line2] 50px [line3] auto [col4-start] 50px [five] 40px [end];
grid-template-rows: [row1-start] 25% [row1-end] 100px [third-line] auto [last-line];
}

如果覺得這么寫麻煩,還可以使用repeat()函數(shù)來指定行高和列寬。例如這樣的寫法:
.container {
grid-template-columns: repeat(3, 20px [col-start]);
}
等價(jià)于:
.container {
grid-template-columns: 20px [col-start] 20px [col-start] 20px [col-start];
}
fr關(guān)鍵字是fraction的縮寫,如果兩列的寬度分別為1fr和2fr,就表示后者按前者的兩倍分配空閑空間,例如設(shè)置誒每個(gè)項(xiàng)占滿容器的1/3:
.container {
grid-template-columns: 1fr 1fr 1fr;
}
因?yàn)榭梢耘c絕對(duì)長(zhǎng)度的單位結(jié)合使用,空閑空間是在排除任何固定尺寸的項(xiàng)之后才計(jì)算的。比如下面這個(gè)例子中fr的計(jì)算就沒有包含50px:
.container {
grid-template-columns: 1fr 50px 1fr 1fr;
}
minmax()函數(shù)產(chǎn)生一個(gè)長(zhǎng)度范圍,表示長(zhǎng)度就在這個(gè)范圍之中,它接受兩個(gè)參數(shù),分別為最小值和最大值。比如:
grid-template-columns: 1fr 1fr minmax(100px, 1fr);
上面這行代碼中minmax(100px, 1fr) 表示長(zhǎng)度不小于100px,不大于1fr。
還有個(gè)auto-fill關(guān)鍵字可以用來表示自動(dòng)填充。有時(shí)單元格的大小是固定的,但是容器的大小不確定。如果希望每一行(或每一列)容納盡可能多的單元格,就需要用到自動(dòng)填充。
.container {
display: grid;
grid-template-columns: repeat(auto-fill, 100px);
}
表示每列寬度100px,然后自動(dòng)填充,直到容器不能放置更多的列。很多常見的實(shí)例用網(wǎng)格布局都能幾行代碼輕松搞定,比如兩欄式布局,其中左邊欄70%,右邊欄30%:
.wrapper {
display: grid;
grid-template-columns: 70% 30%;
}
十二網(wǎng)格布局:
grid-template-columns: repeat(12, 1fr);
5.2.2 行間距與列間距
grid-row-gap屬性定義行與行的間隔;grid-column-gap屬性定義列與列的間隔,這個(gè)屬性相當(dāng)于是定義了網(wǎng)格線的大小。語法規(guī)則如下:
.container {
grid-column-gap: <line-size>;
grid-row-gap: <line-size>;
}
下面這例子設(shè)置列間距為10px,行間距為15px:
.container {
grid-template-columns: 100px 50px 100px;
grid-template-rows: 80px auto 80px;
grid-column-gap: 10px;
grid-row-gap: 15px;
}

grid-gap屬性將成為二者的合并簡(jiǎn)寫形式。如果grid-gap省略了第二個(gè)值,瀏覽器將認(rèn)為第二個(gè)值等于第一個(gè)值。
根據(jù)最新標(biāo)準(zhǔn),上面三個(gè)屬性名的grid-前綴已經(jīng)刪除,grid-column-gap和grid-row-gap寫成column-gap和row-gap,grid-gap寫成gap
5.2.3 grid-template-areas屬性
grid-template-areas屬性通過引用由grid-area屬性(下面會(huì)介紹)定義的網(wǎng)格區(qū)域名稱來定義一個(gè)網(wǎng)格模板。重復(fù)指定的名稱表示該區(qū)域跨越多個(gè)單元格。點(diǎn)號(hào).表示空的單元格(不需要利用的區(qū)域)。該語法展示的是網(wǎng)格的結(jié)構(gòu)形狀。例如下面這段css代碼:
.item-a {
grid-area: header;
}
.item-b {
grid-area: main;
}
.item-c {
grid-area: sidebar;
}
.item-d {
grid-area: footer;
}
.container {
display: grid;
grid-template-columns: 50px 50px 50px 50px;
grid-template-rows: auto;
grid-template-areas:
"header header header header"
"main main . sidebar"
"footer footer footer footer";
}
將定義如下的4列寬,3列高的網(wǎng)格布局。第一行由header全部占滿;第二行為一個(gè)跨兩列的main區(qū)域以及一個(gè)sidebar區(qū)域,最后一行由footer全部占滿。

注意,區(qū)域的命名會(huì)影響到網(wǎng)格線。每個(gè)區(qū)域的起始網(wǎng)格線,會(huì)自動(dòng)命名為區(qū)域名-start,終止網(wǎng)格線自動(dòng)命名為區(qū)域名-end。比如,區(qū)域名為header,則起始位置的水平網(wǎng)格線和垂直網(wǎng)格線叫做header-start,終止位置的水平網(wǎng)格線和垂直網(wǎng)格線叫做header-end。
grid-template屬性是grid-template-rows,grid-template-columns和grid-template-areas的簡(jiǎn)寫形式,因此:
.container {
grid-template:
[row1-start] "header header header" 25px [row1-end]
[row2-start] "footer footer footer" 25px [row2-end]
/ auto 50px auto;
}
其實(shí)等價(jià)于:
.container {
grid-template-rows: [row1-start] 25px [row1-end row2-start] 25px [row2-end];
grid-template-columns: auto 50px auto;
grid-template-areas:
"header header header"
"footer footer footer";
}
5.2.4 grid-auto-flow屬性
劃分網(wǎng)格以后,容器的子元素會(huì)按照順序,自動(dòng)放置在每一個(gè)網(wǎng)格中,該屬性指定放置的順序,若取值為row則表示"先行后列",若取值為column則表示"先列后行"。如果再加上了dense則表示"盡可能緊密填滿”,也就是說如果有尺寸較小的元素,則盡量往前面放。
取值:
- row:行優(yōu)先布局,按次序填滿一行,如果有需要?jiǎng)t增加新的行(默認(rèn))
- column:列優(yōu)先布局,按次序填滿一列,如果有需要?jiǎng)t增加新的列
- dense:如果有較小的項(xiàng)放在后面,算法會(huì)優(yōu)先考慮將其放到前面來填補(bǔ)網(wǎng)格中的空余空間
用下面的html代碼舉個(gè)例子:
<section class="container">
<div class="item-a">item-a</div>
<div class="item-b">item-b</div>
<div class="item-c">item-c</div>
<div class="item-d">item-d</div>
<div class="item-e">item-e</div>
</section>
定義一個(gè)行優(yōu)先的,2行5列的網(wǎng)格布局如下:
.container {
display: grid;
grid-template-columns: 60px 60px 60px 60px 60px;
grid-template-rows: 30px 30px;
grid-auto-flow: row;
}
然后我們放置網(wǎng)格項(xiàng):
.item-a {
grid-column: 1;
grid-row: 1 / 3;
}
.item-e {
grid-column: 5;
grid-row: 1 / 3;
}
就能得到:

如果改為列優(yōu)先,則變?yōu)椋?/p>

5.2.5 新增網(wǎng)格的列寬和行高
有時(shí)候,一些項(xiàng)目的指定位置,在現(xiàn)有網(wǎng)格的外部。比如網(wǎng)格只有3列,但是某一個(gè)項(xiàng)目指定在第5行。這時(shí),瀏覽器會(huì)自動(dòng)生成多余的網(wǎng)格(稱為隱式網(wǎng)格軌道)以便放置項(xiàng)目,如果不指定grid-auto-columns和grid-auto-rows這兩個(gè)屬性,瀏覽器會(huì)完全根據(jù)單元格內(nèi)容的大小,決定新增網(wǎng)格的列寬和行高。
grid-auto-columns屬性指定瀏覽器自動(dòng)創(chuàng)建的多余網(wǎng)格的列寬,grid-auto-rows屬性指定瀏覽器自動(dòng)創(chuàng)建的多余網(wǎng)格的行高??梢允褂瞄L(zhǎng)度,百分比和fr作為單位。比如有如下的2*2網(wǎng)格:
.container {
grid-template-columns: 60px 60px;
grid-template-rows: 90px 90px
}

現(xiàn)在有一個(gè)網(wǎng)格的位置被放置在了這個(gè)2*2的網(wǎng)格外面:
.item-a {
grid-column: 1 / 2;
grid-row: 2 / 3;
}
.item-b {
grid-column: 5 / 6;
grid-row: 2 / 3;
}
這些自動(dòng)生成的網(wǎng)格軌道的大小會(huì)完全根據(jù)所放置的項(xiàng)的大小來決定(注意第3列和第4列):

我們可以給這些隱式網(wǎng)格軌道指定列寬或者行高:
.container {
grid-auto-columns: 60px;
}

5.2.6 grid屬性
grid屬性是grid-template-rows,grid-template-columns,grid-template-areas,grid-auto-rows,grid-auto-columns和grid-auto-flow五個(gè)屬性的簡(jiǎn)寫形式。
取值:
- none:設(shè)置所有的5個(gè)屬性為默認(rèn)值
- <grid-template>:與grid-template簡(jiǎn)寫屬性相同
- <grid-template-rows> / [ auto-flow && dense? ] <grid-auto-columns>?:設(shè)置grid-template-rows的值;如果auto-flow出現(xiàn)在反斜杠的右邊,則表示先列后行;如果再加上dense關(guān)鍵字則表示緊湊模式;如果不設(shè)置grid-auto-columns,則默認(rèn)為auto
- [ auto-flow && dense? ] <grid-auto-rows>? / <grid-template-columns>:設(shè)置grid-template-columns的值;如果auto-flow出現(xiàn)在反斜杠的左邊,則表示先行后列;如果再加上dense關(guān)鍵字則表示緊湊模式;如果不設(shè)置grid-auto-rows,則默認(rèn)為auto
下面的css是等價(jià)的:
.container {
grid: 100px 300px / 3fr 1fr;
}
.container {
grid-template-rows: 100px 300px;
grid-template-columns: 3fr 1fr;
}
下面這段css也是等價(jià)的:
.container {
grid: auto-flow / 200px 1fr;
}
.container {
grid-auto-flow: row;
grid-template-columns: 200px 1fr;
}
以及:
.container {
grid: auto-flow dense 100px / 1fr 2fr;
}
.container {
grid-auto-flow: row dense;
grid-auto-rows: 100px;
grid-template-columns: 1fr 2fr;
}
還有:
.container {
grid: 100px 300px / auto-flow 200px;
}
.container {
grid-template-rows: 100px 300px;
grid-auto-flow: column;
grid-auto-columns: 200px;
}
grid屬性還有一種更復(fù)雜的寫法:一次性把grid-template-areas,grid-template-rows和grid-template-columns的設(shè)置都搞定,所有其他的設(shè)置都保持默認(rèn)值,比如下面這兩段css是等價(jià)的:
.container {
grid: [row1-start] "header header header" 1fr [row1-end]
[row2-start] "footer footer footer" 25px [row2-end]
/ auto 50px auto;
}
.container {
grid-template-areas:
"header header header"
"footer footer footer";
grid-template-rows: [row1-start] 1fr [row1-end row2-start] 25px [row2-end];
grid-template-columns: auto 50px auto;
}
這個(gè)屬性的用法比較靈活,需要多實(shí)踐才能熟練掌握。
5.2.7 單元格對(duì)齊方式
單元格的對(duì)齊有垂直和水平兩個(gè)方向。水平方向的單元格對(duì)齊使用justify-items屬性,垂直方向的單元格對(duì)齊使用align-items屬性。
它們都有4種取值:
start:對(duì)齊單元格的起始邊緣。
end:對(duì)齊單元格的結(jié)束邊緣。
center:?jiǎn)卧駜?nèi)部居中。
stretch:拉伸,占滿單元格的整個(gè)寬度(默認(rèn)值)
start對(duì)齊單元格的起始邊緣(對(duì)于水平方向來說是左邊緣,對(duì)于垂直方向來說是上邊緣):
.container {
justify-items: start;
}

.container {
align-items: start;
}

end對(duì)齊單元格的結(jié)束邊緣(對(duì)于水平方向來說是右邊緣,對(duì)于垂直方向來說是下邊緣):
.container {
justify-items: end;
}

.container {
align-items: end;
}

center將單元格內(nèi)部居中:
.container {
justify-items: center;
}

.container {
align-items: center;
}

stretch將單元格拉伸,占滿單元格整個(gè)寬度(默認(rèn)值):
.container {
justify-items: stretch;
}
.container {
align-items: stretch;
}

place-items屬性是align-items屬性和justify-items屬性的合并簡(jiǎn)寫形式,如果省略第二個(gè)值,則瀏覽器認(rèn)為與第一個(gè)值相等。
5.2.8 內(nèi)容區(qū)域?qū)R方式
如果所有的網(wǎng)格項(xiàng)的大小都是用固定的單位比如px指定的,那么網(wǎng)格本身的尺寸就有可能比容納網(wǎng)格的容器尺寸更小,這個(gè)時(shí)候我們可以通過一些屬性來設(shè)置網(wǎng)格容器中的網(wǎng)格如何對(duì)齊,對(duì)齊的方式仍然包含水平和垂直兩個(gè)方向。
justify-content屬性用于水平方向?qū)R,而align-content屬性用于垂直方向?qū)R。它們都可以選擇如下取值:
- start:對(duì)齊容器的起始邊框
- end:對(duì)齊容器的結(jié)束邊框
- center:容器內(nèi)部居中
- stretch:項(xiàng)的大小沒有指定時(shí),拉伸占據(jù)整個(gè)網(wǎng)格容器
- space-around:每個(gè)項(xiàng)兩側(cè)的間隔相等。所以,項(xiàng)之間的間隔比項(xiàng)與容器邊框的間隔大一倍
- space-between:項(xiàng)與項(xiàng)的間隔相等,項(xiàng)與容器邊框之間沒有間隔
- space-evenly:項(xiàng)與項(xiàng)的間隔相等,項(xiàng)與容器邊框之間也是同樣長(zhǎng)度的間隔
start對(duì)齊容器的起始邊框(水平方向上是左邊框,垂直方向上是上邊框):
.container {
justify-content: start;
}

.container {
align-content: start;
}

end對(duì)齊容器的結(jié)束邊框(水平方向上是右邊框,垂直方向上是下邊框):
.container {
justify-content: end;
}

.container {
align-content: end;
}

center將網(wǎng)格在容器內(nèi)居中顯示:
.container {
justify-content: center;
}

.container {
align-content: center;
}

stretch使得網(wǎng)格拉伸占據(jù)整個(gè)容器:
.container {
justify-content: stretch;
}

.container {
align-content: stretch;
}

space-around使得兩側(cè)的間隔相等,因此中間部分的要比兩邊的間隔大一倍:
.container {
justify-content: space-around;
}

.container {
align-content: space-around;
}

space-between使得項(xiàng)與項(xiàng)之間間隔相等:
.container {
justify-content: space-between;
}

.container {
align-content: space-between;
}

space-evenly使得項(xiàng)與項(xiàng)之間間隔相等,也包括項(xiàng)與邊框之間的間隔:
.container {
justify-content: space-evenly;
}

.container {
align-content: space-evenly;
}

5.3 項(xiàng)屬性
對(duì)于一個(gè)網(wǎng)格項(xiàng)而言,float,display: inline-block,display: table-cell,vertical-align 和 column-*屬性都將失效。
5.3.1 根據(jù)網(wǎng)格線定位項(xiàng)的位置
網(wǎng)格布局是通過網(wǎng)格線來定位網(wǎng)格項(xiàng)的位置的。grid-column-start屬性定位左邊框所在的垂直網(wǎng)格線,grid-column-end屬性定位右邊框所在的垂直網(wǎng)格線,有一個(gè)grid-column屬性能夠提供同時(shí)定義這兩個(gè)屬性的簡(jiǎn)寫形式。grid-row-start屬性定義上邊框所在的水平網(wǎng)格線,grid-row-end屬性定義下邊框所在的水平網(wǎng)格線,有一個(gè)grid-row屬性能夠提供同時(shí)定義這兩個(gè)屬性的簡(jiǎn)寫形式。這四個(gè)屬性的值,除了指定為第幾個(gè)網(wǎng)格線,還可以指定為網(wǎng)格線的名字。這四個(gè)屬性的值還可以使用span關(guān)鍵字,表示"跨越",即左右邊框(上下邊框)之間跨越多少個(gè)網(wǎng)格。四個(gè)屬性都可以使用auto關(guān)鍵字表示自動(dòng)放置/跨越/默認(rèn)單位為1的跨越。使用這四個(gè)屬性,如果產(chǎn)生了項(xiàng)目的重疊,則使用z-index屬性指定項(xiàng)目的重疊順序。
舉例1:
.item-a {
grid-column-start: 2;
grid-column-end: five;
grid-row-start: row1-start
grid-row-end: 3;
}

.item-b {
grid-column-start: 1;
grid-column-end: span col4-start;
grid-row-start: 2
grid-row-end: span 2
}

使用簡(jiǎn)寫形式:
.item-c {
grid-column: 3 / span 2;
grid-row: third-line / 4;
}

5.3.2 grid-area屬性
grid-area屬性用于給項(xiàng)命名,該名稱可以在grid-template-areas中被引用到?;蛘哂米鱣rid-row-start、grid-column-start、grid-row-end、grid-column-end的合并簡(jiǎn)寫形式,直接指定項(xiàng)目的位置。
舉例,第一種用法是給網(wǎng)格項(xiàng)命名:
.item-d {
grid-area: header;
}
第二種用法:
.item-d {
grid-area: 1 / col4-start / last-line / 6;
}

5.3.3 設(shè)置單元格內(nèi)容位置
設(shè)置單元格內(nèi)容位置跟設(shè)置單元格對(duì)齊方式很像,都分為水平方向和垂直方向。區(qū)別在于前者是針對(duì)單個(gè)的項(xiàng),而后者針對(duì)的是全部的項(xiàng)。
justify-self屬性在一個(gè)單元格中對(duì)齊項(xiàng)的水平位置,align-self屬性在一個(gè)單元格中對(duì)齊項(xiàng)的垂直位置。這兩個(gè)屬性都可以取4個(gè)值:
start:對(duì)齊單元格的起始邊緣。
end:對(duì)齊單元格的結(jié)束邊緣。
center:?jiǎn)卧駜?nèi)部居中。
stretch:拉伸,占滿單元格的整個(gè)寬度(默認(rèn)值)
start對(duì)齊單元格的起始邊緣(水平方向上的左邊緣和垂直方向上的上邊緣):
.item-a {
justify-self: start;
}

.item-a {
align-self: start;
}

end對(duì)齊單元格的結(jié)束邊緣(水平方向的右邊緣和垂直方向的下邊緣):
.item-a {
justify-self: end;
}

.item-a {
align-self: end;
}

center在單元格內(nèi)部居中:
.item-a {
justify-self: center;
}

.item-a {
align-self: center;
}

stretch拉伸并占滿單元格的整個(gè)寬度:
.item-a {
justify-self: stretch;
}

.item-a {
align-self: stretch;
}

place-self屬性是align-self屬性和justify-self屬性的合并簡(jiǎn)寫形式,如果省略第二個(gè)值,place-self屬性會(huì)認(rèn)為這兩個(gè)值相等。以上就是網(wǎng)格布局所有的屬性,要熟練掌握網(wǎng)格布局,還是需要在實(shí)踐中多加練習(xí)。有了網(wǎng)格布局,原來我們要實(shí)現(xiàn)的很多復(fù)雜的響應(yīng)式布局就能夠得到極大的簡(jiǎn)化,這篇文章介紹了如何用網(wǎng)格布局來完全替代Bootstrap框架。
六. 表格和字體的響應(yīng)式設(shè)計(jì)
響應(yīng)式設(shè)計(jì)中表格,字體和圖片也是要討論的重要主題。這里簡(jiǎn)單介紹下響應(yīng)式設(shè)計(jì)中如何處理表格和字體。下一部分會(huì)介紹響應(yīng)式設(shè)計(jì)中的圖片。
6.1 響應(yīng)式表格
對(duì)于網(wǎng)頁中出現(xiàn)的表格而言,如果列數(shù)超出一定的范圍,那么可能需要兩個(gè)方向的滾動(dòng)條左右上下拖動(dòng)來查看,這是一種很不好的用戶體驗(yàn)。要盡量避免出現(xiàn)兩個(gè)方向上的滾動(dòng)條,不同的情況有不同的解決方案。對(duì)于表格有三種響應(yīng)式設(shè)計(jì)的技巧:隱藏列(hidden columns),無表格設(shè)計(jì)(no more tables)以及表格內(nèi)滾動(dòng)(contained tables)。
6.1.1 隱藏列
隱藏列的設(shè)計(jì)技巧是當(dāng)視口尺寸縮小時(shí),根據(jù)信息的重要性選擇隱藏一些列。沿著"從小處開始"的設(shè)計(jì)技巧,先思考什么信息最重要,對(duì)這部分信息進(jìn)行保留,然后用display: none隱藏其他相對(duì)不那么重要的信息。這個(gè)技巧最大的問題是它向用戶隱瞞了一些信息,所以使用時(shí)要謹(jǐn)慎。如果有可能的話,盡量使用縮寫,而不是隱藏它。
比如下面這個(gè)表格:
<table class="scores__table">
<thead>
</thead>
</table>
我們可以設(shè)計(jì)當(dāng)視口寬度小于等于499px時(shí)隱藏gametime列:
@media screen and (max-width: 499px) {
.gametime {
display: none;
}
}
6.1.2 無表格設(shè)計(jì)
當(dāng)視口寬度小于一定值時(shí),表格將使用CSS重組成長(zhǎng)列表而不是數(shù)據(jù)表。這種解決方案的好處在于所有數(shù)據(jù)都是可見的。以下面這個(gè)棒球得分表為例:

<table>
<thead>
<tr>
<th>Team</th>
<th>1st</th>
<th>2nd</th>
<th>3rd</th>
<th>4th</th>
<th>5th</th>
<th>6th</th>
<th>7th</th>
<th>8th</th>
<th>9th</th>
<th>Final</th>
</tr>
</thead>
<tbody>
<tr>
<td data-th="Team">Toronto</td>
<td data-th="1st">0</td>
<td data-th="2nd">0</td>
<td data-th="3rd">0</td>
<td data-th="4th">4</td>
<td data-th="5th">0</td>
<td data-th="6th">1</td>
<td data-th="7th">0</td>
<td data-th="8th">0</td>
<td data-th="9th">0</td>
<td data-th="Final">5</td>
</tr>
<tr>
<td data-th="Team">San Francisco</td>
<td data-th="1st">0</td>
<td data-th="2nd">0</td>
<td data-th="3rd">0</td>
<td data-th="4th">4</td>
<td data-th="5th">0</td>
<td data-th="6th">0</td>
<td data-th="7th">0</td>
<td data-th="8th">0</td>
<td data-th="9th">0</td>
<td data-th="Final">4</td>
</tr>
</tbody>
</table>
當(dāng)視口寬度小于500px時(shí)變成長(zhǎng)列表:

table {
border: 1px solid #ddd;
}
tr:nth-child(odd) {
background-color: #f9f9f9;
}
@media screen and (max-width: 500px) {
table, thead, tbody, th, td, tr {
display: block;
}
thead tr {
position: absolute;
top: -9999px;
left: -9999px;
}
td {
position: relative;
padding-left: 50%;
}
td:before {
position: absolute;
left: 6px;
content: attr(data-th);
font-weight: bold;
}
td:first-of-type {
font-weight: bold;
}
}
6.1.3 表格內(nèi)滾動(dòng)
表格內(nèi)滾動(dòng)是一種為超出視口寬度的表格添加水平滾動(dòng)條的方法。首先將表格包括在div中,然后使用CSS將這個(gè)div設(shè)置成100%寬并設(shè)置overflow-x: auto即可。
div {
width: 100%;
overflow-x: auto;
}
6.2 響應(yīng)式字體
網(wǎng)頁上每一行文字的字?jǐn)?shù)不能太長(zhǎng)也不能太短。太短的話人為割裂了詞組會(huì)導(dǎo)致句子含義難以理解;太長(zhǎng)的話不容易定位下一行,用戶讀著讀著就沒耐心開始略讀了。一個(gè)好的建議是網(wǎng)頁上每行大約65個(gè)字符,字體足夠大:至少16像素,行高至少1.2em。我們可以設(shè)置一些次要的斷點(diǎn)媒體查詢來改善字體的響應(yīng)式設(shè)計(jì),比如當(dāng)視口寬度增加時(shí)給一些內(nèi)容增加字號(hào),增加內(nèi)邊距并增大圖標(biāo)的尺寸。
七. 圖片的響應(yīng)式設(shè)計(jì)
在打開網(wǎng)頁所需的平均字節(jié)數(shù)中,圖片的加載要耗去60%。所以我們?cè)谠O(shè)計(jì)網(wǎng)頁時(shí)對(duì)圖片的使用一定要注意。響應(yīng)式圖片設(shè)計(jì)的目的是用最少的字節(jié)傳輸最高質(zhì)量的圖片,因?yàn)閷?duì)于移動(dòng)設(shè)備以及不太好的網(wǎng)絡(luò)環(huán)境而言,圖片精度太高容易增加頁面的加載延遲。我們要避免出現(xiàn)圖片放大后像素失真,圖片無法加載和裁剪后看不到圖像全貌等問題,使得圖片在各種尺寸設(shè)備上表現(xiàn)良好,從而提升用戶體驗(yàn)。
Create a product, don't re-imagine one for small screens, great mobile products are created, never ported. --Brian Fling
7.1 圖片加載的性能優(yōu)化
我們通常要考慮圖片的質(zhì)量和大小。然而對(duì)于網(wǎng)頁上的圖片而言,我們只需要考慮大小就可以了,即圖片的壓縮等級(jí)和實(shí)際的分辨率。圖片文件的大小往往取決于像素?cái)?shù)和每個(gè)像素所占的比特?cái)?shù)量。所以為了提高網(wǎng)站的性能,我們要使用盡可能小的圖片尺寸和盡可能高的圖片壓縮率。常見的錯(cuò)誤是使用了過大的圖片尺寸和過高的圖片質(zhì)量。有人統(tǒng)計(jì)過,平均每個(gè)網(wǎng)頁要發(fā)出56個(gè)左右的請(qǐng)求來加載圖片,每次請(qǐng)求對(duì)頁面加載來說都是一項(xiàng)成本,一個(gè)小的頁面加載延遲都可能造成明顯的流量和經(jīng)濟(jì)損失。Google頁面加載每增加0.4到0.9秒,將導(dǎo)致流量和廣告收入降低20%;Amazon頁面加載延遲每增加100ms就意味著1%銷售額損失。
7.1.1 不使用固定大小圖片
不要使用固定大小的圖片,因?yàn)樗鼰o法根據(jù)視口的尺寸來改變自身大小,應(yīng)該使用百分比相對(duì)大小,比如max-wdith: 100%。對(duì)于臺(tái)式機(jī)或筆記本電腦而言,不要假設(shè)視口尺寸和屏幕尺寸相同,也不要假設(shè)視口會(huì)一直保持相同的大小。使用max-width是一種優(yōu)雅地響應(yīng)視圖區(qū)域變化的方法。如果想要兩張圖片并列對(duì)齊,使每個(gè)圖像為可用寬度的一半,并留有10px的間隔,那么就可以使用calc()函數(shù):
img {
width: calc((100% - 10px) / 2);
}
img: last-of-type {
margin-right: 0;
}
7.1.2 使用特殊的CSS單位
vh和vw兩種單位分別用來表示視口的高度和寬度。一個(gè)vh單位對(duì)應(yīng)1%視口高度,一個(gè)vw單位對(duì)應(yīng)1%視口寬度,所以100vh表示100%視口高度,100vw表示100%視口寬度。另一種常見的響應(yīng)式用例是調(diào)整圖片尺寸來適應(yīng)視口寬度或者高度的較小者或較大者,就可以分別使用vmin和vmax。
7.1.3 柵格圖和矢量圖
有兩種不同的基礎(chǔ)方法創(chuàng)建和存儲(chǔ)圖片,一種叫柵格圖,另一種叫矢量圖。前者是一種點(diǎn)陣圖片,我們平時(shí)從照相機(jī),掃描儀中得到的圖片都是柵格圖。而后者是用特殊格式描述的線條組成的矢量圖形。矢量圖片優(yōu)于柵格圖片的一點(diǎn)是瀏覽器可以渲染任意尺寸的矢量圖片,當(dāng)視口尺寸增加時(shí),矢量圖不會(huì)失真而產(chǎn)生鋸齒。為了提升性能,建議為照片使用jpeg格式,為矢量圖使用svg格式,如果是商標(biāo)等logo圖案,如果不能使用svg,則使用png。
7.1.4 使用專業(yè)工具優(yōu)化圖片
有一些專業(yè)的工具可以提供對(duì)圖片的批量處理。使用ImageMagick可以轉(zhuǎn)換圖片格式,裁剪或者應(yīng)用濾鏡??梢陨赏环鶊D片的多種版本或不同的尺寸和格式。還可以使用Grunt任務(wù)來使用ImageMagick,比如Grunt的響應(yīng)式圖片插件,能夠一次性得到許多不同質(zhì)量的圖片。還有其他一些工具可以使用,ImageOptim可以利用很多開源工具來生成無損圖片。
ImageMagick:
GraphicsMagick (ImageMagick 的一個(gè)分叉)
Grunt:
圖片處理工具:
ImageOptim (Mac)
Trimage - 和 ImageOptim 類似 (Windows, Mac, Linux)
7.1.5 對(duì)頁面進(jìn)行優(yōu)化檢查
怎樣才能檢查頁面上所有的圖片都被優(yōu)化了呢?有一個(gè)在線檢查圖片優(yōu)化情況的工具叫PageSpeed Insights。可以用它的網(wǎng)頁辦來檢查網(wǎng)站,還可以在開發(fā)者工具中使用它。最厲害的是它還有API接口,可以在終端下通過curl命令來檢查。也可以把這個(gè)檢查過程寫入到推送代碼到倉庫時(shí)的構(gòu)建測(cè)試中,使用grunt task runner來實(shí)現(xiàn)。grunt有PageSpeed Insights插件可供使用,參考資料:
7.2 標(biāo)記圖片的技巧
對(duì)移動(dòng)網(wǎng)絡(luò)而言,文件請(qǐng)求次數(shù)和請(qǐng)求文件的大小同樣重要。我們還需要進(jìn)一步優(yōu)化減少請(qǐng)求圖片的次數(shù),而不僅僅是關(guān)注圖片的大小。性能是真正響應(yīng)式設(shè)計(jì)的基本組成部分,既要壓縮圖片,又要減少圖片的數(shù)量。這一節(jié)我們將介紹一些減少圖片請(qǐng)求次數(shù)的技巧。
7.2.1 不要將文字保存成圖片
首先,不要將文字保存成圖片,因?yàn)榉糯蠛髸?huì)失真,還會(huì)使網(wǎng)頁文件變大,造成延遲。使用圖片形式的文字還有一個(gè)問題就是無法被搜索引擎找到,也不能被屏幕閱讀器讀取。正確的做法應(yīng)該是直接把文本覆蓋在圖片上面,這樣圖片和文字就有更好的顯示和放大效果,文本也可以被選中,并且這樣還能更方便的使用CSS來添加效果,文件尺寸也更小。
7.2.2 使用CSS技巧
除了用來調(diào)整樣式屬性,CSS還可以用來實(shí)現(xiàn)其他圖形效果,比如漸變,陰影,圓角或動(dòng)畫效果。但是要注意使用CSS生成這些視覺效果是有處理和渲染成本的,這在移動(dòng)設(shè)備上尤其明顯,要謹(jǐn)慎使用。
關(guān)于如何提升網(wǎng)站在移動(dòng)設(shè)備上的響應(yīng)速度,可以參考這篇文章。
7.2.3 使用符號(hào)字符和圖標(biāo)字體
還有一種方法可以避免使用圖片并保持網(wǎng)站的響應(yīng)性。如果要使用一些圖形標(biāo)志,比如箭頭,星星或者桃心,可以從unicode字符集中找到這樣的字符。
另外,圖標(biāo)字體讓修飾網(wǎng)站的常用圖片和圖標(biāo)使用起來更方便。圖標(biāo)字體相比圖片有很多優(yōu)點(diǎn),它們是矢量圖形,可以無限縮放,整套圖像可以以一套字體的形式下載,而只消耗很小的下載量。
7.2.4 內(nèi)嵌圖片
如果想要減少網(wǎng)頁的文件請(qǐng)求數(shù)量,還可以利用代碼實(shí)現(xiàn)內(nèi)嵌圖片,有兩種實(shí)現(xiàn)方式:SVG或者數(shù)據(jù)URI。內(nèi)嵌的SVG具有很好的移動(dòng)端和PC端瀏覽器支持,優(yōu)化工具還能極大減少SVG的字節(jié)。數(shù)據(jù)URI提供了一種將文件(比如圖片)內(nèi)嵌為base64編碼的字符串的機(jī)制,它也具有很好的瀏覽器支持。它們也可以嵌入到CSS里。
一些參考資料:
7.3 完全響應(yīng)式
在不同的上下文環(huán)境中都使用同一張圖片可能不是一個(gè)好的做法。使用媒體查詢有它自身的一些局限性,首先它不一定能支持未來出現(xiàn)的一些平臺(tái),其次媒體查詢只參考了視窗的大小而不是圖片的實(shí)際尺寸。下面介紹的一些方法采用了另一種截然不同的新思路:給瀏覽器提供信息以讓它在多張圖片中做出最好的選擇。
7.3.1 srcset屬性
img元素的src屬性只能提供一個(gè)圖片文件,而srcset屬性給同一張圖片提供可選擇的多個(gè)文件,可以為更高DPI顯示器選擇更高分辨率的圖片文件,否則使用低分辨率圖片文件。這樣瀏覽器可以根據(jù)視口尺寸和設(shè)備性能做出最合適的選擇。srcset 有兩種自定義方式,一種使用 x 來區(qū)分設(shè)備像素比 (DPR),另一種使用 w 來描述圖像的寬度。對(duì)設(shè)備像素比的反應(yīng):
<img src="image_2x.jpg" srcset="image_2x.jpg 2x, image_1x.jpg 1x" alt="a cool image">
將 srcset 設(shè)置為與逗號(hào)分隔的一連串 filename multiplier 對(duì)相等,其中每個(gè) multiplier 必須是后跟 x 的整數(shù)。例如,1x 表示 1 倍顯示屏,2x 表示像素密度為兩倍的顯示屏,如 Apple 的 Retina 顯示屏。瀏覽器會(huì)下載與其 DPR 對(duì)應(yīng)的最佳圖片。另請(qǐng)注意,有一個(gè)作為備用的 src 屬性。對(duì)圖片寬度的反應(yīng):
<img src="image_200.jpg" srcset="image_200.jpg 200w, image_100.jpg 100w" alt="a cool image">
將 srcset 設(shè)置為與逗號(hào)分隔的一連串 filename widthDescriptor 對(duì)相等,其中每個(gè) widthDescriptor 都以像素為測(cè)量單位, 并且必須是后跟 w 的整數(shù)。在這里,widthDescriptor 指定每個(gè)圖片文件的自然寬度,使瀏覽器能夠根據(jù)窗口大小和 DPR 選擇要請(qǐng)求的最適當(dāng)?shù)膱D片。(如果沒有 widthDescriptor,瀏覽器需要下載圖片才能知道其寬度?。?/p>
7.3.2 sizes屬性
有一點(diǎn)要說明的是,在 JavaScript 中,可以通過 currentSrc 獲得 img 元素的來源。sizes 屬性為瀏覽器提供了有關(guān)圖片元素顯示大小的信息,它實(shí)際上不會(huì)導(dǎo)致圖片大小調(diào)整。該操作是在 CSS 中執(zhí)行的!
包含大小的圖片寬度
如果圖片不以全窗口寬度顯示會(huì)怎樣?那么解析完HTML后,在解析CSS前瀏覽器就會(huì)預(yù)加載圖片。問題是瀏覽器對(duì)圖片尺寸一無所知,我們需要告訴瀏覽器圖片的實(shí)際顯示尺寸。除了 srcset 外,還需要sizes屬性。向包含媒體查詢的圖片添加一個(gè) sizes 屬性和一個(gè) vw 值。srcset 和 sizes 合起來可讓瀏覽器知道圖片的自然寬度以及圖片相對(duì)于窗口寬度的顯示寬度。 知道圖片的顯示寬度和可用圖片文件的寬度后,瀏覽器在解析HTML時(shí)將獲得下載具有滿足其需求的適當(dāng)分辨率且盡可能小的圖片所需的信息。 這里是一個(gè)srcset與sizes配合使用的語法示例:
<img src="images/great_pic_800.jpg"
sizes="(max-width: 400px) 100vw, (min-width: 401px) 50vw"
srcset="images/great_pic_400.jpg 400w, images/great_pic_800.jpg 800w"
alt="great picture">
sizes 由以逗號(hào)分隔的 mediaQuery width 對(duì)組成。sizes 會(huì)在加載流程初期告訴瀏覽器,該圖片會(huì)在點(diǎn)擊 mediaQuery 時(shí)以某個(gè) width 顯示。實(shí)際上,如果 sizes 缺失,瀏覽器會(huì)將 sizes 默認(rèn)為 100vw,表示它預(yù)計(jì)圖片將以全窗口寬度顯示。sizes 會(huì)為瀏覽器額外提供一條信息,以確保它根據(jù)圖片的最終顯示寬度下載正確的圖片文件。說明一下,它實(shí)際上不會(huì)調(diào)整圖片的大小 - 這是 CSS 的工作。在本示例中,如果瀏覽器的窗口寬度等于或小于 400 像素,瀏覽器知道圖片將為全窗口寬度;如果窗口寬度大于 400 像素,則為一半窗口寬度。瀏覽器知道它具有兩個(gè)圖片選項(xiàng):一個(gè)具有 400 像素的自然寬度,另一個(gè)具有 800 像素。
7.3.3 picture元素
新增的picture元素可以通過source元素提供可選擇的源文件:
<picture>
<source srcset="kittens.webp" type="image/webp">
<source srcset="kittens.jpeg" type="image/jpeg">
<img src="kittens.jpeg" alt="Two grey tabby kittens">
</picture>
如果瀏覽器可以使用第一個(gè)資源,則使用它。否則就沿著列表查詢下去。瀏覽器可以根據(jù)設(shè)備性能選擇文件。上面這個(gè)HTML文件為支持webp的瀏覽器選擇webp文件,jpeg作為備選資源。這種方式使得支持webp的平臺(tái)充分利用高性能webp格式。為不支持它的平臺(tái)提供替代方案。
值得注意的是,我們一定要為image元素增加alt屬性,這是一種無障礙性承諾,這是一種對(duì)于視覺障礙者友好的方式。關(guān)于 alt 屬性的一般建議:
對(duì)于重要圖片來說,
alt屬性應(yīng)該具有描述性;對(duì)于純裝飾性的圖片,
alt屬性應(yīng)該為空;應(yīng)該為每張圖片設(shè)置
alt屬性。
八. 參考文獻(xiàn)
-
視口相關(guān)基礎(chǔ)知識(shí):
在移動(dòng)瀏覽器中使用viewport元標(biāo)簽控制布局
-
CSS布局基礎(chǔ):
-
Flex布局相關(guān):
-
Grid布局相關(guān):