商用網站架設實務

LESSON-11 · starter

CSS 進階:Position、Sticky 與堆疊

你會依序完成4個本堂專屬微步驟;每一步只修改一個責任,看到結果後才進下一步。 這頁用 可觀察證據anchor 指出下一個動作。

Starter4 個小成果
Checkpoint一個核心缺口
Solution5 個差異

開始前確認

這一頁的結果:入口頁與四個定位實驗都可以開啟

工作方式:先把這一階段複製到自己的工作資料夾,開啟 files/index.html,記下修改前的畫面、Elements、Styles、Computed、捲動與 Tab狀態。

會用到的檔案:index.htmlstyle.css

本堂焦點:用 Position 控制元素參考點、捲動行為與前後層級

照這個順序做

一次只做一張卡。完成後先重新整理入口,再留下證據,才進入下一張。

TODO-1

比較 static 的 normal flow 與 relative 保留原本空間後的位移。

目的

比較 staticnormal flowrelative 保留原本空間後的位移。

修改檔案

style.css

程式碼位置

.flow-card--moved

現在要做:請在 style.css 的「.flow-card--moved」位置完成:替第二張流程卡加入 position: relative 與 offset

貼上位置:style.css:.flow-card--moved 區塊,先保留同一檔案的其他內容。

.flow-card--moved {
  position: relative;
  top: 1rem;
  left: 1rem;
}

預期結果:第二張卡片往右下移動,但第三張卡片仍保留原本的文件流位置。

驗收證據:Computedposition、top、left,以及第二與第三張卡片的畫面位置。

卡住時先看這裡

常見錯誤:改成 absolute,或以 margin 位移後就當成 relative

第一個檢查:先確認 index.html 有三張 .flow-card,且只檢查第二張 .flow-card--moved。

TODO-2

分辨正常文件流與 absolute 元素的關係。

目的

分辨正常文件流與 absolute 元素的關係。

修改檔案

index.html

程式碼位置

.featured-badge

現在要做:請在 index.html 的「.featured-badge」位置完成:加入推薦標籤並放在服務卡的定位範圍內

貼上位置:index.html:.featured-badge 區塊,先保留同一檔案的其他內容。

<article class="service-card service-card--featured"><span class="featured-badge">推薦</span><h2>定期維護</h2></article>

預期結果:推薦標籤貼在指定卡片角落,不影響其他卡片排版。

驗收證據:Elements 父層與捲動畫面位置。

卡住時先看這裡

常見錯誤:absolute 元素沒有定位父層,跑到 viewport 角落。

第一個檢查:先找最近的 position:relative 父元素。

TODO-3

理解 sticky 依賴捲動與定位參考。

目的

理解 sticky 依賴捲動與定位參考。

修改檔案

style.css

程式碼位置

.site-header

現在要做:請在 style.css 的「.site-header」位置完成:建立 sticky 頁首並設定 top: 0

貼上位置:style.css:.site-header 區塊,先保留同一檔案的其他內容。

.site-header {
  position: sticky;
  top: 0;
  z-index: 10;
}

預期結果:捲動內容時頁首停在容器頂端。

驗收證據:捲動畫面、Computed position 與 top。

卡住時先看這裡

常見錯誤:沒有足夠內容可以捲動,誤以為 sticky 沒作用。

第一個檢查:先確認頁面真的可以捲動,再查看 position

TODO-4

理解 fixed 以 viewport 為參考,並處理它可能遮住內容與鍵盤焦點的問題。

目的

理解 fixedviewport 為參考,並處理它可能遮住內容與鍵盤焦點的問題。

修改檔案

index.html、style.css

程式碼位置

.floating-contact、.stack-card--front、.page-shell

現在要做:請在 index.htmlstyle.css 的「.floating-contact、.stack-card--front、.page-shell」位置完成:加入 fixed 聯絡入口,完成 z-index 重疊與底部安全距離

貼上位置:index.htmlstyle.css:.floating-contact、.stack-card--front、.page-shell 區塊,先保留同一檔案的其他內容。

<a class="floating-contact" href="#contact">聯絡我們</a>

.page-shell { padding-bottom: 6rem; }
.stack-card--front { z-index: 2; }
:focus-visible { outline: 3px solid #1d4ed8; outline-offset: 3px; }

預期結果:聯絡入口固定在右下角但不遮住最後文字,兩張重疊卡片可比較前後層級,Tab focus 清楚可見。

驗收證據:捲動前後位置、Elements 的 href、兩張卡片的 Computed z-index、390px/200% 文字與 Tab。

卡住時先看這裡

常見錯誤:只提高 z-index 卻沒有實際重疊元素、底部留白或 focus-visible

第一個檢查:先確認 fixed CTA 是 a,接著分別檢查 padding-bottom、兩張 stack card 與 :focus-visible

階段檔案

完整檔案收在可展開的卡片中;先完成上方微步驟,再用這裡查閱與複製。檔案位置要和目前的相對路徑一致。

開啟 starter 的可執行入口

index.html入口頁:包含服務卡、長內容、重疊卡片、可聚焦控制項與定位任務。

這段要貼在哪裡:先在自己的工作資料夾建立同名相對位置,再複製內容。

<!doctype html>
<html lang="zh-Hant"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>安心維護|定位練習</title><link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Crect width='16' height='16' rx='4' fill='%230f4c5c'/%3E%3C/svg%3E"><link rel="stylesheet" href="style.css"></head>
<body><header class="site-header"><a class="brand" href="#top">安心維護</a><nav aria-label="主要導覽"><a href="#services">服務</a><a href="#evidence">驗收</a><a href="#contact">聯絡</a></nav></header>
<main id="top" class="page-shell"><p class="eyebrow">LESSON-11 · 用 Position 控制元素參考點、捲動行為與前後層級</p><h1>讓定位關係可以被看見</h1><p class="page-description">本頁用服務卡、長內容、固定入口與重疊卡片,觀察元素相對誰定位,以及如何留下畫面與 DevTools 證據。</p><section class="flow-demo" aria-labelledby="flow-title"><h2 id="flow-title">normal flow 與 relative</h2><article class="flow-card">第一張卡片:static 的 normal flow。</article><article class="flow-card flow-card--moved">第二張卡片:Starter 請讓它使用 relative。</article><article class="flow-card">第三張卡片:觀察它是否保留原本位置。</article></section>
<section id="services" aria-labelledby="services-title"><h2 id="services-title">服務方案</h2><article class="service-card service-card--featured"><!-- TODO-2:加入 .featured-badge,讓推薦方案有可觀察的 absolute 子元素。 --><h3>定期維護</h3><p>推薦方案的 badge 應貼在這張卡片右上角,不應把其他內容往下推。</p><a href="#evidence">查看定位證據</a></article><article class="service-card"><h3>到府諮詢</h3><p>這張卡片留在 normal flow,方便和推薦卡比較。</p></article></section>
<section class="long-content" aria-labelledby="scroll-title"><h2 id="scroll-title">長內容與捲動</h2><p>內容刻意保留足夠高度,讓 sticky header 的前後狀態可以觀察。</p><p>在這裡按 Tab 也能確認 header、連結與固定入口的操作順序。</p><p>固定元素不會自動替內容讓出空間,所以頁面底部需要安全距離。</p><p>把 viewport 切換到 390px,再檢查長文字、按鈕與卡片是否仍可讀。</p><p>將瀏覽器文字放大到 200%,確認內容沒有依賴固定高度或水平捲軸。</p><p>這些段落讓 sticky、fixed 與 overflow 的差異有實際畫面證據。</p></section>
<section id="evidence" class="stack-demo" aria-labelledby="stack-title"><h2 id="stack-title">z-index 重疊實驗</h2><article class="stack-card stack-card--back">後層卡片:z-index 1</article><article class="stack-card stack-card--front">前層卡片:z-index 2</article></section>
<section id="contact" aria-labelledby="contact-title"><h2 id="contact-title">聯絡與鍵盤驗收</h2><p>請只用 Tab 走過導覽、卡片連結、固定 CTA 與下面的按鈕。</p><button type="button">可聚焦的按鈕</button> <a href="#top">回到頁面頂端</a></section></main><!-- TODO-3:加入 href="#contact" 的 .floating-contact fixed 聯絡入口。 -->
<!-- TODO-4:完成 fixed CTA 的內容安全距離、z-index 與 focus-visible 驗收。 --></body></html>
style.css定位樣式:集中觀察 normal flowrelativeabsolutestickyfixedz-indexfocus-visible

這段要貼在哪裡:先在自己的工作資料夾建立同名相對位置,再複製內容。

:root { font-family: system-ui, -apple-system, "Segoe UI", "Noto Sans TC", sans-serif; color: #17324d; background: #f5f8fb; } * { box-sizing: border-box; } body { margin: 0; min-height: 100vh; line-height: 1.7; }
.site-header { width: 100%; padding: .9rem max(1rem, calc((100% - 820px) / 2)); display: flex; justify-content: space-between; gap: 1rem; align-items: center; background: #0f4c5c; color: #fff;  } .site-header nav { display: flex; flex-wrap: wrap; gap: .75rem; } .site-header a { color: #fff; }
.page-shell { width: min(100% - 2rem, 820px); margin: 0 auto; padding: 2rem 2rem 1rem; background: #fff; } .eyebrow { color: #075985; font-weight: 800; } .page-description { color: #52657d; } section { margin-block: 2rem; }
.flow-demo { display: grid; gap: .75rem; } .flow-card { padding: 1rem; border: 1px solid #b9cddd; border-radius: .6rem; background: #f8fafc; } .flow-card--moved { /* TODO-1:請加入 position: relative、top 與 left,觀察原本空間仍被保留。 */ border-color: #0f766e; background: #ecfdf5; }
.service-card { position: static; min-height: 10rem; padding: 1.25rem; border: 2px solid #b9cddd; border-radius: .75rem; background: #fff; } .service-card--featured { border-color: #0f766e; position: relative; } .featured-badge { position: absolute; top: .75rem; right: .75rem; padding: .25rem .6rem; border-radius: 999px; background: #9a3412; color: #fff; font-weight: 800; }
.long-content { min-height: 125vh; padding-block: 1rem; } .stack-demo { position: relative; min-height: 14rem; } .stack-card { position: absolute; width: min(70%, 22rem); padding: 1rem; border: 2px solid #17324d; border-radius: .75rem; } .stack-card--back { top: 1rem; left: 1rem; z-index: 1; background: #dbeafe; } .stack-card--front { top: 4rem; left: 4rem; background: #fed7aa;  }
.floating-contact { position: fixed; right: 1rem; bottom: 1rem; z-index: 20; padding: .7rem 1rem; border-radius: .55rem; background: #9a3412; color: #fff; font-weight: 800; text-decoration: none; } button { padding: .65rem .9rem; border: 0; border-radius: .5rem; background: #0f4c5c; color: #fff; font: inherit; cursor: pointer; }
@media (max-width: 560px) { .site-header { align-items: flex-start; flex-direction: column; } .page-shell { width: min(100% - 1rem, 820px); padding-inline: 1rem; } .stack-card { width: calc(100% - 2rem); } .stack-card--front { left: 2rem; } }
/* TODO-4:請補上 page-shell 的底部安全距離與 front card 的 z-index。 */

完成驗收

下一步

Starter 完成後,不要直接看 Solution;先前往 Checkpoint,自己找出最後一個核心缺口。

前往 Checkpoint,自己補最後一個核心缺口