一、從“偽類”到“偽元素”:概念澄清
很多人把 `:hover` 與 `::before` 混為一談,前者是“偽類”,描述狀態;后者是“偽元素”,描述結構。一句話:偽類選中已有元素在特定狀態下的樣式;偽元素則憑空生成一個不在 DOM 樹中的盒子,再給它樣式。理解這一點,就不會把 `::before` 當成“加在元素前面”的魔法,而是“在元素內部,創建一個位于內容之前的盒子”。
二、家族成員一覽
1. `::before` 與 `::after`
最常見,用來生成裝飾性內容或清除浮動。
2. `::first-line` 與 `::first-letter`
分別選中段落的首行或首字母,雜志排版常用。
3. `::selection`
用戶選中文本時的背景與前景色,品牌定制神器。
4. `::marker`
列表項目前的符號,輕松換顏色或圖形。
5. 實驗性成員
`::backdrop`、`::placeholder`、`::cue` 等,按需漸進增強。
三、渲染原理:瀏覽器如何“造”盒子
當解析器遇到 `::before`,會:
- 在當前元素的內部,創建一個匿名行內盒子;
- 繼承父元素的字體、顏色、行高,但可獨立設置 `display`、`position`、`transform`;
- 該盒子與真實子元素同級,參與布局、回流、重繪。
因此,`::before` 可以清除浮動、可以絕對定位、可以旋轉,但不能單獨觸發事件(因為它不在 DOM)。
四、性能考量:回流、重繪與層爆炸
- 回流:偽元素與父元素共用一個布局上下文,除非單獨設置 `position:absolute/fixed`;
- 重繪:修改顏色、陰影、背景不會觸發回流,可放心做動畫;
- 層爆炸:大量 `::before` + `transform:translateZ` 會生成額外合成層,移動端需節制;
- 優化口訣:裝飾用偽元素,交互用真實元素,動畫慎用合成層。
五、語法細節:單冒號還是雙冒號?
CSS2 時代寫作 `:before`,CSS3 起推薦 `::before`,兩者渲染一致,但語義更清晰。現代工具鏈默認輸出雙冒號,保持向后兼容。
六、實戰場景:創意與實用并存
1. 圖標系統
用 `::before` 注入 SVG 圖標,實現“零 DOM”圖標庫。
2. 清除浮動
經典 `.clearfix::after { content:''; display:block; clear:both; }`。
3. 進度條
`::before` 寬度隨 CSS 變量變化,實現純 CSS 進度動畫。
4. 文本高亮
`::selection { background:#ffcc00; }` 讓品牌色無處不在。
5. 裝飾角標
`::after` 絕對定位生成“NEW”角標,無需額外 HTML。
七、陷阱與誤區
- 事件冒泡:偽元素無法綁定事件,需用父元素代理;
- z-index 陷阱:偽元素層級受父元素限制,需配合 `position:relative`;
- 可訪問性:屏幕閱讀器不朗讀 `content` 文本,重要信息請放真實元素;
- 打印樣式:偽元素不會出現在打印預覽,需用 `@media print` 單獨處理。
八、可訪問性與語義
- 裝飾性內容:放在偽元素,避免干擾語義樹;
- 語義性內容:如按鈕文字、表單提示,必須放回真實 DOM;
- 鍵盤焦點:偽元素無法聚焦,交互元素請用 tabindex。
九、漸進增強與降級策略
- 老舊瀏覽器:單冒號語法兼容,功能降級不影響布局;
- 實驗特性:使用 `@supports` 檢測 `::marker`,漸進增強;
- 打印樣式:隱藏裝飾性偽元素,避免打印浪費墨水。
十、未來展望:CSS 4 與偽元素
- `::highlight`:自定義選區顏色;
- `::target-text`:滾動到錨點時高亮文本;
- 容器查詢 + 偽元素:響應式裝飾角標、進度條。
十一、每日一練:親手寫一條裝飾線
1. 需求:在卡片底部添加波浪線
2. 實現:
- `::after` 絕對定位
- `background-image` 波浪 SVG
- CSS 變量控制顏色
3. 測試:移動端 60 FPS 驗證
4. 復盤:記錄性能與可訪問性
十二、結語:把偽元素當成設計系統
偽元素不是“奇技淫巧”,而是設計系統的一部分:
- 它讓 HTML 保持語義純凈;
- 它讓 CSS 承擔裝飾責任;
- 它讓性能與可維護性兼得。
當你下一次面對“只需一個裝飾角”的需求時,請想起這支隱形畫筆——用一行 CSS,繪出無限可能。