← HTML / CSS Course

CSS CORE · 50

Responsive / Position / States:讓同一份 UI 在不同限制下仍成立

Responsive 不是做「桌機版 + 手機版兩個網站」,而是從 flexible defaults 出發,當內容真的在某個寬度壞掉時才引入 breakpoint。

Learning outcomes

1. Mobile-first / flexible defaults

.layout {
  display: grid;
  gap: 1rem;
}

@media (
  min-width: 50rem
) {
  .layout {
    grid-template-columns:
      16rem 1fr;
  }
}

Breakpoint 應服務 layout need,而不是因為「某手機是 768px」。

2. Positioning context

.card {
  position: relative;
}

.badge {
  position: absolute;
  top: .75rem;
  right: .75rem;
}

Absolute element 相對哪個 containing block 定位,是 debug 時第一個問題。

3. Sticky / Fixed 不一樣

.toolbar {
  position: sticky;
  top: 0;
}

.help {
  position: fixed;
  right: 1rem;
  bottom: 1rem;
}

Sticky 仍參與原本 flow 並在 scroll constraint 下黏住;fixed 通常相對 viewport 固定。

4. Interaction states

button:hover {
  transform:
    translateY(-1px);
}

button:focus-visible {
  outline:
    3px solid #315fcb;
}

button:disabled {
  opacity: .5;
  cursor: not-allowed;
}

不要只設 hover,鍵盤使用者也需要可見 focus state。

5. Reduced motion / user preference

@media (
  prefers-reduced-motion:
    reduce
) {
  * {
    scroll-behavior: auto;
  }
}

Responsive 也包含使用者與裝置能力偏好,不只 viewport width。

Project checkpoint:Course Profile v7

.profile-layout {
  display: grid;
  gap: 1rem;
}

@media (
  min-width: 56rem
) {
  .profile-layout {
    grid-template-columns:
      18rem 1fr;
  }
}

.course-nav {
  position: sticky;
  top: 1rem;
}

現在 Course Profile 已從 semantic HTML 走到真正 responsive layout。下一步才適合用 JavaScript 加互動 state。

Debug evidence:手機版被遮住

  1. DevTools 切到問題 viewport。
  2. 看 element box 是否超出。
  3. 檢查 fixed/sticky/absolute containing context。
  4. 檢查 z-index/stacking context,而不是盲目把 z-index 加到 999999。

Knowledge check

  1. Breakpoint 應依裝置名稱還是 content failure?
  2. absolute badge 相對誰定位?
  3. hover-only interaction 有什麼 accessibility 問題?
  4. 用 360px、768px、1440px 三種 viewport 驗證 Course Profile。