iT邦幫忙

2025 iThome 鐵人賽

DAY 18
3
Modern Web

從 Canvas 到各式各樣的 Web API 之旅系列 第 18

Day 18 - EyeDropper API 滴管選色器

  • 分享至 

  • xImage
  •  

真的是需要休息一下... 今天來點輕鬆又有趣的! 😇
把整個螢幕當成調色盤,一滴就準。這篇超短,三分鐘懂一個「看起來像原生 App」的小魔法。 🎨

EyeDropper API 讓網頁呼叫「系統取色器」:使用者點一下螢幕任一像素,網站就能拿到 #RRGGBB(sRGB)色值。最常見應用:設計工具、佈景主題自訂、品牌色偵測、無障礙對比檢查。


1. DevTools 直接可貼的極簡範例(僅為示範,不建議正式使用)

用途:快速驗證你這台瀏覽器是否「大致可用」。有些瀏覽器要求必須是 使用者明確觸發 才給開滴管,因此這段 可能會失敗;但若環境寬鬆或你剛好有使用者啟動(user activation)狀態,它就能跑。

EyeDropper API 滴管選色器

EyeDropper API 滴管選色器alert

EyeDropper API 滴管選色器顏色區塊

(async () => {
  if (!("EyeDropper" in window)) {
    console.warn("此瀏覽器不支援 EyeDropper API");
    return;
  }
  try {
    // 以非同步方式開啟系統取色器,等待使用者選色
    const { sRGBHex } = await new EyeDropper().open();

    // 頁面右上角放 60x60 的色塊預覽(6 秒自動消失)
    const box = document.createElement("div");
    Object.assign(box.style, {
      position: "fixed",
      top: "12px",
      right: "12px",
      width: "60px",
      height: "60px",
      borderRadius: "10px",
      boxShadow: "0 2px 8px rgba(0,0,0,.2)",
      zIndex: 999999,
      border: "1px solid rgba(0,0,0,.1)",
      background: sRGBHex,
    });
    document.body.appendChild(box);
    setTimeout(() => box.remove(), 6000);

    // 最基本的通知方式:alert + Console
    alert(`Picked: ${sRGBHex}`);
    console.log("[EyeDropper] sRGBHex =", sRGBHex);
  } catch (err) {
    console.warn(
      "EyeDropper 可能被「需要使用者手勢」限制擋下,或你取消了取色。",
      err
    );
  }
})();

會發生什麼事?

  • 游標變滴管 → 點任一像素 → Console(與通知)顯示顏色,右上角短暫出現 60×60 色塊預覽。
  • 若失敗,多半是需要使用者明確觸發(如按鈕點擊)才能開啟;或你按了 Esc 取消。

註:這段設計成「一貼即跑」,方便讀者不寫 HTML 就能試。但正式功能請改用互動版範例。


2. 互動版(完整、可上線的做法)

以「按鈕觸發」滿足使用者手勢要求,並加上基礎 UX。

<button id="pick">Pick a color</button>
<p id="result">—</p>

<script>
  const btn = document.getElementById('pick');
  const result = document.getElementById('result');

  // 這是瀏覽器提供的「系統級取色器」介面,非所有瀏覽器都支援。
  const supported = 'EyeDropper' in window;
  if (!supported) {
    btn.disabled = true;
    result.textContent = 'Your browser does not support EyeDropper.';
  }

  btn.addEventListener('click', async () => {
    if (!supported) return;
    btn.disabled = true;
    try {
      // 以非同步方式開啟取色器,等待使用者在螢幕上點選一個像素。
      const eye = new EyeDropper();
      // 回傳物件包含 sRGBHex(如 "#a1b2c3"),代表 sRGB 色域的 16 進位顏色字串。
      // 多數瀏覽器要求必須在「使用者手勢」(例如 click 事件)中呼叫 open(),否則會被拒絕或拋錯。
      const { sRGBHex } = await eye.open();
      result.textContent = sRGBHex;
      result.style.color = sRGBHex;
    } catch (err) {
      console.log('Cancelled or failed:', err);
    } finally {
      btn.disabled = false;
    }
  });
</script>

小技巧

  • 取色進行中把按鈕 disable,避免瘋狂點擊。

底層原理

  • 誰來取色?其實不是你的網頁,而是瀏覽器本身。
    • 當你呼叫 new EyeDropper().open(),瀏覽器進入一個系統級的取色模式。游標下方的像素值並不是讓你的 JS 任意存取整張畫面,而是由瀏覽器在合成/呈現層(compositor,把圖層變成螢幕像素)上,對當前螢幕畫面進行單點取樣,只把結果(例如 #a1b2c3)回傳給你。
  • 作業系統 / 瀏覽器與裝置的連動
    • 桌面系統(如 macOS、Windows)都有原生取色器能力;瀏覽器實作會呼叫 OS 的對應能力或在自己的 GPU 合成管線 做像素讀取。重點是:
      • 你的網頁拿不到一整張螢幕的畫面,只得到一個像素的顏色
      • 這就是它比「螢幕錄影 API」更安全的原因:最小資料揭露(minimal disclosure)。
  • 為何常常需要使用者手勢?
    • 取色會覆蓋全螢幕游標行為,屬於「強互動」層級。
    • 為了避免網頁未經使用者同意就改變游標、造成困惑或被用於釣魚,瀏覽器規定要由 使用者明確觸發(例如按鈕 click)才允許。

不支援時的「兩段式降級」

原則:能選到顏色就好,體驗再慢慢加。

  1. 最簡降級:<input type="color">

input能選到顏色就好

<input type="color" id="fallback" value="#ffb703" />
  1. 圖片內取樣:Canvas Pixel Pick(進階)
  • 讓使用者上傳或拖拉圖片 → 繪到 <canvas> → 用 ctx.getImageData(x,y,1,1) 取 RGBA → 轉 #rrggbb

還記得 Day 4 - Canvas API 進階用法篇 介紹過的「像素級操作」嗎?當時我們學過如何用 getImageData 取得 Canvas 上任意位置的 RGBA 像素資料。這裡的降級方案就是運用這個技巧!


瀏覽器支援

仍建議在程式裡以 "EyeDropper" in window 動態偵測。

Browser 支援狀態 備註
Chrome / Edge / Brave / Opera ✅ 支援 可直接使用 new EyeDropper().open()
Safari (桌機/行動) ✅(新版本) 舊版不支援,請以特性偵測為準
Firefox ❌ 尚未支援 需降級方案

記住

  • 版本與平台細節可能變動,不要硬寫死版本號;用特性偵測最穩。
  • 如果你的產品面向 Firefox 使用者,務必提供 <input type="color"> 或 Canvas 取樣降級。

👉 歡迎追蹤這個系列,我會從 Canvas 開始,一步步帶你認識更多 Web API 🎯


上一篇
Day 17 - 超越 RWD:讓網站依裝置資源自動調整體驗!Network Information / Device Memory / Hardware Concurrency
下一篇
Day 19 - 滑鼠、鍵盤全接管!用 Pointer Lock API、Keyboard Lock API 做高強度互動
系列文
從 Canvas 到各式各樣的 Web API 之旅19
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言