Learning Objectives
- 說明 viewport meta 的作用,以及手機上少了它會發生什麼事
- 用 @media (min-width: …) 寫出行動優先的樣式,並依內容決定斷點
- 用 rem、%、max-width 等相對單位,讓版面跟著螢幕寬度縮放
- 用 clamp() 設定會隨視窗寬度變化、但有上下限的字級
- 讓圖片不超出容器,並處理比螢幕還寬的表格
同一個網頁,在手機和電腦上都要好用
你用手機打開社團的活動頁,字小到要用兩根手指放大,表格要左右拖來拖去才看得完; 同一頁在電腦上看卻很正常。這是因為那個網頁只照著某一種螢幕寬度設計。
響應式設計(responsive web design)的意思是:同一份 HTML,用 CSS 依照螢幕寬度調整版面, 讓手機、平板、筆電都能好好閱讀。它不是替手機另外做一個網站,而是讓同一頁自己適應。
| 寬度大約 | 常見的裝置 | 版面可能長這樣 |
|---|---|---|
| 320~480px | 手機直拿 | 一欄,卡片上下排 |
| 600~900px | 手機橫拿、小平板 | 兩欄 |
| 1000px 以上 | 筆電、桌機 | 三、四欄,旁邊多一條側欄 |
這一課用到的工具你在前幾課都學過:Grid(第 19、20 課)、Flexbox(第 17、18 課)、單位(第 9 課)。 新的只有兩樣:viewport meta 和媒體查詢(media query)。
viewport meta:請手機用真正的寬度排版
早期的網頁都是照桌機寬度做的。手機瀏覽器為了讓這些網頁不要排壞,會先假裝自己的螢幕比較寬 (例如用 980px 寬的「虛擬視窗」排版),排好之後再整頁縮小塞進手機螢幕。結果就是字變得很小。
在 <head> 裡加這一行,告訴手機瀏覽器「這一頁有做手機版,請用螢幕真正的寬度排版」:
<meta name="viewport" content="width=device-width, initial-scale=1">
| 寫法 | 意思 |
|---|---|
width=device-width |
虛擬視窗的寬度=裝置螢幕的寬度(以 CSS 像素計) |
initial-scale=1 |
一打開就是 100% 的縮放,不要自動縮小 |
少了這一行,手機會用比較寬的虛擬視窗排版,你為窄螢幕寫的媒體查詢根本不會生效。
不要加
user-scalable=no或maximum-scale=1禁止縮放。視力不好的人需要放大才能閱讀; 不少手機瀏覽器也會直接忽略這個設定。
媒體查詢與行動優先
媒體查詢讓一段 CSS 只在符合條件時生效。最常用的條件是視窗寬度:
.cards { /* 所有寬度都套用 */
display: grid;
grid-template-columns: 1fr; /* 一欄 */
}
@media (min-width: 600px) { /* 寬度 ≥ 600px 才套用 */
.cards {
grid-template-columns: repeat(2, 1fr);
}
}
min-width: 600px 的意思是「視窗至少 600px 寬」,所以 600px、800px、1200px 都符合。
行動優先(mobile first)的寫法是:
- 不在媒體查詢裡的規則,先寫最窄螢幕的版面(通常是一欄)。
- 再用
min-width一層一層往寬的螢幕加上變化。 - 媒體查詢依寬度由小到大排列。
為什麼要由小到大?因為寬度 1000px 時,min-width: 600px 和 min-width: 900px 兩個都符合,
權重又一樣(都是 .cards),所以寫在後面的贏(第 11 課的層疊規則)。
把 900px 那條寫在 600px 前面,寬螢幕就永遠只看到兩欄。
斷點(breakpoint)是版面改變的寬度。斷點依內容決定,不依裝置型號: 把預覽寬度慢慢拉寬,看到一行字太長、卡片太寬、空白太多的地方,就是該加斷點的地方。 手機型號每年都在變,照某一支手機的寬度寫斷點,很快就過時了。
小測驗:viewport 與媒體查詢
@media (min-width: 768px) { … } 裡的規則,在哪些視窗寬度會生效?
一個網頁寫了 @media (min-width: 600px) 的兩欄版面,卻忘了加 viewport meta。用手機直拿(螢幕約 390px 寬)打開,最可能看到什麼?
視窗寬 1000px,下面的 CSS 讓 .cards 變成幾欄?
.cards { display: grid; grid-template-columns: 1fr; }
@media (min-width: 900px) { .cards { grid-template-columns: repeat(4, 1fr); } }
@media (min-width: 600px) { .cards { grid-template-columns: repeat(2, 1fr); } }
決定斷點最好的方法是?
相對單位與 clamp()
寫死的 width: 700px 在 360px 寬的手機上一定會超出畫面。響應式的版面多用相對單位:
| 單位 | 相對於 | 常見用途 |
|---|---|---|
% |
父元素(寬度、內距等) | width: 100% |
rem |
根元素 html 的字級(瀏覽器預設通常是 16px) | 字級、間距、max-width: 40rem |
em |
自己的字級(用在 font-size 時是父元素的字級) | 按鈕內距跟著按鈕字級變 |
vw/vh |
視窗寬度/高度的 1% | 滿版區塊、隨視窗變化的字級 |
兩個實用的寫法:
max-width取代width:max-width: 40rem表示「最寬 40rem,螢幕比較窄時就跟著變窄」。 文章欄寬限制在 35~45rem 左右,一行字不會長到讀不完。- 字級用 rem:使用者在瀏覽器設定把預設字級調大時,用 rem 的文字會跟著變大;寫死 px 的不會。
想讓標題在手機上小一點、在大螢幕上大一點,可以用 clamp(最小值, 理想值, 最大值):
h1 {
font-size: clamp(1.5rem, 6vw, 3rem);
}
瀏覽器先算「理想值」6vw,再把它限制在最小值與最大值之間:
| 視窗寬度 | 6vw 算出來 | 實際字級(根字級 16px) |
|---|---|---|
| 360px | 21.6px | 24px(比最小值 1.5rem=24px 小,用最小值) |
| 640px | 38.4px | 38.4px(在範圍內) |
| 1280px | 76.8px | 48px(比最大值 3rem=48px 大,用最大值) |
只寫
font-size: 6vw的話,使用者用瀏覽器放大頁面時字幾乎不會變大(vw 只看視窗寬度)。 在 clamp() 裡用 rem 當上下限,並讓最大值至少是最小值的兩倍,放大頁面時文字才有空間跟著變大。
圖片與寬表格
圖片:圖片預設用自己的原始寬度顯示,640px 寬的圖放在 360px 的手機上一定會超出畫面。加兩行就能解決:
img {
max-width: 100%; /* 最寬不超過容器 */
height: auto; /* 高度跟著寬度等比例縮放,不會變形 */
}
用 max-width 而不是 width: 100%:小圖不會被硬拉大到模糊,大圖在窄螢幕才縮小。
同一張圖要在不同螢幕載入不同尺寸的檔案,可以用第 5 課的 srcset。
寬表格:有五、六欄的表格很難塞進 360px。常見的處理方式:
| 做法 | 適合 |
|---|---|
表格外面包一層 div,設 overflow-x: auto |
欄位都很重要、要能左右對照(課表、成績表) |
| 縮小內距與字級、讓長字可以換行 | 欄位不多,只是有點擠 |
| 在窄螢幕把每一列改排成一張卡片 | 每一列是一筆獨立資料(活動清單) |
第一種最簡單:只有表格那一塊可以左右捲動,整個頁面不會跟著左右晃。 整頁可以橫向捲動通常代表有東西超出畫面,是響應式版面最常見的錯誤。
小測驗:單位、clamp() 與圖片
根元素字級是 16px,font-size: clamp(1rem, 4vw, 2rem) 在視窗寬 1000px 時是多大?
img { max-width: 100%; height: auto; } 對一張 300px 寬的小圖、放在 800px 寬的容器裡,會怎樣?
使用者在瀏覽器設定裡把預設字級從 16px 調成 20px,網頁沒有另外設定 html 的字級。font-size: 1rem 的文字會顯示多大?
一個 6 欄的成績表在手機上超出畫面,下面哪個做法最妥當?
重點整理
<meta name="viewport" content="width=device-width, initial-scale=1">:請手機用真正的寬度排版;不要禁止縮放。- 行動優先:基本規則寫最窄的版面,再用
@media (min-width: …)往寬的螢幕加變化,媒體查詢由小到大排列。 - 斷點依內容決定:版面開始變難看的地方,就是斷點。
- 用
max-width、%、rem取代寫死的 px 寬度;字級用 rem,使用者調大預設字級時才會跟著變。 clamp(最小, 理想, 最大)做出隨視窗變化、但有上下限的字級。img { max-width: 100%; height: auto; }讓圖片不超出容器;寬表格用overflow-x: auto的外框。- 檢查響應式版面最快的方法:把視窗拉到最窄,看整頁會不會左右捲動。
下一課講轉場、動畫與 CSS 變數:讓按鈕的顏色慢慢變化、做出載入中的動畫,並用變數一次切換整頁的深色模式。