網頁黑暗模式 Dark Mode 設計技巧 - Jason's Web Memo

網頁黑暗模式 Dark Mode 設計技巧

網頁黑暗模式 dark mode 的出發點是讓晚上夜貓子的使用者不會受到螢幕強烈的白光照射瞳孔,對於需要大量閱讀文字的服務如 blog 新聞類的網頁,利用黑底白字強調內容並增加訊噪比,是一個希望在黑暗環境中增進使用者體驗的做法,另外發的光少,也有節約電力的好處。本文介紹目前自己研究 dark mode 的心得以及設計技巧。

dark mode 顏色色盤設計注意事項

dark mode 顧名思義就是要黑底白字,但其實你如果直接用純黑底色 #000 純白文字 #fff,對比太強烈反而對於眼睛閱讀更不舒服,這個世界的顏色並非都是非黑即白的。因此設計時可以透過深灰來代替純黑,淺灰代替純白,閱讀上看起來會比較柔和。

而其他網頁元件顏色的選用,因為佔整個網頁的面積不像是文字那麼多,要記得要把明度拉高一點才不會被黑暗背景色吃掉變得不明顯。

用 css variable 實現 dark mode

css variable 是一個把 css 裡面用到的 value 都抽象成變數並放在 class 裡面,並透過抽換覆寫 body 或 html 最上層裡頭的 class 來決定 css variable 的內容,這個技巧使得網頁容易做到有色彩主題的功能,使用方式如下:

body {
--bgColor: #fff;
--fontColor: #424242;
background: var(--bgColor);
}

p {
color: var(--fontColor);
}

另外也還需要使用一個新的 media query prefers-color-scheme,是一個用來作為偵測系統目前是不是處於 dark mode 下的 media query,如果偵測裝置目前需要呈現 dark mode 我們就可以把 css variable 抽換成黑暗系色碼如下:

@media (prefers-color-scheme: dark) {
body {
--bgColor: #212121;
--fontColor: #bdbdbd;
}
}

這樣就完成了 dark mode 的功能,然而 css variable 目前美中不足的地方就是不支援 IE,如果你的服務必須要支援 IE,你可能就要在 dark 模式底下覆寫掉其他 class 的色碼。

黑暗模式中的圖片處理

去背圖片在黑暗模式中因為背景變成黑底色,可能就會造成深色內容被深色背景吃掉的問題,為了避免這個問題,建議 img 的背景一律調成跟正常模式的背景色

@media (prefers-color-scheme: dark) {
img {
background: #fff;
}
}

即使處理好文字以及背景的色系讓其在黑暗模式不過於刺眼,依舊會遇到另一個問題就是萬惡白底圖,大圖片的白底在 dark mode 裡面就像是被使用太陽拳(暴露年齡)一樣的刺眼,而每上一次圖都要去調整圖片的亮度做切換這樣十分的麻煩,還好 css 有提供一個屬性 filter 讓我們可以調整亮度這件事情

@media (prefers-color-scheme: dark) {
img,
video,
iframe
{
filter: brightness(0.9);
}
}

這樣就可以盡量減少白底圖的刺眼,提供更舒適的閱讀體驗

黑暗模式手動切換

但不是每一個使用者都希望照著裝置的喜好來看網頁,根據環境光線的不同,使用者可能需要手動做黑暗模式的主題切換,這時候我們必須利用 JavaScript 幫忙做一個切換的 switcher 按鈕,讓使用者自己可以開燈關燈,並儲存使用者的喜好進到 localStorage,讓他下次進來也可以保持一致的主題。

  1. 把原本 prefers-color-scheme 的 style 都改到 .dark 的下面
  2. 偵測並使用使用者上次喜好的主題,若無則使用裝置預設的喜好主題
  3. 把切換按鈕綁定 click 事件,點擊則做主題切換,並儲存主題喜好進到 localStorage

其中第二步從其他 blog 參考過來的作法如下:

<script>
var preferredTheme;

try {
preferredTheme = localStorage.getItem("theme");
} catch (err) {}

function setTheme(newTheme) {
if (newTheme !== document.body.className) {
window.__theme = newTheme;
preferredTheme = newTheme;
document.body.className = newTheme;
}
}

window.__setPreferredTheme = function (newTheme) {
try {
if (newTheme !== preferredTheme) {
localStorage.setItem("theme", newTheme);
}
} catch (err) {}
setTheme(newTheme);
};

var darkQuery = window.matchMedia("(prefers-color-scheme: dark)");

darkQuery.addListener(function (e) {
window.__setPreferredTheme(e.matches ? "dark" : "light");
});

setTheme(preferredTheme || (darkQuery.matches ? "dark" : "light"));
</script>

剩下就把 window.__setPreferredTheme 綁定到切換按鈕下就完成了。

注意這段 script 建議 inline 插在 <body> 下面,利用 sync script 會 block rendering process 的特性,在畫面渲染前設定好正確的 class ,避免渲染兩次會顏色忽白忽黑的跳動問題,如果你是在類似 React.useEffect 瀏覽器渲染之後才設定 theme 就容易導致顏色跳動問題。

心得

也許黑暗模式 dark mode 可能照顧了使用者在光線不足下的閱讀體驗,但並不是每一個服務都適合 dark mode,像我覺得電商類的服務就沒有那麼適合,黑黑的看的購物慾都沒了,也有許多網站做了 dark mode 也沒有提供使用者手動做切換的功能,有時候我用 dark mode 只是想要我的系統列在 mac 上有個黑框而已,而被逼的我逛每一個網站都黑黑的。

黑暗模式真的顧眼睛嗎?我是抱持著存疑的態度。另外畢竟不是所有的網站都有實作 dark mode,用 dark mode 瀏覽網頁導致瞳孔放大,不小心切換到沒有實作的網站,放大的瞳孔又瞬間被太陽拳重擊一發,說不定更不舒服啊。晚上還是早點睡,別看螢幕才是最好的做法啊。

Webmention 社群迴響 12

喜歡 12
轉推 0
    引用或評論 0

      用 Webmentions 參與社群迴響

      若你的 blog 文章想要引用本文,請確認 blog 文章含有正確的本文網址連結,並且 blog 文章本身支持 microformat,歡迎透過下方表單用將你的 blog 文章網址傳送給我,之後你的引用資訊會更新在上面社群迴響的引用評論列表。

      或是透過 twitter 轉推,你的轉推評論之後會更新在上面社群迴響的引用評論列表。

      轉推這篇文章

      社群迴響將不定期更新,不保證同步,同時有資料缺漏的可能性。 最新回應請參考以下連結:

      Jason Chen - Yahoo Taiwan EC Web frontend engineer currently. Write something about web and React.js here

      Jason Chen

      Yahoo Taiwan Sr. Frontend Engineer. Write something about web and React.js here.


      訂閱 blog 掌握最新文章

      訂閱 RSS 更新,複製 xml 網址

      加入 Google Groups 訂閱電子報

      追蹤我的 Medium,文章異步更新

      Other Posts