
結論先講
很多人寫 RWD 是這樣:
@media (max-width: 1024px) { /* 平板 */ }
@media (max-width: 768px) { /* 手機 */ }
@media (max-width: 375px) { /* 小手機 */ }然後發現 1024px 剛好不包括筆電、768px 大於部分平板、375px 壓根不存在。斷點設錯整個 RWD 崩潰。
現代 RWD 三大改變:
- Mobile-first:先寫手機,斷點用
min-width往上加 - Fluid:用
clamp()/min()/max()讓數值隨視窗流動,減少斷點 - Container Query:不只看視窗,看元件容器的大小
這篇講現代 RWD 的正確思維。
為什麼 Mobile-first
傳統(Desktop-first)寫法
.card { width: 33%; } /* 桌面:3 欄 */
@media (max-width: 1024px) {
.card { width: 50%; } /* 平板:2 欄 */
}
@media (max-width: 768px) {
.card { width: 100%; } /* 手機:1 欄 */
}Mobile-first 寫法
.card { width: 100%; } /* 預設:手機 1 欄 */
@media (min-width: 768px) {
.card { width: 50%; } /* 平板以上:2 欄 */
}
@media (min-width: 1024px) {
.card { width: 33%; } /* 桌面以上:3 欄 */
}為什麼 mobile-first 更好
- 手機 CSS 先載(先級進增強,桌面才疊上去)— 手機載入更快
- 斷點語意清楚:
min-width: 768px= 「768 以上才啟用」 - 不會忘記「手機能看」:從小開始,自然覆蓋所有尺寸
- Tailwind / Bootstrap 預設 mobile-first,跟主流一致
斷點(Breakpoint)怎麼選
不要從裝置尺寸反推。要從內容反推。
錯誤做法
「iPhone 15 Pro Max 是 430px,我用 430 當斷點」 → 明天出新手機就崩。
正確做法
看你的內容在不同寬度下什麼時候開始壞。設在壞掉的那個寬度。
實用斷點建議
現代專案常見:
/* 手機(預設) : 0-640 */
@media (min-width: 640px) { /* sm: 大手機、小平板 */ }
@media (min-width: 768px) { /* md: 平板 */ }
@media (min-width: 1024px) { /* lg: 筆電 */ }
@media (min-width: 1280px) { /* xl: 桌面 */ }
@media (min-width: 1536px) { /* 2xl: 大螢幕 */ }這是 Tailwind 預設的斷點,跟一般裝置對應合理。
為什麼不用 em
@media (min-width: 40em) { ... }有人主張用 em 是為了「使用者放大字體時斷點跟著變」。好處合理,但實務上大多數人不放大字體,用 px 反而直觀。爭議隨你。
Fluid:讓數值流動,少用斷點
傳統:用斷點切換
.title { font-size: 16px; }
@media (min-width: 768px) {
.title { font-size: 20px; }
}
@media (min-width: 1024px) {
.title { font-size: 24px; }
}768px 以下跟 1023px 中間字都是 16px,很醜。
現代:clamp() 流動
.title { font-size: clamp(16px, 2vw + 12px, 24px); }解讀:
- 最小 16px
- 偏好值
2vw + 12px(跟著視窗流動) - 最大 24px
字體連續隨視窗大小變化,沒有「跳動」的瞬間。
clamp() 三個用法
/* 字體 */
font-size: clamp(1rem, 2vw + 0.5rem, 2rem);
/* 容器寬度 */
width: clamp(300px, 50vw, 800px);
/* 間距 */
padding: clamp(16px, 5vw, 64px);min() 跟 max()
/* 不超過 800px,但可以更小 */
width: min(100%, 800px);
/* 至少 16px */
font-size: max(16px, 1vw);實戰上,clamp(a, b, c) 等同 min(max(a, b), c)。
Container Query:容器查詢(遊戲規則改變者)
Media Query 看視窗大小。Container Query 看容器大小。
為什麼重要
你做一張卡片元件。放在:
- Sidebar(窄):應該單欄排列
- Main(中):應該兩欄排列
- Full Width(寬):應該三欄排列
傳統 Media Query 只看視窗寬度,不知道卡片現在在哪個容器裡。同一個元件無法複用。
Container Query 解決這個問題:
/* 宣告 .card-container 是可以被查詢的容器 */
.card-container {
container-type: inline-size;
}
/* 查詢容器本身的寬度 */
@container (min-width: 400px) {
.card {
display: grid;
grid-template-columns: 150px 1fr;
}
}
@container (min-width: 600px) {
.card {
grid-template-columns: 200px 1fr 1fr;
}
}卡片根據自己容器的寬度調整,不管視窗多大。真正的元件化 RWD。
瀏覽器支援
- Chrome 105+(2022-09)
- Firefox 110+(2023-02)
- Safari 16+(2022-09)
2026 年可以放心用。
圖片 RWD:不只是 max-width: 100%
最小做法
img { max-width: 100%; height: auto; }圖片不超出容器,高度自動。但大螢幕還是載大圖,浪費。
進階:srcset + sizes
<img
srcset="
photo-320.jpg 320w,
photo-640.jpg 640w,
photo-1280.jpg 1280w
"
sizes="(max-width: 768px) 100vw, 50vw"
src="photo-640.jpg"
alt="..."
>解讀:
- 提供三種尺寸
sizes告訴瀏覽器圖片實際顯示寬度(看 CSS 會用多寬)- 瀏覽器根據裝置 + DPR(像素密度)自動挑最適合的
<picture> + <source>:Art Direction
桌面用橫幅圖、手機用直幅圖:
<picture>
<source media="(min-width: 768px)" srcset="hero-wide.jpg">
<source media="(max-width: 767px)" srcset="hero-portrait.jpg">
<img src="hero-wide.jpg" alt="...">
</picture>AVIF / WebP:格式 fallback
<picture>
<source type="image/avif" srcset="hero.avif">
<source type="image/webp" srcset="hero.webp">
<img src="hero.jpg" alt="...">
</picture>排版方向:Logical Properties
做國際化 RWD 要懂 logical properties:
| 傳統 | 邏輯 | 阿拉伯文(RTL)時 |
|---|---|---|
margin-left | margin-inline-start | 自動變右邊 |
margin-right | margin-inline-end | 自動變左邊 |
padding-top | padding-block-start | 不變 |
width | inline-size | 橫向尺寸 |
height | block-size | 縱向尺寸 |
直書(日文)跟右到左(阿拉伯)時這組超重要。
Dark Mode:用 prefers-color-scheme
:root {
--bg: white;
--text: black;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #1a1a1a;
--text: #eee;
}
}
body {
background: var(--bg);
color: var(--text);
}系統切換 dark mode 自動變色。
給手動切換按鈕
[data-theme="dark"] {
--bg: #1a1a1a;
--text: #eee;
}JS 切 data-theme 屬性,CSS 變數跟著變。
其他常用 Media Query
/* 降低動畫(使用者勾選減少動態) */
@media (prefers-reduced-motion: reduce) {
* { animation: none !important; transition: none !important; }
}
/* 高對比模式 */
@media (prefers-contrast: high) {
:root { --border-color: black; }
}
/* 列印樣式 */
@media print {
.no-print { display: none; }
}
/* 直橫向 */
@media (orientation: landscape) { ... }實戰 Checklist
- Mobile-first(
min-width往上加) - 斷點從內容反推,不從裝置反推
- 字體/容器/間距用
clamp()流動 - 元件 RWD 用 Container Query
- 圖片用
srcset/<picture> - 支援
prefers-color-scheme: dark - 尊重
prefers-reduced-motion - 國際化用 logical properties
相關文章
- Flexbox — 配合 flex-wrap 做響應式
- Grid —
auto-fit+minmax()是 RWD 神器 - CSS 子 Roadmap
- Frontend Roadmap
