📋 目錄
還記得被
<select>元素支配的恐懼嗎?那個怎麼改color都沒反應的下拉選單,那個在各瀏覽器看起來都不一樣的原生元件。別擔心,CSS 現在給了我們一把解鎖原生選單的鑰匙——appearance: base-select、::picker() 偽元素,以及強大的 sibling-index() 函數。準備好讓你的下拉選單煥然一新了嗎?
傳統 Select 的困境
在過去十年裡,前端工程師面對 <select> 元素時,內心都會浮現一個共同的疑問:「為什麼這麼難樣式化?」
無論你嘗試什麼:
select {
color: red;
background: blue;
border-radius: 8px;
}
結果往往是——什麼都沒變。那個熟悉的下拉箭頭依然固執地待在那個位置,背景色依然是我行我素的白色。這是因為 <select> 是一個「替換元素」(replaced element),它的渲染由作業系統和瀏覽器原生控制,傳統 CSS 幾乎無法干預。
但時代變了。CSS 規範帶來了一系列新武器,讓我們終於可以對原生選單下手了。
解鎖樣式的第一把鑰匙:appearance: base-select
什麼是 appearance?
appearance 是一個 CSS 屬性,用於控制元素是否使用作業系統的原生物件外觀。傳統上,你可能看過 appearance: none——這會完全移除原生樣式,讓元素變得像一個普通的 div。
但 none 太激進了,它把所有東西都拿走,連基本的行為都沒有。
base-select 的誕生
這時候 base-select 就派上用場了。它是 appearance 屬性的一個新值,專門針對 <select> 元素設計。讓我們看看它的效果:
.custom-select {
appearance: base-select;
}
加上這一行之後,奇蹟發生了——
- 原本不可修改的
color和background-color現在可以改變了 - 邊框、圓角終於聽話了
- 文字樣式(字體、大小、字重)也可以自由設定
但這只是第一步。base-select 讓元素變得「可樣式化」,但要真正自訂下拉選單的各個部分,我們還需要認識更多偽元素。
深入選單內部:::picker() 偽元素
認識 ::picker()
::picker() 是 CSS 新的偽元素,它代表 <select> 元素的下拉面板——也就是你點擊時彈出來的那個選項列表。
這是我們第一次可以對下拉選單的「內部」進行樣式控制!
/* 改變下拉面板的背景 */
select::picker(select) {
background-color: #1a1a2e;
border-radius: 12px;
padding: 8px;
}
::picker() 的強大應用
讓我們看一個完整的例子:
.theme-dark select::picker(select) {
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
border: 1px solid #0f3460;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
}
.theme-dark select::picker(select) li {
padding: 12px 16px;
color: #e8e8e8;
border-radius: 6px;
margin: 2px 0;
}
.theme-dark select::picker(select) li:hover,
.theme-dark select::picker(select) li:highlighted {
background: #0f3460;
color: #00d9ff;
}
你可以看到,我們現在可以:
- 設定下拉面板的背景(支援漸層和陰影!)
- 調整每個選項的內邊距和間距
- 自訂 hover 和选中状态的样式
這在以前是根本不可能做到的事。
鉤選標記:::checkmark 偽元素
::checkmark 的作用
除了下拉面板,選項旁邊的「勾選標記」也是可以自訂的。當一個選項被選中時,旁邊會出現一個勾勾,這就是 ::checkmark 偽元素代表的內容。
/* 自訂勾選標記 */
select::checkmark {
color: #00d9ff;
font-size: 14px;
}
完整範例:時尚的下拉選單
讓我們把這些技術整合在一起,創建一個現代感十足的下拉選單:
/* 基礎樣式 */
.fancy-select {
appearance: base-select;
padding: 14px 40px 14px 16px;
font-size: 16px;
border: 2px solid #e0e0e0;
border-radius: 12px;
background-color: #ffffff;
color: #333;
cursor: pointer;
transition: all 0.3s ease;
}
.fancy-select:hover {
border-color: #00d9ff;
box-shadow: 0 4px 12px rgba(0, 217, 255, 0.15);
}
.fancy-select:focus {
outline: none;
border-color: #00d9ff;
box-shadow: 0 0 0 4px rgba(0, 217, 255, 0.1);
}
/* 下拉面板 */
.fancy-select::picker(select) {
background: #ffffff;
border: 1px solid #e0e0e0;
border-radius: 12px;
padding: 8px;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
}
/* 選項樣式 */
.fancy-select::picker(select) li {
padding: 12px 16px;
border-radius: 8px;
transition: background 0.2s;
}
.fancy-select::picker(select) li:hover,
.fancy-select::picker(select) li:highlighted {
background: #f0f9ff;
color: #0077cc;
}
/* 勾選標記 */
.fancy-select::checkmark {
color: #00d9ff;
}
這段程式碼創造了一個有圓角邊框、 hover 效果、自訂背景的下拉選單——完全擺脫了原生外觀的束縛。
動態效果:sibling-index() 函數
什麼是 sibling-index()?
sibling-index() 是 CSS 的一個新函數,它可以返回當前元素在其所有兄弟元素中的索引位置。這個函數特別適合用在 <select> 的選項上,實現各種動態效果。
語法很簡單:
select li {
/* 索引從 1 開始 */
--index: sibling-index();
}
實際應用:編號效果
想象一個情境:你有一個選項列表,希望每個選項旁邊顯示它的編號。過去你可能需要用 JavaScript 動態添加,現在純 CSS 就可以做到:
/* 在選項前顯示編號 */
select::picker(select) li::before {
content: counter(list-item) ". ";
counter-increment: list-item;
color: #888;
margin-right: 8px;
}
不過更精確的做法是使用 sibling-index():
select::picker(select) li {
/* 使用 --index 變數 */
counter-set: option sibling-index();
}
select::picker(select) li::before {
content: counter(option) ". ";
color: #666;
font-weight: 600;
min-width: 24px;
display: inline-block;
}
進階應用:漸層顏色效果
sibling-index() 更酷的應用是創建漸層或花哨的顏色效果:
select::picker(select) li {
--hue: calc(sibling-index() * 30);
background: hsl(var(--hue), 70%, 95%);
}
select::picker(select) li:nth-child(1) { --hue: 0; } /* 紅色系 */
select::picker(select) li:nth-child(2) { --hue: 30; } /* 橙色系 */
select::picker(select) li:nth-child(3) { --hue: 60; } /* 黃色系 */
/* ...以此類推 */
或者用更動態的方式:
select::picker(select) li {
/* 根據索引計算色相,實現彩虹漸變效果 */
--hue: calc(sibling-index() * 40);
background: hsl(var(--hue), 80%, 90%);
color: hsl(var(--hue), 80%, 20%);
}
select::picker(select) li::before {
content: "🎨 ";
}
間距動態效果
你還可以根據索引調整間距,創造層次感:
select::picker(select) li {
--indent: calc(sibling-index() * 8px);
padding-left: calc(16px + var(--indent));
}
/* 讓第一個選項更醒目 */
select::picker(select) li:first-child {
font-weight: 700;
font-size: 1.1em;
border-bottom: 2px solid #00d9ff;
margin-bottom: 4px;
}
瀏覽器支援與相容性
當前支援狀態
截至 2026 年,這些特性的瀏覽器支援如下:
| 特性 | Chrome | Firefox | Safari | Edge |
|---|---|---|---|---|
appearance: base-select | ✅ 120+ | ✅ 121+ | ✅ 17.2+ | ✅ 120+ |
::picker() | ✅ 120+ | ✅ 121+ | ✅ 17.2+ | ✅ 120+ |
::checkmark | ✅ 120+ | ✅ 121+ | ✅ 17.2+ | ✅ 120+ |
sibling-index() | ✅ 123+ | ✅ 124+ | ✅ 17.5+ | ✅ 123+ |
優雅降級
為了確保在不完全支援的瀏覽器上也能正常運作,建議加上 fallback:
.custom-select {
/* Fallback:傳統樣式 */
background: #fff;
border: 1px solid #ccc;
/* 新式屬性 */
appearance: base-select;
}
@supports (appearance: base-select) {
.custom-select {
/* 進階樣式,只在支援的瀏覽器生效 */
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border: none;
}
}
總結:CSS 的新時代
我們從「對 select 無能為力」的過去走到了「可以完全掌控」的今天。appearance: base-select 解開了原生元素的封印,::picker() 讓我們可以樣式化下拉面板,::checkmark 讓勾選標記不再單調,而 sibling-index() 則為動態效果開啟了大門。
這些技術的結合,讓我們終於可以告別那個醜醜的原生下拉選單,創造出與網站整體設計完美融合的自訂選單。
下一當你專案需要美化下拉選單時,記得這些新武器:先從
appearance: base-select開始,然後用::picker()打造獨特的下拉體驗,最後用sibling-index()添加一點創意魔法。
Happy styling! 🚀