LESSON-10 · 零基礎學生教材
CSS 進階:Mobile First 與 Media Query
讓服務網格與聯絡版面在 390px、768px 與桌機寬度都可閱讀與操作。
先理解:這堂課解決什麼問題?
服務商家的訪客可能用手機、平板或桌機進站,固定桌機欄位會讓手機操作困難。
本堂要完成:讓服務網格與聯絡版面在 390px、768px 與桌機寬度都可閱讀與操作。
學習邊界:先完成「用 Mobile First 與 Media Query 讓服務型網站適應不同寬度」,不提前引入尚未教過的框架或建置工具。
先備知識與操作環境
本堂先備:先知道瀏覽器會讀取 HTML、CSS,並能在編輯器儲存檔案、用瀏覽器開啟 HTML、按右鍵開啟 DevTools。檔案只使用本堂列出的 examples、starter 與 checkpoint 路徑,不需要猜測其他資料夾。
- 檔案位置:先找到
examples/minimal.html、starter/files/index.html、starter/files/style.css、starter/files/main.js、checkpoint/files/style.css,再從本頁的最小實驗開始。 - 瀏覽器:開啟最小實驗與階段頁;每次修改後儲存並重新整理。
- DevTools:依本堂內容使用 Elements、Styles、Computed、Console 或 Network,記下第一個可觀察證據。
- 操作習慣:每次只修改一個檔案或一個責任,先預測、再操作、最後驗收。
先做最小實驗:先看見結果
這不是期末網站,而是一個可以直接看到本堂核心結果的最小實驗。先完成一次操作,再回到檔案和名詞卡對照。
- 入口:開啟
examples/minimal.html。 - 操作:先開啟
examples/minimal.html,在 390px、768px 與桌機寬度各觀察一次,再用 Tab 走過連結、輸入框與按鈕。 - 預期:390px 時服務卡與聯絡區塊各為單欄;768px 以上服務卡為三欄、聯絡區塊為雙欄;沒有水平捲軸且 focus 清楚可見。
- 重設:重新整理
examples/minimal.html,將 DevTools Device Mode 回到 390px 後重新開始。這份最小實驗不需要修改。
學生練習流程
依序完成每一張卡;目前只聚焦一個步驟,先操作,再用可觀察證據確認結果。
-
1
最小實驗
先閱讀本頁的問題、檔案地圖、名詞卡與最小例子。 -
2
Step 2
自己回答互動問答 4 題,再展開解析。 -
3
最小實驗 2
開啟最小實驗,實際操作一次並記下證據。 -
4
Starter
把 Starter 複製到自己的工作資料夾,照 3 張微步驟卡逐一完成;每一步都要看到結果再繼續。 -
5
Checkpoint
前往 Checkpoint,只處理 1 個本堂核心缺口;先預測,再用指定證據驗收。 -
6
Solution
前往 Solution,先看逐檔差異與修改原因,再決定要不要把完整內容帶回自己的檔案。 -
7
變體驗收
完成情境變體與獨立挑戰,留下檔案位置、操作、結果與驗收證據,並閱讀下一堂銜接:下一堂會處理徽章、置頂導覽與浮動聯絡按鈕的定位關係。
檔案地圖:每個位置負責什麼?
先不要急著背檔名;請把檔案位置和責任連起來。你在階段頁會看到同一份檔案的可執行版本。
examples/minimal.html只讀最小實驗:先觀察完整結果,不修改它。starter/files/index.htmlStarter 入口:六張服務卡與聯絡區塊的實際 HTML。starter/files/style.cssStarter CSS:完成 Mobile First、media query 與 focus 的微步驟。starter/files/main.js選用觀察工具:讀取真實 viewport、欄位與 overflow 數值。checkpoint/files/style.cssCheckpoint CSS:故意以 width: 760px 製造 390px 水平溢位。
先學會這些詞
先從名詞、英文與白話意思開始;每次只展開一張名詞卡,再對照正式定義、範例與驗收證據。專業術語、語法、檔案路徑會使用不同樣式。第一次遇到術語時,先回到這裡,不要靠猜。
響應式基礎
5 個詞viewportviewport 白話意思:瀏覽器目前拿來顯示頁面的可視範圍。 展開查看正式定義、範例與驗收證據
- 正式定義
- 使用者代理程式呈現文件內容的視窗區域;本堂用它觀察可用寬度。
- 什麼時候用
- 要測試手機、平板與桌機寬度是否都能閱讀時。
- 最小範例
- DevTools Device Mode 設為 390px,就是在觀察 390px viewport。
- 可觀察證據
- 查看 Device Mode 的寬度、畫面是否出現水平捲軸,以及 document.documentElement.clientWidth。
- 容易混淆
- 和整個瀏覽器視窗混淆;viewport 是頁面內容實際可見的範圍。
selectorselector 白話意思:告訴 CSS 要對哪個 HTML 元素套用規則。 展開查看正式定義、範例與驗收證據
- 正式定義
- CSS 規則中用來匹配文件元素的模式。
- 什麼時候用
- 要控制服務卡父層或聯絡區塊的欄位時。
- 最小範例
- .service-grid 會選到服務卡片的父層。
- 可觀察證據
- 在 Elements 選取元素後,Styles 能看到 selector 是否命中。
- 容易混淆
- 和 property 混淆;selector 決定對誰作用,property 決定要改什麼。
propertyproperty 白話意思:CSS 想要改變的項目名稱。 展開查看正式定義、範例與驗收證據
- 正式定義
- CSS 宣告中描述可設定樣式特性的名稱。
- 什麼時候用
- 要改欄數、寬度、間距或焦點外框時。
- 最小範例
- grid-template-columns 是控制 Grid 欄位的 property。
- 可觀察證據
- Styles 左側看到 property,Computed 看到它最後採用的值。
- 容易混淆
- 和 value 混淆;property 是名稱,value 是實際設定。
valuevalue 白話意思:property 實際採用的設定內容。 展開查看正式定義、範例與驗收證據
- 正式定義
- CSS 宣告中賦予 property 的資料與單位。
- 什麼時候用
- 需要判斷
1fr、760px或minmax(0, 1fr)代表什麼時。 - 最小範例
- grid-template-columns: 1fr 中 1fr 是 value。
- 可觀察證據
- Computed 會顯示瀏覽器計算後的欄位值,例如
390px或多個像素寬度。 - 容易混淆
- 和 property 混淆;
grid-template-columns是 property,1fr是 value。
Mobile FirstMobile First 白話意思:先做最窄、最容易壞的手機單欄,再逐步增加寬版能力。 展開查看正式定義、範例與驗收證據
- 正式定義
- 以小 viewport 的基礎規則作為預設,再以較大的 min-width 條件增強版面。
- 什麼時候用
- 需要讓手機先可讀、桌機再增加欄位時。
- 最小範例
- 基礎 .service-grid { grid-template-columns: 1fr; },再在 760px 以上改成三欄。
- 可觀察證據
- 先測 390px,再測 768px;基礎 CSS 沒有依賴桌機固定欄數。
- 容易混淆
- 和先寫桌機再用 max-width 硬改手機混淆。
Grid 與間距
3 個詞Grid containerGrid container 白話意思:負責安排子元素列欄的父層。 展開查看正式定義、範例與驗收證據
- 正式定義
- 設定
display: grid的元素;其直接子元素會依 Grid 軌道排列。 - 什麼時候用
- 服務卡或聯絡資訊需要二維欄位時。
- 最小範例
- .service-grid { display: grid; gap: 1rem; }。
- 可觀察證據
- 選取
.service-grid,在 Computed 讀到display: grid與grid-template-columns。 - 容易混淆
- 和 Grid item 混淆;本堂先看父層 container,不把 display:grid 加到每張卡。
1frone fraction 白話意思:把剩餘可用空間分成一份。 展開查看正式定義、範例與驗收證據
- 正式定義
- CSS Grid 的 fractional unit,依 Grid 容器剩餘空間分配軌道。
- 什麼時候用
- 想讓欄位流動填滿容器,而不是固定像素時。
- 最小範例
- grid-template-columns: 1fr 1fr 把可用空間分成兩欄。
- 可觀察證據
- 在寬度改變時,Computed 欄位像素值會跟著變化,沒有固定 760px 子欄。
- 容易混淆
- 和
1px混淆;fr是比例單位,不是固定像素。
gapgap 白話意思:Grid 欄與欄、列與列之間的間距。 展開查看正式定義、範例與驗收證據
- 正式定義
- 設定 layout container 內部軌道間距的 CSS property。
- 什麼時候用
- 需要讓多張卡片有一致空隙時。
- 最小範例
- .service-grid { gap: 1rem; }。
- 可觀察證據
- Computed 能讀到 gap;卡片之間的空隙不需要逐張加 margin。
- 容易混淆
- 和 padding 混淆;gap 在子元素之間,padding 在容器內邊界。
斷點與溢位
6 個詞media querymedia query 白話意思:依 viewport 或使用者環境條件選擇是否套用 CSS。 展開查看正式定義、範例與驗收證據
- 正式定義
- 以
@media條件群組 CSS 宣告的條件式規則。 - 什麼時候用
- 內容在寬版有足夠空間時才增加欄位。
- 最小範例
- @media (min-width: 760px) { ... }。
- 可觀察證據
- 在 390px 看不到該規則命中,768px 時 Styles 顯示它覆蓋基礎欄位。
- 容易混淆
- 和 JavaScript if 混淆;本堂用 CSS 條件控制版面,不用 JS 判斷寬度改 CSS。
breakpointbreakpoint 白話意思:版面規則切換的寬度門檻。 展開查看正式定義、範例與驗收證據
- 正式定義
- 使 media query 從不生效變成生效,或讓版面責任改變的條件值。
- 什麼時候用
- 決定服務卡何時從單欄變三欄時。
- 最小範例
- 本堂 breakpoint 是 760px,所以 768px 會套用寬版規則。
- 可觀察證據
- 比較 759px 與 760px 的 Computed 欄位與畫面差異。
- 容易混淆
- 和裝置名稱混淆;breakpoint 應由內容需要的空間決定,不是手機/平板標籤。
min-widthmin-width 白話意思:表示寬度至少達到某個值。 展開查看正式定義、範例與驗收證據
- 正式定義
- 在 media query 中限制條件必須大於或等於指定寬度。
- 什麼時候用
- 用 Mobile First 在寬版增加欄位時。
- 最小範例
- @media (min-width: 760px) 表示 760px 以上才套用。
- 可觀察證據
- 在 390px 規則未命中,768px 規則命中。
- 容易混淆
- 和
max-width混淆;min-width 適合由手機基底往寬版增加能力。
overflowoverflow 白話意思:內容超出容器或 viewport 邊界的狀態。 展開查看正式定義、範例與驗收證據
- 正式定義
- 內容盒超出其可用排版區域時形成的版面溢位。
- 什麼時候用
- 手機出現水平捲軸,或固定寬度讓內容超出畫面時。
- 最小範例
- .page-shell { width: 760px; } 在 390px 會造成水平 overflow。
- 可觀察證據
- 畫面水平捲軸、Elements 選取超出元素,以及 scrollWidth 大於 clientWidth。
- 容易混淆
- 和
overflow-x: hidden混淆;隱藏捲軸不等於修正造成溢位的根因。
scrollWidthscrollWidth 白話意思:內容實際需要的完整寬度。 展開查看正式定義、範例與驗收證據
- 正式定義
- 元素包含不可見溢出內容時的完整內容寬度,以 CSS pixel 表示。
- 什麼時候用
- 需要用數值確認頁面是否比 viewport 寬時。
- 最小範例
- document.documentElement.scrollWidth 讀取整份文件的內容寬度。
- 可觀察證據
- 與
document.documentElement.clientWidth比較;前者不應大於後者。 - 容易混淆
- 和
window.innerWidth混淆;innerWidth 是 viewport,scrollWidth 是內容需求寬度。
focus-visible:focus-visible 白話意思:鍵盤走到元素時顯示清楚的焦點位置。 展開查看正式定義、範例與驗收證據
- 正式定義
- 當瀏覽器判斷使用者需要可見焦點提示時套用的 CSS pseudo-class。
- 什麼時候用
- 驗收連結、輸入框與按鈕能否只用鍵盤操作時。
- 最小範例
- button:focus-visible { outline: 3px solid #f1ab2c; }。
- 可觀察證據
- 按 Tab 逐項移動時,焦點外框清楚可見且沒有被
outline: none移除。 - 容易混淆
- 和
:hover混淆;hover 需要滑鼠,focus-visible 讓鍵盤使用者知道目前位置。
最小例子:先看懂,再複製
這段只保留本堂第一個微成果。先預測結果,再逐行讀;完整檔案請開啟下方最小實驗。
.service-grid,
.contact-layout {
grid-template-columns: 1fr;
}Live Lab:逐段讀碼與驗證
每一步只回答五件事:為什麼做、改哪裡、會看到什麼、用什麼證據確認、卡住先查什麼。
-
Step 1
先建立 Mobile First 單欄基底
- 目的
- 先處理最窄 viewport,建立服務卡與聯絡區塊的預設單欄。
- 修改位置
starter/files/style.css的 TODO-1
將.service-grid與 .contact-layout 的基礎 grid-template-columns 都改為 1fr。- 預期結果
- 390px 下兩個區塊都變成單欄,卡片內容可讀且沒有水平捲軸。
- 驗收證據
- DevTools 390px 畫面;選取兩個 Grid container,在 Computed 讀到 grid-template-columns。
- 卡住先查
- 只檢查
.service-grid的 display、grid-template-columns 與目前是否真的開啟starter/files/index.html。
-
Step 2
用 Media Query 在 760px 增加欄位
- 目的
- 理解 breakpoint 是內容有足夠空間時的切換門檻。
- 修改位置
starter/files/style.css的 TODO-2
加入@media(min-width: 760px),服務卡使用三欄,聯絡區塊使用雙欄。- 預期結果
- 390px 保持單欄;768px 以上服務卡變三欄、聯絡區塊變雙欄。
- 驗收證據
- 比較 390px 與 768px 的畫面、Styles 命中狀態與 Computed 欄位值。
- 卡住先查
- 只看目前 viewport 是否達到 760px,再看
@media是否出現在 Styles 的命中規則。
-
Step 3
用數值與 DevTools 觀察證據
- 目的
- 把『看起來有變』轉成 viewport、欄位與 overflow 的可重現數值。
- 修改位置
starter/files/main.js的 measureLayout;DevTools Device Mode、Computed、Console
按檢查目前版面,讀取 window.innerWidth、scrollWidth、clientWidth 與computedgrid-template-columns。- 預期結果
- 狀態文字與 Console 顯示實際數值;主要驗收仍回到 DevTools 畫面與 Computed。
- 驗收證據
- Console 物件、頁面 status、Computed grid-template-columns,以及 scrollWidth <= clientWidth。
- 卡住先查
- 先檢查 #responsive-status、#measure-layout 與
.service-grid是否存在,再按一次按鈕。
-
Step 4
Checkpoint:找出固定寬度造成的溢位
- 目的
- 練習以症狀、數值與 Elements 找根因,不用 overflow:hidden 隱藏問題。
- 修改位置
checkpoint/files/style.css的 CHECKPOINT-1:.page-shell
先量測 scrollWidth 與 clientWidth,再把.page-shell改為流動的 min(100% - 2rem, 72rem)。- 預期結果
- 修正前後有數值與畫面差異;修正後 390px 沒有水平捲軸。
- 驗收證據
- 修正前後的 scrollWidth、clientWidth、Elements 的
.page-shell寬度與 390px 截圖。 - 卡住先查
- 只做兩件事:先在 Console 比較兩個寬度,再在 Elements 選取
.page-shell。
-
Step 5
用 Tab 驗收 focus 不會消失
- 目的
- 把 responsive 的可用性延伸到鍵盤操作,確保連結、欄位與按鈕仍可找到。
- 修改位置
starter/files/style.css的:focus-visible;starter/files/index.html的互動元素
按 Tab 依序經過品牌連結、跳到表單、輸入框、textarea 與按鈕,確認 focus ring 清楚可見。- 預期結果
- 每個互動元素都能聚焦,focus 外框不會被移除或被內容遮住。
- 驗收證據
- 純鍵盤 Tab 截圖、Computed outline 與互動元素的 DOM 名稱。
- 卡住先查
- 重新整理後只按 Tab,不要先移動滑鼠;第一個檢查是目前 activeElement。
-
Step 6
獨立任務:增加第 4–6 張服務卡
- 目的
- 把規則移植到另一個內容變體,證明理解的是結構與條件,不是只複製畫面。
- 修改位置
- 自己的
starter/files/index.html與style.css
自行新增或改寫第 4–6 張服務卡,保留.service-grid、390px 單欄與 768px 三欄。 - 預期結果
- 新增內容在窄版仍可讀,寬版依同一條 media query 排列,沒有依賴不存在的圖片或頁面。
- 驗收證據
- 390px、768px、桌機三張截圖;服務卡欄位 Computed;scrollWidth <= clientWidth;Tab focus。
- 卡住先查
- 只先用 Elements 數
.service-card,再用 390px 檢查最長的文字是否造成溢位。
讀碼順序:先找入口,再找被引用的檔案,最後用畫面、DOM、Console、Network 或資料結果驗證。
互動問答
先回答目前這一題,再展開解析;完成後按下一題,讓每一次回答都回到檔案或瀏覽器完成驗證。
Q1概念理解 「viewport」在本堂要解決什麼問題? 本題線索:viewport;回到名詞卡與 查看 Device Mode 的寬度、畫面是否出現水平捲軸,以及 document.documentElement.clientWidth。 展開解析收合解析
白話解析:
瀏覽器目前拿來顯示頁面的可視範圍。 正式來說,使用者代理程式呈現文件內容的視窗區域;本堂用它觀察可用寬度。
對照位置:
回到名詞卡「viewport」,再看 查看 Device Mode 的寬度、畫面是否出現水平捲軸,以及 document.documentElement.clientWidth。
預期觀察:
你應該能用自己的話說出:要測試手機、平板與桌機寬度是否都能閱讀時。
常見錯誤:
不要只回答「它是viewport」;那是重複名詞,不是說明責任。
立即驗證:
開啟 examples/minimal.html,依序做「先開啟 examples/minimal.html,在 390px、768px 與桌機寬度各觀察一次,再用 Tab 走過連結、輸入框與按鈕。」並記下畫面或工具證據。
Q2程式碼閱讀
修改指定規則後,你預測畫面會看到什麼?
本題線索:starter/files/style.css 的 TODO-1;要修改:將 .service-grid 與 .contact-layout 的基礎 grid-template-columns 都改為 1fr。;觀察:DevTools 390px 畫面;選取兩個 Grid container,在 Computed 讀到 grid-template-columns。
展開解析收合解析
白話解析:
先看檔案責任,再預測結果。這一步的目的:先處理最窄 viewport,建立服務卡與聯絡區塊的預設單欄。
對照位置:
對照 Live Lab Step 1,位置是 starter/files/style.css 的 TODO-1;範例內容:.service-grid,
.contact-layout {
grid-template-columns: 1fr;
}
預期觀察:
390px 下兩個區塊都變成單欄,卡片內容可讀且沒有水平捲軸。
常見錯誤:
如果只改了檔案但沒有結果,先不要重寫全部;只檢查 .service-grid 的 display、grid-template-columns 與目前是否真的開啟 starter/files/index.html。
立即驗證:
實際操作後檢查 DevTools 390px 畫面;選取兩個 Grid container,在 Computed 讀到 grid-template-columns。。
Q3概念比較
「viewport」和「selector」在本堂的責任有什麼不同?
本題線索:比較 viewport 與 selector;操作位置:starter/files/style.css 的 TODO-2
展開解析收合解析
白話解析:
viewport:瀏覽器目前拿來顯示頁面的可視範圍。;selector:告訴 CSS 要對哪個 HTML 元素套用規則。
對照位置:
對照兩張名詞卡的正式定義:使用者代理程式呈現文件內容的視窗區域;本堂用它觀察可用寬度。/CSS 規則中用來匹配文件元素的模式。
預期觀察:
你應該能指出兩者分別出現在哪個檔案或工具,以及哪一個結果會改變。
常見錯誤:
不要把「改變畫面」當成所有技術的責任;先說清楚誰負責結構、呈現、行為或驗收。
立即驗證:
在 starter/files/style.css 的 TODO-2 做「加入 @media (min-width: 760px),服務卡使用三欄,聯絡區塊使用雙欄。」,再用 比較 390px 與 768px 的畫面、Styles 命中狀態與 Computed 欄位值。 比較前後差異。
Q4除錯驗收
如果完成操作後結果不對,你會先從哪一個證據開始查?
本題線索:自己的 starter/files/index.html 與 style.css;第一個檢查位置:390px、768px、桌機三張截圖;服務卡欄位 Computed;scrollWidth <= clientWidth;Tab focus。
展開解析收合解析
白話解析:
先描述症狀,再提出一個最小假設。本堂常見錯誤是:只把文字貼到頁面外,或為每張卡寫一套不同的固定寬度。
對照位置:
對照最後一段 Live Lab:自己的 starter/files/index.html 與 style.css;檢查方式:只先用 Elements 數 .service-card,再用 390px 檢查最長的文字是否造成溢位。
預期觀察:
你要能指出一個具體位置,而不是一次修改很多檔案。
常見錯誤:
不要先清快取、重裝工具或複製 Solution;先查看第一個可觀察錯誤。
立即驗證:
重新操作並留下「症狀、證據、假設、單一修正、結果」五項紀錄。
常見誤解
- 看到畫面沒有變化,不代表程式沒執行;先確認檔案、路徑、元素與狀態證據。
- 能複製 Solution 不代表理解;請先說出修改哪個檔案、預期哪個結果、用什麼證據確認。
- 本堂只使用既定的 HTML、CSS、JavaScript、Vue CDN、Apps Script mock 與 Cloudflare Pages 驗收範圍。
本堂任務與驗收
讓服務網格與聯絡版面在 390px、768px 與桌機寬度都可閱讀與操作。
- 能用 390px 留下可重現證據。
- 能用 768px 留下可重現證據。
- 能用 桌機三種 viewport 留下可重現證據。
- 能用 scrollWidth 與欄位變化證據 留下可重現證據。
- Starter、Checkpoint、Solution 的入口都能開啟並知道三者差異。
- 遇到問題時能先寫出症狀,再檢查一個最小假設。