HOWTO · CSS

CSS 中的樣式選擇下拉選單

本教程介紹瞭如何在 CSS 中設定下拉選單的樣式。

本頁內容

您可以調整原生 HTML select 下拉選單的外觀,並以 CSS 繪製的箭頭取代預設箭頭。這仍是真正的 select 控制項,因此使用者保有內建的選取行為與鍵盤操作功能。常見做法有兩種:直接移除原生外觀,或用包裝元素裁切掉原生箭頭。

設定原生 select 下拉選單的樣式,同時保留其行為

select 包含 option 元素,而瀏覽器會依照平台與自身慣例來呈現控制項。CSS 可以修改可見的控制項外框,但彈出選項清單及部分細節仍會因瀏覽器和作業系統而異。若要保留內建的表單與鍵盤操作功能,請使用原生元素,不要用通用元素重新製作下拉選單。

範例使用相同的四個選項。CSS 在控制項右側預留箭頭空間,並為鍵盤使用者提供清楚可見的焦點外框。您可以調整顏色與尺寸,讓它符合介面設計。

使用 appearance: none 隱藏原生箭頭並新增自訂箭頭

在 select 上設定 appearance: none,即可在支援此設定的環境中移除瀏覽器的原生箭頭,接著用兩個 CSS 漸層繪製 V 形箭頭。background 圖層會將兩道線條放在靠近右側的位置;右側內距則讓選項文字不會貼近線條。-webkit-appearance 和 -moz-appearance 是供使用這些前綴的引擎採用的廠商前綴形式,並不代表各自對應不同的 WebKit/Blink 瀏覽器家族。標準屬性是主要宣告;只有在瀏覽器支援需求需要時,才保留前綴版本。

這是一個完整的靜態瀏覽器範例。將它儲存為 HTML 檔案並在瀏覽器中開啟,即可查看控制項;封包沒有提供瀏覽器實際呈現結果的證據,因此本文不宣稱已確認其視覺效果。

本節中的程式碼以及顯示的標籤或輸出仍為英文。

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Styled select</title>
  <style>
    .vehicle-select {
      box-sizing: border-box;
      width: 220px;
      height: 40px;
      padding: 0 32px 0 10px;
      border: 1px solid #777;
      border-radius: 4px;
      color: #222;
      background-color: #fff;
      background-image:
        linear-gradient(45deg, transparent 50%, #333 50%),
        linear-gradient(135deg, #333 50%, transparent 50%);
      background-position:
        calc(100% - 14px) 50%,
        calc(100% - 9px) 50%;
      background-size: 5px 5px, 5px 5px;
      background-repeat: no-repeat;
      appearance: none;
    }

    .vehicle-select:focus-visible {
      outline: 3px solid #1769aa;
      outline-offset: 2px;
    }
  </style>
</head>
<body>
  <label for="vehicle">Choose a vehicle</label>
  <select class="vehicle-select" id="vehicle" name="vehicle">
    <option>RE Himalayan</option>
    <option selected>CRF Rally</option>
    <option>GS 310</option>
    <option>KTM ADV</option>
  </select>
</body>
</html>

使用裁切包裝元素隱藏原生箭頭

包裝元素也能用來隱藏原生箭頭。將 select 的寬度設為略大於包裝元素,並把包裝元素的 overflow 設為 hidden;原生箭頭便會落在包裝元素的可見範圍之外。接著用偽元素在包裝元素上繪製替代箭頭。由於 select 仍位於包裝元素內,選項與原生互動功能都會保留。

包裝元素的寬度要足以容納控制項文字,而 select 只需比它稍寬。如果兩者寬度差距太大,控制項右側邊框或其他內容也可能被裁切。偽元素使用 pointer-events: none,因此不會攔截對 select 的點擊。

在包裝元素範例中,select 比包裝元素多出 20 像素。以下簡短的 JavaScript 檢查會明確確認這個尺寸關係:

本節中的程式碼以及顯示的標籤或輸出仍為英文。

const wrapperWidth = 200;
const selectWidth = 220;
if (selectWidth <= wrapperWidth) {
  process.exitCode = 1;
}

當 select 比包裝元素寬時,這項檢查會順利完成;否則便會設定失敗的結束代碼。

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Select with clipped arrow</title>
  <style>
    .select-wrap {
      position: relative;
      box-sizing: border-box;
      width: 200px;
      height: 42px;
      overflow: hidden;
      border: 1px solid #777;
      border-radius: 4px;
      background: #fff;
    }

    .select-wrap select {
      box-sizing: border-box;
      width: 220px;
      height: 40px;
      padding: 0 10px;
      border: 0;
      color: #222;
      background: transparent;
      font: inherit;
    }

    .select-wrap::after {
      position: absolute;
      top: 18px;
      right: 12px;
      width: 7px;
      height: 7px;
      border-right: 2px solid #333;
      border-bottom: 2px solid #333;
      content: "";
      pointer-events: none;
      transform: rotate(45deg);
    }

    .select-wrap:focus-within {
      outline: 3px solid #1769aa;
      outline-offset: 2px;
    }
  </style>
</head>
<body>
  <label for="vehicle">Choose a vehicle</label>
  <div class="select-wrap">
    <select id="vehicle" name="vehicle">
      <option>RE Himalayan</option>
      <option selected>CRF Rally</option>
      <option>GS 310</option>
      <option>KTM ADV</option>
    </select>
  </div>
</body>
</html>

選擇合適的做法並確認限制

如果希望由 select 本身決定寬度與邊框,而且目標瀏覽器支援所需樣式,可以使用 appearance: none。如果需要在包裝元素上放置箭頭,或不適合直接設定外觀,則可使用裁切包裝元素的做法。無論選擇哪一種,都請在支援的瀏覽器與裝置上測試頁面:原生 select 的呈現方式與彈出選單並不完全一致。

請確認選取值完整可見、自訂箭頭位置正確,而且鍵盤焦點清楚易辨。若使用包裝元素的做法,當邊框或文字看起來遭到裁切時,請比對包裝元素與 select 的寬度。不要只為了讓控制項看起來更簡潔就移除焦點指示;若要自訂樣式,請改用同樣清晰的指示方式。這些技巧會改變外觀呈現,但仍由原生 select 負責選取與表單行為。