CSS:
網頁的皮膚
HTML 蓋好了一個沒裝潢的毛胚屋。CSS 就是裝潢工程:刷油漆、鋪地板、選沙發、調光線。 這章是前端最有趣也最頭痛的部分,很多人放棄都放棄在這。但學會 Flexbox 跟 Grid,你就贏了 80% 的人。
- 把任何 HTML 變漂亮
- 讓網站在電腦、平板、手機都好看(RWD)
- 做出滑鼠 hover 動畫、頁面載入動畫
- 用 Flexbox 跟 Grid 排出複雜版面
- 會用 CSS 變數、規模化你的樣式
CSS 是什麼?怎麼用?
CSS(Cascading Style Sheets,串接樣式表)是規則。它告訴瀏覽器:「這個 h1 要紅色」、「這個 p 字要 16px」。
規則的長相:
h1 {
color: red;
font-size: 32px;
}
翻譯:「找到所有 h1,把字變紅、變 32px」。前面的 h1 叫選擇器,大括號裡叫宣告。
三種引入 CSS 的方法
方法一:行內樣式(不推薦)
<h1 style="color: red;">標題</h1>
方法二:寫在 head 裡
<head>
<style>
h1 { color: red; }
</style>
</head>
方法三:外部 CSS 檔(最推薦)
// index.html
<link rel="stylesheet" href="style.css">
/* style.css */
h1 { color: red; }
正式專案永遠用方法三。HTML 一個檔、CSS 一個檔、JS 一個檔。混在一起寫很爽,兩週後維護想哭。
選擇器:怎麼挑出要改的元素
CSS 第一個關卡:怎麼跟瀏覽器精準說「我要改的是這個」。
| 選擇器 | 意思 | 範例 |
|---|---|---|
* | 所有元素 | * { margin: 0; } |
h1 | 所有 h1 | h1 { color: red; } |
.btn | class 是 btn | .btn { ... } |
#hero | id 是 hero | #hero { ... } |
div p | div 裡所有 p | article p { ... } |
div > p | div 的直接子層 p | nav > a { ... } |
h1 + p | 緊接 h1 的 p | — |
a:hover | 滑鼠移過去 | a:hover { color: blue; } |
input:focus | 正在輸入 | — |
li:first-child | 第一個 li | — |
li:nth-child(2) | 第二個 li | — |
[type="email"] | type 是 email | — |
組合起來用
/* nav 裡的 a,當滑鼠移過去 */
nav a:hover { color: orange; }
/* class 是 card 且 也有 featured */
.card.featured { border: 2px solid gold; }
/* class 是 btn 但 不是 disabled */
.btn:not(.disabled) { cursor: pointer; }
優先級(specificity)
當兩條規則套到同一個元素,分數高的贏:
- 行內樣式(
style="...")= 1000 分 - id 選擇器(
#xx)= 100 分 - class / 屬性 / 偽類 = 10 分
- 標籤選擇器 = 1 分
新手很愛濫用 !important。它會無視所有規則直接贏。但用了 !important 之後就只能再用 !important 蓋它,最後整份 CSS 都是 !important。不到萬不得已不要用。
顏色、字體、單位
顏色寫法
color: red; /* 顏色名稱 */
color: #ff0000; /* 16 進位 */
color: #f00; /* 短寫 */
color: rgb(255, 0, 0); /* RGB */
color: rgba(255, 0, 0, 0.5); /* 多了透明度 0~1 */
color: hsl(0, 100%, 50%); /* 色相、飽和度、亮度 */
記住基本顏色對照:#000 黑、#fff 白、#f00 紅、#0f0 綠、#00f 藍。
字體
body {
font-family: 'Noto Sans TC', 'Microsoft JhengHei', sans-serif;
font-size: 16px;
font-weight: 400; /* 100~900,400 = 普通,700 = 粗 */
line-height: 1.6; /* 行高,1.5~1.8 最舒服 */
letter-spacing: 0.02em; /* 字距 */
}
font-family 寫多個值是「萬一第一個沒有,用下一個」。最後一定要寫 sans-serif 或 serif 保底。
單位
| 單位 | 意思 | 用在哪 |
|---|---|---|
px | 像素(絕對值) | 邊框、icon |
% | 父元素的百分比 | 寬度 |
em | 父元素 font-size 倍數 | 內距 |
rem | html 的 font-size 倍數 | 大部分東西 |
vw | 視窗寬度的 1% | 滿版區塊 |
vh | 視窗高度的 1% | 全螢幕區塊 |
px 是「絕對」的,不管螢幕多大都長一樣。rem 是「相對」的,使用者放大字體會跟著放大。字體用 rem,邊框用 px 是新手最快上手的規則。
盒子模型(Box Model)
CSS 最核心的概念,沒搞懂這個就不要往下走。
每個 HTML 元素在瀏覽器看來都是盒子。盒子由內到外有四層:
┌─────── margin(外距)─────────┐
│ ┌──── border(邊框)──────┐ │
│ │ ┌── padding(內距)─┐ │ │
│ │ │ content(內容) │ │ │
│ │ └────────────────── ┘ │ │
│ └────────────────────────┘ │
└──────────────────────────────┘
- content:內容(文字、圖片)
- padding:內容跟邊框的距離
- border:邊框
- margin:跟其他元素的距離
禮物盒。content 是禮物、padding 是緩衝氣泡紙、border 是紙盒、margin 是這個盒子跟其他盒子的空隙。
.box {
width: 200px;
padding: 20px;
border: 2px solid black;
margin: 16px;
}
/* 簡寫:上 右 下 左 */
.box { padding: 10px 20px 30px 40px; }
/* 上下 / 左右 */
.box { padding: 10px 20px; }
那個讓所有人崩潰的 box-sizing
預設情況下,width: 200px 只算 content。padding 跟 border 額外加上去。也就是 width: 200px; padding: 20px; border: 2px;,實際盒子寬 244px。難排版。
解法:在 CSS 開頭加這段,每個專案都加:
* {
box-sizing: border-box;
}
之後 width: 200px 就是「整個盒子 200px」,padding 和 border 算進去。世界和平。
display:盒子的種類
| 值 | 意思 |
|---|---|
block | 區塊:獨佔一行,可設寬高 |
inline | 行內:跟著文字流,無法設寬高 |
inline-block | 混血:跟文字並排但可設寬高 |
none | 消失(不佔空間) |
flex | 變 Flexbox 容器 |
grid | 變 Grid 容器 |
Flexbox:水平排列救星
「我想把三個東西並排放,間距平均」——這個需求出現過上萬次。在 2015 年以前要用 float 拼湊,超痛苦。現在有 Flexbox。
父元素設 display: flex,它的直接子元素就會自動變成 flex 項目。
<div class="row">
<div>項目 1</div>
<div>項目 2</div>
<div>項目 3</div>
</div>
.row {
display: flex;
gap: 16px;
justify-content: space-between;
align-items: center;
}
justify-content(主軸對齊)
flex-start:靠左(預設)center:置中flex-end:靠右space-between:兩端對齊,中間平均space-around:每個項目左右等距space-evenly:所有間距完全一樣
align-items(交叉軸對齊)
stretch:拉滿(預設)center:垂直置中flex-start:靠上flex-end:靠下
水平垂直完美置中(神技)
.parent {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
flex 屬性(給項目用)
.item { flex: 1; } /* 平均分配剩餘空間 */
.item:nth-child(2) { flex: 2; } /* 這項佔兩倍寬 */
flex-direction、flex-wrap
.col {
display: flex;
flex-direction: column; /* 變垂直堆疊 */
}
.gallery {
display: flex;
flex-wrap: wrap; /* 寬度不夠時自動換行 */
}
導覽列、卡片並排、按鈕群組、表單欄位排列、頁尾分欄——這些用 Flexbox 全部搞定。Flexbox 是接案前端的菜刀,不熟練不能出師。
Grid:二維排版王者
Flexbox 一次處理一條軸。Grid 同時處理兩條,是排版界的魔王。
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr); /* 3 欄平均 */
gap: 16px;
}
fr 是 fraction(份)。1fr 1fr 1fr = 三欄一樣寬。1fr 2fr = 第二欄是第一欄的兩倍寬。
RWD 神技(背下這行)
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 24px;
}
「每張卡片至少 250px 寬,能放幾張就放幾張,放不下自動換行。」接案 80% 的卡片排版會用到它。
跨欄、跨列
.featured {
grid-column: span 2; /* 橫跨兩欄 */
grid-row: span 2; /* 縱跨兩列 */
}
Flexbox vs Grid 怎麼選?
- 一條線(按鈕排、導覽列)→ Flexbox
- 網格狀(卡片牆、整頁版型)→ Grid
- 不確定?先試 Flexbox,撞牆再換 Grid
Position:把元素釘在畫面上
| 值 | 意思 |
|---|---|
static | 預設,照正常順序排 |
relative | 相對自己原本位置偏移 |
absolute | 相對最近的「定位過的祖先」 |
fixed | 釘在視窗,捲動不動 |
sticky | 滾到某位置就黏住 |
/* 經典用法:徽章貼在卡片右上 */
.card { position: relative; }
.badge {
position: absolute;
top: 8px;
right: 8px;
}
/* 滾動時固定的導覽列 */
nav {
position: sticky;
top: 0;
z-index: 100;
}
z-index 不要設 99999。設了之後別的東西要蓋上來就要 999999,永遠在比大。用 10、100、1000 三個層級就夠了。
響應式設計(RWD)
2026 年了,超過 70% 的人用手機看網站。電腦上漂亮、手機上爆掉,就是廢的。
第一步:viewport meta
<meta name="viewport" content="width=device-width, initial-scale=1.0">
第二步:媒體查詢
/* 預設樣式(電腦版) */
.container { width: 1200px; }
/* 螢幕寬 768px 以下 */
@media (max-width: 768px) {
.container { width: 100%; padding: 16px; }
.nav { flex-direction: column; }
}
常用斷點
- 手機:< 768px
- 平板:768px ~ 1024px
- 桌機:> 1024px
Mobile First 思維
新手通常先做電腦版再縫補手機版。反過來:先做手機版,用 min-width 加大螢幕的樣式。
/* 預設:手機 */
.card { width: 100%; }
/* 平板以上 */
@media (min-width: 768px) {
.card { width: 50%; }
}
/* 桌機以上 */
@media (min-width: 1024px) {
.card { width: 33%; }
}
動畫與過渡
transition:簡單過渡
.btn {
background: #5fff87;
transition: all 0.3s ease;
}
.btn:hover {
background: #ffb13d;
transform: translateY(-2px);
}
transform:變形
.box {
transform: translateX(20px);
transform: scale(1.1);
transform: rotate(45deg);
transform: scale(1.1) rotate(5deg); /* 組合 */
}
animation + @keyframes
@keyframes bounce {
0% { transform: translateY(0); }
50% { transform: translateY(-20px); }
100% { transform: translateY(0); }
}
.ball {
animation: bounce 1s ease infinite;
}
不要過度動畫。每個東西都動會讓使用者頭暈也讓網站變慢。動畫只用在重點上:按鈕 hover、頁面載入、滾動進入。
CSS 變數:可重用的設定值
專案有 50 個地方用到 #5fff87。客戶說「想換成紫色」。要改 50 個地方?太蠢了。
:root {
--primary: #5fff87;
--secondary: #ffb13d;
--text: #1a1814;
--bg: #f4ead5;
--space-1: 8px;
--space-2: 16px;
--space-3: 24px;
}
.btn {
background: var(--primary);
padding: var(--space-2) var(--space-3);
}
之後客戶要換顏色,改 :root 那一行就好。
標準作業流程:拿到客戶 brand 後,第一件事就是把所有顏色、字級、間距寫成 CSS 變數。後面整個專案都用變數。要改主題色一鍵搞定。
練習:個人品牌頁
用上一章的個人介紹頁加上 CSS:
- 定義 CSS 變數:主色、副色、字體、間距
- 用 Flexbox 把 header 做成「左 logo / 右導覽」
- 用 Grid 做技能區塊:3 欄、卡片式、滑鼠 hover 浮起
- 聯絡表單置中、最大寬度 600px
- 導覽列 sticky 在頂部
- 手機版(< 768px)導覽列改成垂直、技能區改成 1 欄
- 頁面載入時 h1 從下往上淡入
常見卡關 FAQ
<link> 路徑寫錯;(2) 選擇器寫錯(class 前面要 . 、id 前面要 #);(3) 被優先級更高的規則蓋掉了。F12 → Elements 選你那個元素,右邊 Styles 看哪條規則生效。<meta name="viewport" content="width=device-width, initial-scale=1.0">。.a { margin-bottom: 20px } 接 .b { margin-top: 30px },間距是 30px 不是 50px。解法:用 gap(在 flex/grid 裡)或 padding。img { display: block; } 就正常。100dvh(dynamic viewport height)就會自動扣掉網址列。或備援用 min-height: 100vh; min-height: 100dvh;。