Day 62:BEM 命名、定位技巧與 Hero Section 完整實作

📅 2026-02-24 | 🏷 CSS · BEM · Layout · Positioning


一、版面結構拆解

電商首頁的切版練習,目標是不使用 flex/grid,僅用傳統 CSS 佈局完成設計稿還原。

由上而下拆成四個水平區塊:Header、Hero、Products、Footer。傳統佈局的三個核心工具分工明確:

  • Block 元素:四大區塊天生垂直堆疊,不需要額外設定

  • inline-block:讓選單項目、產品卡片水平並排(需注意空白字元問題)

  • float:Header 左右分離、Footer 三欄排列(需搭配 clearfix 清除浮動)

外層容器寬度控制慣例:

/* 外層撐滿螢幕,內層置中限寬 */
.section {
  width: 100%;
}
.section__inner {
  max-width: 1200px;
  margin: 0 auto;
}

二、語意化 HTML 結構規劃

標籤選用原則

<header>   <!-- 頁首導航 -->
<nav>      <!-- 導航連結集合 -->
<main>     <!-- 頁面主要內容 -->
<section>  <!-- 獨立內容區塊 -->
<footer>   <!-- 頁腳 -->

<h1> 只給頁面主標題,例如 Hero 的 "Fall & Winter",Logo 文字改用 <div> 或 <a>。 developer.mozilla

容器規劃判斷流程

情境

結論

需要定位基準(absolute 的父層)

需要容器

需要清除內部浮動(clearfix)

需要容器

<li> 本身可當容器

不需要再包 <div>

沒有 class 的無名 <div>

移除,避免巢狀過深


三、BEM 命名規範實踐

BEM 是 Block(區塊)__Element(元素)--Modifier(修飾符) 的命名方法論,目標是讓 CSS class 名稱具備自解釋能力,並避免樣式衝突。 sparkbox

.block {}              /* 獨立元件本身 */
.block__element {}     /* 元件的組成部分,雙底線 __ */
.block--modifier {}    /* 元件的變體狀態,雙橫線 -- */

Header 命名示範

.header
  .header__logo          ← Block 的一級 Element
  .header__nav           ← Block 的一級 Element
    .header__nav-list    ← <ul> 列表容器
      .header__nav-item  ← <li> 單項
        .header__nav-link ← <a> 連結

Products 命名示範

.products
  .products__list        ← <ul>
    .products__item      ← <li>
      .products__item-link ← <a>
        .products__item-img ← <img>

⚠️ 常見命名錯誤

<ul class="header__nav-item"> <!-- ul 不是 item --> ✅ <ul class="header__nav-list"> ❌ <a href="#">Home</a> <!-- 缺少 class,無法精確控制樣式 --> ✅ <a href="#" class="header__nav-link">Home</a> ❌ <li><div class="products__item">...</div></li> <!-- 多餘容器 --> ✅ <li class="products__item">...</li>

BEM 一致性原則:products 不能在某個地方寫成 product(少一個 s),Block 名稱必須在整個元件內保持統一。 hackmd


四、CSS 選擇器語法錯誤導致樣式失效

問題根源

/* ❌ 選擇器沒有 { },破壞後續 CSS 的解析 */
.header
.header__logo {
    display: inline-block;
}

當 CSS 選擇器缺少配對的 {} 時,瀏覽器無法正確解析,導致後續的規則失效或行為異常。 developer.mozilla

解決習慣:未完成的選擇器先註解

/* 先把架構列出,未完成的用註解佔位 */
/* .header */
.header__logo {
    display: inline-block;
}

/* .header__nav-link */
.header__cart {
    float: right; /* 靠右對齊 */
}

口訣:選擇器若沒有規則,就先註解起來!

此外,display: inline-block 只能讓元素並排,不會改變對齊位置;要讓元素靠右需要用 float: right(傳統佈局下)。


五、vertical-align 的正確使用方式

核心概念

vertical-align 有三個容易混淆的特性: w3docs

  1. 設定在子元素上,不是父元素

  2. 只對 inline 或 inline-block 元素有效

  3. 對齊基準是行盒(Line Box),不是父元素的邊界

行盒(Line Box)
┌─────────────────────────────────┐  ← line-height 決定高度
│  [logo]  [nav]  [cart]          │  ← 三個 inline-block 元素
└─────────────────────────────────┘

實作:Header 垂直置中

步驟一:在所有並排子元素加上 vertical-align: middle

.header__logo,
.header__nav,
.header__cart {
    display: inline-block;
    vertical-align: middle; /* 設定在子元素,不是父元素 */
}

步驟二:在父元素設定 line-height 等於 height,撐高行盒

.header {
    height: 100px;
    line-height: 100px; /* 行盒高度 = 容器高度 → 子元素垂直置中 */
}

⚠️ 邊界情況:子元素高度大於 line-height

子元素過高時行盒會被撐大,對齊基準也跟著偏移,視覺上不在預期位置。防禦措施:

.header__cart-img {
    max-height: 35px; /* 限制最大高度,防止撐破版面 */
    height: auto;
    width: auto;
}

六、inline-block 子元素的水平置中

兩種置中方法的適用場景

目標元素

正確方法

inline / inline-block 元素

在父層設 text-align: center

block 元素(有明確 width)

在自身設 margin: 0 auto

margin: 0 auto 對 inline-block 無效,因為 margin: auto 只在 block formatting context 中計算。text-align: center 控制的是 inline formatting context 中的物件,而 inline-block 正是讓元素「偽裝」成行內物件,所以能被父層的 text-align 控制。 developer.mozilla

/* ✅ 正確:三張產品卡片水平置中 */
.products {
    text-align: center;
}

.products__item {
    display: inline-block;
}

<ul> 預設樣式造成視覺偏移

<ul> 有瀏覽器預設的 padding-left: 40px,需要 reset:

.products__list {
    padding: 0;
    margin: 0;
    list-style: none;
}

七、Hero Section 完整實作

background-image vs <img> 的選擇

<img> 標籤

background-image

層級

HTML 內容層

CSS 裝飾層

撐開容器

(需手動設 height)

SEO/無障礙

有 alt 屬性

無語義資訊

疊加文字

較複雜

直覺(搭配 position)

Hero banner 使用 background-image,方便直接在容器內定位文字與按鈕。 developer.mozilla

背景圖關鍵 CSS

.hero {
  background-image: url("img/cover.jpg");
  background-size: cover;           /* 覆蓋容器,等比例裁切 */
  background-position: center center;
  background-repeat: no-repeat;
  position: relative;               /* 作為內部絕對定位元素的基準 */
  height: 710px;                    /* background-image 不撐高,必須手動設定 */
}

遮罩層 + 內容層的 HTML 架構

<section class="hero">
  <div class="hero__overlay"></div>    <!-- 半透明遮罩層 -->
  <div class="hero__content">          <!-- 文字與按鈕 -->
    <h1 class="hero__title">Fall & Winter</h1>
    <a href="#" class="hero__btn">Shop Now</a>
  </div>
  <p class="hero__shipping">FREE SHIPPING WORLDWIDE</p>
</section>

水平垂直置中:transform 方法

/* 遮罩層 */
.hero__overlay {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%); /* 補償自身寬高的 50% */
  width: 605px;
  height: 190px;
  background-color: rgba(255, 255, 255, 0.6);
  z-index: 1; /* 遮罩在背景圖上方 */
}

/* 內容層,z-index 高於遮罩 */
.hero__content {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 2; /* 文字在遮罩上方 */
  text-align: center;
}

/* 底部橫幅 */
.hero__shipping {
  position: absolute;
  bottom: 0;
  left: 0;
  width: 100%;
  background-color: rgb(222, 222, 222);
  margin: 0;
  padding: 10px 0;
  text-align: center;
}

transform: translate(-50%, -50%) 原理:top: 50% 讓元素頂部對齊容器中線,但元素本身有寬高,所以要再往左上移動自身寬高的 50% 才會真正置中。 stackoverflow

z-index 層級示意

.hero(position: relative)
  ├── background-image  ← 最底層
  ├── .hero__overlay    ← z-index: 1
  ├── .hero__content    ← z-index: 2
  └── .hero__shipping   ← z-index: auto(最上層)

z-index 只對 position 不是 static 的元素生效。 w3schools


八、偽元素 vs 真實 DOM 的選擇判斷

偽元素(::before/::after)與偽類(:hover/:focus)的核心差異: developer.mozilla

偽元素 ::

偽類 :

功能

創造新的虛擬節點

描述元素的狀態

常見例子

::before, ::after

:hover, :focus

可被 JS 操作

—

選擇判斷流程

這個層需要被 JavaScript 操作嗎?
├── 是 → 真實 DOM 元素
└── 否 → 是純視覺裝飾嗎?
          ├── 是 → 偽元素 ✅(::before / ::after)
          └── 否(例如需要 ARIA / 點擊事件) → 真實 DOM 元素

本次遮罩選用真實 DOM,理由是尺寸為局部區域(不是全滿背景),且未來可能需要 JS 控制動態效果。


九、本次學到的 CSS 屬性整理

屬性

用途

background-size: cover

圖片覆蓋容器,等比例裁切

background-position

控制背景圖位置

position: absolute

相對於 relative 父層定位

transform: translate()

位移,用於水平垂直置中

rgba()

含透明度的顏色,製作半透明遮罩

z-index

控制堆疊層級,只對非 static 元素有效

vertical-align

控制 inline-block 兄弟元素的對齊基準

line-height

設定行盒高度,間接控制垂直置中範圍

text-align: center

使父層內的 inline-block 子元素水平置中


延伸資源