Day 56:切版實作——垂直置中、文字段落行距、雙欄排版

完成切版成果


實作重點: 不使用 Flexbox/Grid 的傳統排版技巧


核心技術 1: Position Absolute 垂直置中

問題情境

需要讓 <header> 裡的 <nav> 垂直置中,但不能使用 flex 或 grid。

解決方案: 絕對定位 + Transform 位移

header {
  position: relative;  /* 成為定位參考點 */
}

header nav {
  position: absolute;
  top: 50%;                    /* 上緣對齊 header 的 50% 高度 */
  transform: translateY(-50%); /* 往上移自己高度的 50% */
  left: 300px;                 /* 水平定位 */
}

三步驟理解垂直置中原理

步驟 1: top: 50% 讓上緣對齊中線

┌──────────────────────┐
│      header          │
│ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─  │ ← 50% 高度
│ ┌──────────┐         │
│ │   nav    │         │ ← nav 的上緣在這裡
│ └──────────┘         │
└──────────────────────┘

此時 nav 的上緣對齊 header 高度的一半,但視覺上偏下。

步驟 2: transform: translateY(-50%) 往上移自己高度的一半

┌──────────────────────┐
│      header          │
│     ┌──────────┐     │
│ ─ ─ │   nav    │─ ─  │ ← nav 的中心線對齊 header 中心線
│     └──────────┘     │
└──────────────────────┘

translateY(-50%) 的 -50% 是相對於 nav 自己的高度,不是 header 的高度。 developer.mozilla

步驟 3: 完美置中

nav 的中心點現在精準對齊 header 的中心點,實現垂直置中效果。


核心概念

1. position: absolute 的三大影響

  • 脫離 Normal Flow: 元素不再佔據版面空間

  • 定位參考點改變: 變成最近的 position: relative 祖先

  • Margin 語義改變: margin-left 的參考點從「前一個元素」變成「父容器左邊界」

stackoverflow

2. left vs margin-left (定位元素專用)

屬性

語義

適用場景

left

從參考點定位

position: absolute/fixed 時更語意清晰

margin-left

推出空白

所有元素通用,但在定位時語義較弱

最佳實踐: 元素已經 position: absolute 時,優先用 left/right/top/bottom 表達定位意圖。 sitepoint


其他不用 Flex/Grid 的垂直置中方法

方法 2: Line-height 法

header {
  height: 80px;
  line-height: 80px; /* 與高度相同 */
}

header nav {
  display: inline-block;
  vertical-align: middle;
  line-height: normal; /* 重設 line-height */
}

限制: 需要固定高度,不適合響應式設計。

方法 3: Table-cell 法

header {
  display: table;
}

header nav {
  display: table-cell;
  vertical-align: middle;
}

限制: 語義較差,且 display: table 有其他副作用。


核心技術 2: 按鈕置中 + 文字左對齊

問題情境

有一個按鈕區塊 .try-it-btn 包含:

  • <h2>: 橘色按鈕顯示 "TRY IT NOW!"

  • <p>: 按鈕下方的說明文字

需求:

  • 整個按鈕區塊在頁面中視覺上置中

  • <p> 文字要對齊按鈕的左邊緣(不是置中)

  • .hero-intro 內的標題和段落文字都要左對齊


解決方案

1. 按鈕區塊內部設定

section .try-it-btn {
  text-align: left;        /* 內部元素左對齊 */
  display: inline-block;   /* 容器縮到內容寬度 */
  margin-top: 0px;
}

section .try-it-btn h2 {
  display: block;          /* 獨占一行 */
  padding: 20px 30px;
  background-color: orange;
  color: white;
  font-weight: bold;
  border-radius: 5px;
}

section .try-it-btn p {
  display: block;          /* 獨占一行,自動對齊左邊緣 */
  font-size: 16px;
  margin-left: 0;
}

2. 父容器設定(讓按鈕區塊置中)

section .hero-intro {
  display: inline-block;
  width: 50%;
  vertical-align: top;
  text-align: center;      /* 讓子元素 .try-it-btn 置中 */
}

/* 覆蓋父層的 text-align,讓文字內容左對齊 */
section .hero-intro h1 {
  font-size: 60px;
  text-align: left;
  margin-bottom: 0px;
}

section .hero-intro h2 {
  font-size: 30px;
  text-align: left;
  margin-top: 0px;
  margin-bottom: 0px;
}

section .hero-intro p {
  font-size: 20px;
  text-align: left;
  margin-top: 0px;
  margin-bottom: 20px;
}

核心概念

display: inline-block 的作用

  • 讓容器寬度縮到內容大小(不會占滿父容器 100% 寬)

  • 這樣父容器的 text-align: center 才能讓它置中

text-align 的繼承與覆蓋

.hero-intro { text-align: center; }
    ↓
讓 .try-it-btn 這個「元素本身」水平置中
    ↓
但 .try-it-btn 內的 text-align: left 讓「文字內容」左對齊

分層理解:

  • .hero-intro 的 text-align: center 影響直接子元素的橫向位置(讓 .try-it-btn 置中)

  • .hero-intro h1/h2/p 用自己的 text-align: left 覆蓋,讓文字內容左對齊

  • .try-it-btn 內的 text-align: left 讓按鈕和下方文字自然對齊左邊緣


核心技術 3: Linear Gradient 硬切換

問題情境

需要製作一個橘色按鈕,但不是純色或漸層,而是上下兩個橘色色塊直接分界的效果,中間沒有平滑過渡。

解決方案

section.hero .try-it-btn h2 {
  display: block;
  padding: 20px 30px;
  background: linear-gradient(to bottom, #ffb84d 50%, #ff9500 50%);
  color: white;
  font-weight: bold;
  border-radius: 5px;
}

一般漸層 vs. 硬切換

/* ❌ 平滑漸層:顏色會逐漸過渡 */
background: linear-gradient(to bottom, #ffb84d, #ff9500);

/* ✅ 硬切換:兩個色塊直接分界 */
background: linear-gradient(to bottom, #ffb84d 50%, #ff9500 50%);

視覺對比:

平滑漸層:               硬切換:
┌──────────┐           ┌──────────┐
│  淺橘    │           │  淺橘    │
│   ↕      │           │          │
│  漸層    │           ├──────────┤ ← 直接切換
│   ↕      │           │  深橘    │
│  深橘    │           │          │
└──────────┘           └──────────┘

為什麼加百分比可以做出硬切換?

background: linear-gradient(to bottom, #ffb84d 50%, #ff9500 50%);
                                       ^^^^^^^^ ^^   ^^^^^^^^ ^^
                                       顏色1   位置  顏色2   位置

運作原理: stackoverflow

  • #ffb84d 50%: 淺橘色從 0% 延伸到 50%

  • #ff9500 50%: 深橘色從 50% 開始到 100%

  • 兩個顏色在 50% 的位置重疊,就形成了直接切換而不是漸層


調整分界線位置

/* 上面佔 40%,下面佔 60% */
background: linear-gradient(to bottom, #ffb84d 40%, #ff9500 40%);

/* 上面佔 70%,下面佔 30% */
background: linear-gradient(to bottom, #ffb84d 70%, #ff9500 70%);

實務技巧:兩個百分比設定在同一個位置就會產生硬切換效果。 stackoverflow


延伸應用:多色硬切換

/* 三等分,三種顏色 */
background: linear-gradient(
  to right,
  red 33.33%,
  blue 33.33%,
  blue 66.66%,
  green 66.66%
);

產生效果:


核心技術 4: CSS Multi-column Layout

問題情境

將 <article> 內的多個 <p> 段落排版成雙欄,類似報紙排版效果。

解決方案

article {
  column-count: 2;           /* 指定欄數 */
  column-gap: 20px;          /* 欄位間距 */
  margin-bottom: 200px;
}

article h2 {
  column-span: all;          /* h2 跨越所有欄位,不參與分欄 */
  margin-bottom: 40px;
}

article p {
  break-inside: avoid;       /* 避免段落在換欄時被切斷 */
  margin-top: 0;             /* 統一移除上方間距,避免兩欄不對齊 */
  line-height: 1.2;
}

為什麼選擇 column-count?

CSS Multi-column Layout 的三大優勢: developer.mozilla

  1. 內容自動流動: 左欄滿了自動流到右欄,不需要手動分組

  2. 不改動 HTML: 維持語義化的單一 <article> 結構

  3. 適合流動式內容: 比 Grid 或 Flexbox 更適合「文字排版」場景


遇到的問題與解決

問題 1: 第二欄高度跟 h2 一樣高

錯誤結果:
┌──────────┬──────────┐
│          │          │
│   h2     │  第二欄  │ ← h2 只佔一欄寬度
│          │  很短    │
│  第一欄  │          │
└──────────┴──────────┘

原因: <h2> 也被分欄了,只佔一欄寬度。

解決: 用 column-span: all 讓 <h2> 跨越所有欄位。 developer.mozilla

article h2 {
  column-span: all; /* h2 現在橫跨兩欄 */
}
正確結果:
┌──────────────────────┐
│         h2           │ ← 跨越所有欄位
├──────────┬──────────┤
│  第一欄  │  第二欄  │
└──────────┴──────────┘

問題 2: 第一欄開頭 <p> 有 margin-top,第二欄沒有

錯誤結果:
┌──────────┬──────────┐
│          │          │
│ ↓ margin │  段落 3  │ ← 第二欄頂部緊貼
│  段落 1  │  段落 4  │
└──────────┴──────────┘

原因: Multi-column 會折疊新欄頂部元素的 margin-top(類似新容器開始)。 developer.mozilla

解決: 統一設定 article p { margin-top: 0; } 讓兩欄對齊。

article p {
  margin-top: 0; /* 統一移除,避免不對齊 */
}
正確結果:
┌──────────┬──────────┐
│  段落 1  │  段落 3  │ ← 兩欄頂部對齊
│  段落 2  │  段落 4  │
└──────────┴──────────┘

重要屬性說明

column-count vs column-width

屬性

用途

適用場景

column-count: 2

固定欄數

希望永遠顯示 2 欄

column-width: 300px

固定欄寬

響應式設計,欄數自動調整

developer.mozilla

break-inside: avoid

article p {
  break-inside: avoid; /* 段落不會被切成上下兩半 */
}

避免這種情況:


學到的概念

  1. CSS Multi-column Layout: 適合報紙、雜誌式的流動排版 mdn2.netlify

  2. Margin Collapsing: 在 multi-column 環境下,新欄頂部的 margin 會被折疊

  3. column-span: 控制元素是否跨越所有欄位

  4. break-inside: avoid: 避免內容(如段落)在分欄時被切斷


完整代碼

HTML 結構

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>ZERO TYPE</title>
  </head>
  <body>
    <header>
      <div class="logo">
        <img src="./public/logo.png" alt="網站 logo" />
        <p>ZERO TYPE</p>
      </div>
      <nav>
        <ul>
          <li><span>Home</span></li>
          <li>Feature</li>
          <li>News</li>
          <li>About</li>
          <li>Contact</li>
        </ul>
      </nav>
    </header>

    <main>
      <section class="hero">
        <div class="hero-intro">
          <h1>IDEAS?</h1>
          <h2>This is just a placeholder.</h2>
          <p>
            You can remove any link to our website from this website template,
            you're free to use this website template without linking back to us.
          </p>
          <div class="try-it-btn">
            <h2>TRY IT NOW!</h2>
            <p>Don't worry it's for free.</p>
          </div>
        </div>
        <div class="hero-img">
          <img
            src="./public/box.png"
            alt="網站主視覺圖片,一個裝滿各種不同類型檔案圖示的箱子"
          />
        </div>
      </section>

      <article>
        <h2>This is just a placeholder.</h2>
        <p>You can remove any link to our website...</p>
        <p>This is just a place holder...</p>
        <!-- 更多段落 -->
      </article>
    </main>

    <footer>
      <div class="copyright">&copy; 2023 Zerotype. All Rights Reserved.</div>
      <div class="social-media-link">
        <ul>
          <li><a href="##"><img src="./public/facebook.png" alt="" /></a></li>
          <!-- 更多社交媒體連結 -->
        </ul>
      </div>
    </footer>
  </body>
</html>

CSS 樣式(關鍵部分)

/* Header 垂直置中 */
header {
  position: relative;
  border: 5px solid black;
  margin-bottom: 30px;
  background-color: #f2f2f2;
}

header nav {
  position: absolute;
  top: 50%;
  left: 300px;
  transform: translateY(-50%);
}

/* Hero 區塊按鈕置中 */
section.hero .hero-intro {
  display: inline-block;
  width: 45%;
  vertical-align: top;
  text-align: center;
}

section.hero .try-it-btn {
  text-align: left;
  display: inline-block;
  margin-top: 0px;
}

section.hero .try-it-btn h2 {
  background: linear-gradient(to bottom, #ffb84d 50%, #ff9500 50%);
  padding: 20px 30px;
  color: white;
  border-radius: 5px;
}

/* 雙欄文章排版 */
article {
  column-count: 2;
  column-gap: 20px;
  margin-bottom: 200px;
}

article h2 {
  column-span: all;
  margin-bottom: 40px;
}

article p {
  margin-top: 0px;
  break-inside: avoid;
  line-height: 1.2;
}

學習重點總結

技術層面

  1. Position Absolute + Transform: 不用 Flex/Grid 實現精準垂直置中 geeksforgeeks

  2. Inline-block + Text-align: 傳統的元素置中組合技巧

  3. Linear Gradient 硬切換: 用相同位置的色標製作雙色分界 developer.mozilla

  4. Multi-column Layout: 流動式雙欄排版的最佳選擇 developer.mozilla

設計思維

  1. 語義化 HTML: 保持結構清晰,不為排版犧牲語義

  2. 漸進式除錯: 從視覺問題追蹤到 CSS 屬性,逐步解決

  3. 屬性語義選擇: 定位用 left/top,留白用 margin,各司其職


延伸學習資源


筆記時間: 2026-02-09
核心學習: Position Absolute 垂直置中、Linear Gradient 硬切換、Multi-column Layout
學習階段: Phase 2 - CSS 切版實作