RWD 響應式設計

隨著行動裝置的普及,RWD 可以說是現今網頁開發中必備的一項技能,剛好最近也學到這方面的知識,藉此機會寫一篇筆記,提供自己後續資料的查找。


RWD 在做什麼?

響應式網頁設計(Responsive Web Design),是為了因應現今網頁瀏覽裝置的多樣性,而衍生出來的一網頁設計模式;能夠讓一個網頁在多種裝置寬度下,呈現出不同的內容排版。

初始設置

語法

要使網頁符合 RWD 條件,就必須在 head 標籤內層加入以下設定:

1
<meta name="viewport" content="width=device-width, initial-scale=1.0">

上述語法中的 viewport 代表視埠,可以理解成可視區域,在後方可以看到 width=device-width 與 initial-scale=1.0 兩個參數,前者表示強制讓網頁的解析度等於瀏覽裝置的寬度,後者則是設定網頁的縮放比例為 1 倍。

viewport 可設定參數分別有以下幾種:

  • width(設定寬度)
  • height(設定高度)
  • initial-scale(設定初始縮放比例)
  • minimum-scale(設定最小縮放比例)
  • maximum-scale(設定最大縮放比例)
  • user-scalable(是否允許畫面縮放)

檢視前後差異

以 Chrome 瀏覽器為例,網頁在加上 viewport 的語法後,可以透過開發人員工具的 toggle device toolbar 功能來檢視是否載入成功,而先前的語法中分別設定了 width 以及 initial-scale,因此將瀏覽裝置變更為手機後,網頁中的文字會保持原本大小,並且內容會被侷限在裝置的寬度範圍裡,不會產生 x 軸

補充說明:上述提到的 x 軸,是指瀏覽器底部的水平移動軸(scroll bar)。

Media Queries

media 是在設計響應式網頁時,必然會使用到的語法,而 Media Queries(媒體查詢)的作用是偵測使用者目前裝置的屬性(如裝置寬度),並針對這些屬性定義樣式。

媒體類型

根據 W3C 文件中所列出的媒體類型,目前主要有以下幾種:

  • all(所有裝置)
  • print(印刷裝置)
  • screen(螢幕裝置)
  • speech(朗讀裝置)

備註:後續內容會著重在網頁上會使用的相關設定。

設定方式(CSS)

以下原始碼只有指定 media 類型,因此只要裝置類型為螢幕(screen)時,就會載入樣式。

1
2
3
@media screen {
/* CSS Style */
}

以下原始碼除了指定 media 類型之外,還使用了 Queries 的判斷條件 and,此時需要符合裝置為螢幕,以及畫面的最大寬度為 768 像素,才會載入樣式。

1
2
3
@media screen and ( max-width: 768px ) {
/* CSS Style */
}

判斷條件也可以設定多個,以下方原始碼為例:

1
2
3
@media screen and ( min-width: 375px ) and ( max-width: 768px ) {
/* CSS Style */
}

除了上述的 and,還可以使用 or、not、only 來設定判斷條件,在此不討論。

如果不指定 media 類型,判斷的裝置類型就會是 all(所有裝置),此時 and 也可以省略,設定方式如下:

1
2
3
@media ( max-width: 768px ) {
/* CSS Style */
}

寬度設定類型

因為響應式網頁的運作方式是根據裝置的寬度,而相關的設定可使用以下兩種:

max-width

表示最大寬度在設定的數值(含)以下時,範例原始碼如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
h1 {
color: red;
}
/* 斷點一 */
@media ( max-width: 768px ) {
h1 {
color: green;
}
}
/* 斷點二 */
@media ( max-width: 375px ) {
h1 {
font-size: 24px;
}
}

假設目前瀏覽器寬度為 1024 像素,此時 h1 的字體顏色為紅色,接著嘗試使用 iPad Mini(768*1024)進行瀏覽,此時就會滿足斷點一的條件並載入樣式,使 h1 的顏色變更為綠色。

因為 CSS 權重觀念,Media Queries 的樣式載入後,前者相同屬性的樣式就會被後者載入的樣式覆蓋。

同理,如果將瀏覽裝置切換成 iPhone SE(375*667),就會滿足斷點二的條件,並將 h1 的字體大小設定為 24 像素。

min-width

表示最小寬度在設定的數值(含)以上時,範例原始碼如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
h1 {
color: green;
font-size: 24px;
}
/* 斷點一 */
@media ( min-width: 768px ) {
h1 {
font-size: 32px;
}
}
/* 斷點二 */
@media ( min-width: 992px ) {
h1 {
color: red;
}
}

min-width 是依據最小寬度來載入樣式,以此例子來說,在未滿足任何斷點時,文字大小都會是 24 像素,即使斷點一、二的撰寫位置在下方,也會因為沒有滿足媒體查詢條件而使樣式不被套用。

差異與影響

因為 CSS 的載入邏輯是先判斷權重,再判斷先後順序,因此若是使用 max-width 來設計響應式網頁,在行動裝置上 Media Queries 就會因為符合所有斷點條件使樣式從電腦版一路覆蓋到行動版;但如果是使用 min-width,在行動裝置上就不會有樣式覆蓋的問題,不過使用上並不會有影響,依照習慣擇一使用即可。

讓網頁自適應寬度

一般網頁在沒有設計響應式的情況下,最外層容器都會設定一個固定寬度,範例如下:

1
2
3
4
5
6
<!-- HTML -->
<body>
<div clss="container">
<header>...</header>
</div>
</body>
1
2
3
4
/* CSS */
.container {
width: 1000px;
}

但是在響應式網頁中,如果使用 width 來設定容器寬度,會造成網頁在縮放時,因為寬度固定而無法使內容自適應寬度,導致產生 x 軸,以上方範例來說,手動調整瀏覽器寬度到 1000 像素以下時,網頁的寬度還是 1000 像素,因此部分內容會被隱藏到可視範圍外,需要拖曳瀏覽器底部的 x 軸,才能看到被隱藏的內容。

所以如果要讓上方原始碼具有響應式網頁的功能,就必須將最外層容器原本設定的屬性 width 更改為 max-width(最大寬度),設定方式如下:

1
2
3
4
/* CSS */
.container {
max-width: 1000px;
}

如此一來,任意調整瀏覽器寬度時,最外層容器的寬度就會是瀏覽器當下的寬度,並且最大不會超過容器本身的寬度。

CSS Reset

大部分的網頁在開始設定樣式之前,都會先載入習慣的 CSS Reset 設定,而在響應式網頁中,會建議另外加上幾個 Reset 設定。

設定圖片

設定方式如下:

1
2
3
4
img {
max-width: 100%;
height: auto;
}

假設網頁中的任意一張圖片原始大小為 900 像素,此時如果將瀏覽器寬度調整至小於 900 像素時,圖片預設還是會保持原本的大小,造成網頁產生 x 軸,但如果使用上述設定,圖片就會根據父層元素的寬度,以原始比例自動調整大小,並且最大不會超過圖片原始大小。

屬性 max-width 若改為 width,可能會因為圖片解析度較小而失真。

設定容器寬度

一般情況下,網頁容器設定 Padding、Margin 或 Border 後,容器本身實際寬度都會改變,以下方原始碼為例:

1
2
<!-- HTML -->
<div class="box">...</div>
1
2
3
4
5
6
/* CSS */
.box {
width: 100px;
margin: 10px;
padding: 5px;
}

上述 box 區塊在載入樣式後,寬度不是 width 所設定的 100 像素,而是 100 + 10 * 2 + 5 * 2,因此實際寬度會變成 130 像素,這樣在網頁排版時,會因為需要計算容器寬度而變得相當麻煩。

為了避免發生這方面的問題,可以在排版之前先加入以下設定:

1
2
3
*,*::before,*::after {
box-sizing: border-box;
}

加入這段設定後,元素的寬度與高度就不會包含 Padding、Border 所產生的距離,可以理解成實際寬度等於設定的寬度(width、max-width)。

margin 不在 border-box 範疇之內。

使用百分比控制寬度

在響應式網頁中,也常會使用百分比(%)單位來設計網頁元素的排版,而使用百分比的元素會根據父層元素的寬度,自適應調整自身的寬度與高度。

以下方原始碼為例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- HTML -->
<div class="wrap">
<ul>
<li>
<h2>圖片一</h2>
<img src="path" alt="desc">
</li>
<li>
<h2>圖片二</h2>
<img src="path" alt="desc">
</li>
<li>
<h2>圖片三</h2>
<img src="path" alt="desc">
</li>
</ul>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/* CSS / 假設已載入 meyerweb reset */
*,*::before,*::after {
box-sizing: border-box;
}
img {
max-width: 100%;
height: auto;
}
.wrap {
max-width: 1000px;
}
ul {
display: flex;
flex-wrap: wrap;
}
li {
width: 33.33%;
padding: 10px;
margin-bottom: 10px;
}
/* 斷點一 */
@media ( max-width: 768px ) {
li {
width: 50%;
}
}

上述範例在 ul 使用了 flex 屬性值,讓內層的元素 li 並排,而 li 因為設定了寬度 33.33%,因此當瀏覽器寬度在 1000 像素或以上時,li 會以三個並排的方式呈現;當瀏覽器寬度在 768 像素或以下時,斷點一的條件就會滿足,使該斷點的樣式設定覆蓋原先的設定,因為 ul 有設定 wrap 屬性值,因此 li 會以兩個並排的方式呈現。

斷點規劃

雖然在設計響應式網頁時,可以新增斷點讓網頁在不同瀏覽裝置上呈現不同排版,但是礙於現今裝置的多樣性,並沒有辦法透過幾個斷點就兼容所有瀏覽裝置,因此只能針對當下較熱門的解析度來設定斷點內容。

可以使用 statcounter 工具來查詢目前熱門的螢幕解析度,並規劃網頁的斷點。

表格設計

電腦版網頁中的表格在轉換至行動版時,為了避免瀏覽器寬度不足而擠壓到內容,可透過 display 設定屬性來將較不重要的欄位隱藏,以下為範例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- HTML -->
<div class="wrap">
<table>
<tr>
<th class="d-none">訂單編號</th>
<th>姓名</th>
<th>品項</th>
<th>產品價格</th>
</tr>
<tr>
<td class="d-none">001</td>
<td>皮卡丘</td>
<td>雷之石</td>
<td>1500</td>
</tr>
</table>
</div>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* CSS */
.wrap {
max-width: 500px;
}
table {
width: 100%;
text-align: center;
}
th, td {
border: 1px solid #eee;
}
@media ( max-width: 375px ) {
.d-none {
display: none;
}
}

上述為簡易的後台訂單表格,因為在 CSS 第 12 行設定了 Media Queries 的斷點設定,因此該表格在瀏覽器寬度 375 像素以下時,被加上 d-none 類別的 th 標籤與 td 標籤就會被隱藏。

但如果遇到在行動裝置上,表格的所有欄位都要顯示時,也可以透過以下方式來保留所有內容並防止內容擠壓,範例原始碼如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- HTML -->
<div class="wrap">
<table>
<tr>
<th>訂單編號</th>
<th>姓名</th>
<th>品項</th>
<th>產品價格</th>
</tr>
<tr>
<td>001</td>
<td>皮卡丘</td>
<td>雷之石</td>
<td>1500</td>
</tr>
</table>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* CSS */
.wrap {
max-width: 500px;
}
table {
width: 100%;
text-align: center;
}
th, td {
border: 1px solid #eee;
}
@media ( max-width: 375px ) {
.wrap {
overflow-x: auto;
}
table {
width: 375px;
}
}

上述範例與先前內容相同,但是在 Media Queries 的設定裡,針對表格的外容器 wrap 設定了 overflow-x 的屬性與對應值 auto,這種設定方式能夠使內容因擠壓而超出元素寬度時,使該容器本身產生 x 軸,而在 CSS 第16 行的部分因為將表格設定了固定寬度,因此就算瀏覽器寬度小於表格寬度也不會被擠壓,而是隱藏在外容器產生的 x 軸外。

網頁優化

這一部分的內容與 RWD 較不相關,但也建議學會的小技巧!

使用圖片取代文字

LOGO 是用來識別一個網站的重要圖片元素,而 h1 標籤通常是網頁中最重要的內容之一,可以透過以下技巧,將 LOGO 以 h1 標籤的方式撰寫,並將 h1 標籤中的文字隱藏不顯示,範例原始碼如下:

1
2
3
4
<!-- HTML -->
<h1>
<a class="logo" href="index.html">最重要網頁標題</a>
</h1>
1
2
3
4
5
6
7
8
9
10
11
/* CSS */
h1 .logo {
background-image: url('images/logo.svg'); /* 推薦使用 svg 圖片格式 */
display: block;
width: 200px; /* 視圖片本身寬度而定 */
height: 100px; /* 視圖片本身高度而定 */
background-size: contain; /* 使圖片自適應在寬度與高度(200*100)之中 */
text-indent: 101%;
white-space: nowrap;
overflow: hidden;
}

上述範例中,CSS 第 3~7 行的部分較容易理解,主要是設定背景圖片,而第 8 行開始,text-indent 的屬性值設定 101% 可使文字縮排至本身寬度以外,white-space 的屬性值 nowrap 則是能讓內容超過最大寬度時不會自動斷行,最後再透過 overflow 使寬度以外的部分隱藏不顯示。

圖片取代文字的用意,在於 LOGO 在網頁上呈現的結果雖然是一張圖片,但是搜索引擎的爬蟲機器人還是能夠抓取到被隱藏的文字內容,會比較有利於 SEO。

參考資料

RWD - The Viewport
CSS Media Queries 詳細介紹


RWD 響應式設計
http://kurifu.tw/2022-03-14-rwd-note/
作者
Cliff Chu
發布於
2022年3月14日
許可協議