CSS 沒有像 HTML 和 JavaScript 那樣有一份統一的標準文檔,而是由近百份不同的標準組成。本章透過 CSS 語法結構這條線索,系統性地整理 CSS 的核心知識。
CSS 語法結構#
CSS 的頂層樣式表由兩種規則組成:
- at-rule(@ 規則):以
@關鍵字開頭的特殊規則 - qualified rule(普通規則):選擇器 + 聲明區塊
常用 @ 規則#
/* 字符編碼,必須在最前面 */
@charset "utf-8";
/* 引入其他 CSS 文件 */
@import "mystyle.css";
/* 媒體查詢 */
@media print {
body {
font-size: 10pt;
}
}
/* 關鍵幀動畫 */
@keyframes slidein {
from {
transform: translateX(0%);
}
to {
transform: translateX(100%);
}
}
/* 自定義字體 */
@font-face {
font-family: "MyFont";
src: url("myfont.woff2");
}
/* 特性檢測 */
@supports (display: grid) {
.container {
display: grid;
}
}選擇器體系#
選擇器分類#
| 類別 | 說明 | 範例 |
|---|---|---|
| 類型選擇器 | 根據標籤名選擇 | div, p |
| 全體選擇器 | 選擇所有元素 | * |
| ID 選擇器 | 根據 id 屬性 | #myid |
| Class 選擇器 | 根據 class 屬性 | .myclass |
| 屬性選擇器 | 根據屬性 | [type="text"] |
| 偽類選擇器 | 元素特定狀態 | :hover, :first-child |
| 偽元素選擇器 | 虛擬元素 | ::before, ::after |
屬性選擇器#
/* 存在屬性 */
[disabled] {
opacity: 0.5;
}
/* 精確匹配 */
[type="text"] {
border: 1px solid;
}
/* 包含匹配(空格分隔的列表) */
[class~="active"] {
color: red;
}
/* 前綴匹配(值或值-開頭) */
[lang|="en"] {
font-family: serif;
}
/* 開頭匹配 */
[href^="https"] {
color: green;
}
/* 結尾匹配 */
[href$=".pdf"] {
color: red;
}
/* 包含匹配 */
[href*="example"] {
text-decoration: underline;
}選擇器組合#
選擇器的連線方式有優先級:
| 優先級 | 連線符 | 說明 |
|---|---|---|
| 第一 | (無連線) | 複合選擇器,表示「且」 |
| 第二 | 空格, >, ~, +, || | 關係選擇器 |
| 第三 | , | 選擇器列表,表示「或」 |
/* 複合選擇器:同時具有 class a 和 b */
.a.b {
}
/* 後代選擇器:a 的所有後代 b */
.a .b {
}
/* 子代選擇器:a 的直接子元素 b */
.a > .b {
}
/* 相鄰兄弟:緊跟在 a 後面的 b */
.a + .b {
}
/* 後續兄弟:a 之後的所有兄弟 b */
.a ~ .b {
}選擇器優先級#
CSS 使用三元組 (a, b, c) 計算選擇器優先級:
- a:ID 選擇器數量
- b:偽類選擇器 + class 選擇器數量
- c:偽元素選擇器 + 標籤選擇器數量
/* 優先級:(0, 1, 1) */
div.active {
}
/* 優先級:(1, 0, 0) */
#myid {
}
/* 優先級:(0, 2, 0) */
.a.b {
}行內樣式的優先級永遠高於 CSS 規則,
!important則高於行內樣式。避免濫用!important,它會造成樣式難以維護。
偽類選擇器#
樹結構偽類#
/* 根元素 */
:root {
}
/* 空元素 */
:empty {
}
/* 第 n 個子元素 */
:nth-child(2n) {
} /* 偶數 */
:nth-child(2n + 1) {
} /* 奇數 */
:nth-child(3) {
} /* 第 3 個 */
/* 第一個/最後一個 */
:first-child {
}
:last-child {
}
/* 唯一子元素 */
:only-child {
}鏈接與行為偽類#
:link {
} /* 未訪問的鏈接 */
:visited {
} /* 已訪問的鏈接 */
:hover {
} /* 滑鼠懸停 */
:active {
} /* 激活狀態(點擊時) */
:focus {
} /* 獲得焦點 */
:target {
} /* URL hash 指向的元素 */邏輯偽類#
/* 否定選擇器 */
:not(.disabled) {
}
/* 選擇器 4 級(部分瀏覽器支持) */
:is(h1, h2, h3) {
}
:where(h1, h2, h3) {
}偽元素#
偽元素創造不存在的虛擬元素:
/* 首行 */
p::first-line {
text-transform: uppercase;
}
/* 首字母 */
p::first-letter {
font-size: 2em;
float: left;
}
/* 在內容前插入 */
.icon::before {
content: ">";
}
/* 在內容後插入 */
.external::after {
content: url(external-icon.svg);
}
::before和::after必須設定content屬性才會生效,它們支援所有 CSS 屬性。
盒模型#
box-sizing#
/* content-box(預設):width/height 只包含內容 */
.content-box {
box-sizing: content-box;
width: 100px;
padding: 10px;
/* 實際寬度 = 100 + 10*2 = 120px */
}
/* border-box:width/height 包含 padding 和 border */
.border-box {
box-sizing: border-box;
width: 100px;
padding: 10px;
/* 實際寬度 = 100px */
}推薦全域使用
border-box:*, *::before, *::after { box-sizing: border-box; }
Flex 佈局#
Flex 是為了解決傳統 CSS 三大經典問題而設計的:
- 垂直居中
- 兩列等高
- 自適應寬度
核心概念#
- Flex 容器:設定
display: flex的元素 - Flex 項目:容器的直接子元素
- 主軸(Main Axis):項目排列方向
- 交叉軸(Cross Axis):垂直於主軸
容器屬性#
.container {
display: flex;
/* 主軸方向 */
flex-direction: row | row-reverse | column | column-reverse;
/* 換行 */
flex-wrap: nowrap | wrap | wrap-reverse;
/* 主軸對齊 */
justify-content: flex-start | flex-end | center | space-between | space-around
| space-evenly;
/* 交叉軸對齊(單行) */
align-items: stretch | flex-start | flex-end | center | baseline;
/* 交叉軸對齊(多行) */
align-content: stretch | flex-start | flex-end | center | space-between |
space-around;
}項目屬性#
.item {
/* 擴展比例 */
flex-grow: 0;
/* 收縮比例 */
flex-shrink: 1;
/* 基準大小 */
flex-basis: auto;
/* 簡寫 */
flex: 0 1 auto; /* grow shrink basis */
flex: 1; /* flex: 1 1 0 */
/* 單獨對齊 */
align-self: auto | flex-start | flex-end | center | baseline | stretch;
/* 排序 */
order: 0;
}經典問題解決方案#
垂直居中
.parent {
display: flex;
justify-content: center; /* 水平居中 */
align-items: center; /* 垂直居中 */
height: 300px;
}兩列等高
.parent {
display: flex;
align-items: stretch; /* 預設值 */
}
.child {
width: 100px;
}自適應寬度
.parent {
display: flex;
}
.fixed {
width: 200px;
}
.auto {
flex: 1; /* 填滿剩餘空間 */
}CSS 動畫#
Transition 過渡#
.box {
transition: property duration timing-function delay;
/* 範例 */
transition: all 0.3s ease-in-out;
transition: transform 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}Animation 動畫#
@keyframes slide {
0% {
transform: translateX(0);
}
50% {
transform: translateX(100px);
}
100% {
transform: translateX(0);
}
}
.animated {
animation-name: slide;
animation-duration: 2s;
animation-timing-function: ease;
animation-delay: 0s;
animation-iteration-count: infinite;
animation-direction: alternate;
/* 簡寫 */
animation: slide 2s ease 0s infinite alternate;
}時間函式#
| 函式 | 說明 |
|---|---|
linear | 線性 |
ease | 慢-快-慢(預設) |
ease-in | 慢-快 |
ease-out | 快-慢 |
ease-in-out | 慢-快-慢 |
cubic-bezier(x1,y1,x2,y2) | 自定義貝塞爾曲線 |
貝塞爾曲線是一種插值曲線,其特點是「平滑」。時間曲線平滑意味著動畫較少突兀的變化,這是動畫設計所追求的效果。
CSS 變數#
:root {
--primary-color: #007bff;
--spacing: 8px;
}
.button {
background: var(--primary-color);
padding: var(--spacing);
margin: calc(var(--spacing) * 2);
}CSS 函式#
常用函式#
/* 計算 */
width: calc(100% - 200px);
width: min(100%, 500px);
width: max(300px, 50%);
width: clamp(300px, 50%, 800px);
/* 顏色 */
color: rgb(255, 0, 0);
color: rgba(255, 0, 0, 0.5);
color: hsl(0, 100%, 50%);
/* 變數 */
color: var(--primary-color, #000);
/* 屬性值 */
content: attr(data-label);
/* 漸變 */
background: linear-gradient(to right, red, blue);
background: radial-gradient(circle, red, blue);實用建議#
選擇器使用原則
- 用 ID 選擇單個元素
- 用 class 組合選擇成組元素
- 用標籤選擇器確定頁面風格
- 避免過於複雜的選擇器組合
避免的做法
- 過度依賴
!important- 使用過深的選擇器嵌套
- 在組件庫中使用標籤選擇器
- 忽略 box-sizing 的設定