技術約12分で読めます

Safari 27.3 betaのAdaptive Dark Modeを防ぐcolor-schemeの書き方

いけさん目次

TL;DR

機能の概要 Safari 27.3 betaのAdaptive Dark Modeは、OSがダーク表示のとき、ダークモード未対応の明るいサイトをSafari側で暗く描き直す機能。ユーザーが設定で有効化する。

変換を止める条件 HTMLの <meta name="color-scheme" content="light dark"> か、CSSの color-scheme: light dark で対応を宣言しているページは変換対象から外れる。

注意点 変換を抑えるために color-scheme: light dark を宣言すると、OSがダークのときはブラウザ既定の文字色も明るい色へ変わる。背景色だけを白に固定して文字色を指定していないページでは、白い背景に白い文字が重なり読めなくなる。Adaptive Dark Modeが文字を白くしたのではなく、宣言とOSダーク設定による既定色の副作用。宣言とセットでダーク用の背景色・文字色を用意しておく必要がある。部分除外の light only はbeta 1ではまだ反映されない。


Appleが2026年11月3日に開発者向けに配布したiOS 27.3、iPadOS 27.3、macOS 27.3の最初のベータで、Safariに「Adaptive Dark Mode」が追加された。
WebKitの発表記事によると、ダークモードに対応していない明るい配色のサイトを、Safariが自動で暗い見た目に変換して表示する。

サイトを運営する側から見ると、ダーク用の配色を用意していないページが、Safari側の処理で配色を変えて表示される。
変換されるのは、ユーザーが機能を有効にしていて、ページがダーク対応を宣言していなくて、全体が明るい場合になる。
サイト側で決められるのはCSSの color-scheme の宣言なので、その書き方と、宣言を追加したときの挙動をコード例と一緒に整理してみる。

なお、Safari 27.3 betaの実機での見え方は未確認で、Adaptive Dark Modeの挙動の説明はWebKitの発表記事やCSS仕様・MDNの記述を元にしている。
記事中のコード例はmacOSのSafari 26.5.2で開き、color-scheme の宣言によってページの見た目がどう変わるかを確かめた。

Adaptive Dark Modeが何をするか

使うときは、まずOSの外観設定をダークにする。
その状態で背景の明るいサイトを開くと、Safariが変換後のプレビューを出し、「Try」をタップすると暗い表示に切り替わる。
9to5Macの記事では、自動で適用するか、サイトごとに選ぶかも設定できるとしている。

変換処理は、色の明るさ(輝度)を反転させつつ色相を保つ仕組みだ。
文字と背景のコントラストは、アクセシビリティ基準のWCAGが定める4.5:1を目標にしている。
ボタンや画像の上に載った文字、カーソルを重ねて出るメニューが使えなくならないよう、要素ごとに判定しているとも書いている。

要素ごとの扱いはこんな感じ。

対象Adaptive Dark Modeでの扱い
もともと暗い背景に明るい文字のページ何も変えない
CSSの明るいグラデーション暗くする
SVG画像アイコンやロゴが見えるよう、必要なら色を変える
ビットマップ画像ほとんどはそのまま。白黒の単純なロゴだけ、画素の明るさの分布(ヒストグラム)から判定して反転する
<canvas> の中身内容を予測しにくいので変えない
マスクや mix-blend-mode変換した要素では効果を無効にすることがある

変換されないための宣言

color-scheme は、その要素がライトとダークのどちらの配色で描画されてよいかをブラウザに伝えるCSSプロパティで、light dark と指定すると「自前でダークモードに対応している」という意味になる。

WebKitの発表では、この宣言があるページにはAdaptive Dark Modeは何もしない。
宣言の場所はHTMLの <head> か、CSSの :root や body を勧めていて、あとからJavaScriptで追加するのは避けるよう案内されている。

<!-- HTMLで宣言する。<head>の中、CSSより前に置く -->
<meta name="color-scheme" content="light dark">
/* CSSで宣言する */
:root {
  color-scheme: light dark;
}

次のように、読み込み完了後にスクリプトで宣言を追加する形は避けておく。

// 避ける例:ページ表示後にJavaScriptで宣言を追加している
window.addEventListener('load', () => {
  const meta = document.createElement('meta');
  meta.name = 'color-scheme';
  meta.content = 'light dark';
  document.head.append(meta);
});

宣言ごとの扱いはこんな感じ。

ページの状態変換されるか出典での扱い
light dark をmetaかCSSで宣言されないWebKitの発表に明記
light only をmetaかCSSで宣言変換から外す指定だが、beta 1では反映されないWebKitの発表に明記。beta 1では only キーワードに未対応と注記あり
宣言なしで、背景が明るいされるWebKitの発表に明記
宣言なしで、もともと暗いされないWebKitの発表に明記
light だけ、dark だけを宣言不明WebKitの発表には書かれていない

beta 1の時点で確実に変換を抑えられるのは、light dark を宣言する方法になる。

宣言だけ追加したときの文字消失

color-scheme: light dark は変換停止スイッチというより、「このページはダーク表示にも対応している」とブラウザへ伝える宣言だ。
この宣言があると、OSがダーク表示のときはブラウザ側の既定配色がダーク用に切り替わる。

CSSの仕様では、宣言で決まった配色がスクロールバーやフォーム要素の既定の色を変え、ルート要素(html タグ)ではページの背景色も変えるとしている。
文字色を指定していない要素は、ブラウザの既定の文字色を使う。
この既定色はOSやブラウザの配色に合わせて変わるシステムカラーで、ダーク用では明るい色になる。
そのため背景色だけを白に固定していたページでは、白い背景に白い文字が重なって読めなくなる。

<!-- 注意すべき例:宣言だけ追加して、ダーク用の配色を用意していない -->
<meta name="color-scheme" content="light dark">
<style>
  body {
    background: #ffffff; /* 背景は白に固定している */
    /* 文字色は指定していないので、ダーク表示では既定の明るい色になる */
  }
</style>

このコードに見出し、本文、リンク、入力欄、ボタンを追加したページを、Safari 26.5.2で開いた。
OSの外観設定がライトのときは、白い背景に黒い文字で普通に読める。

OSがライト表示のときのSafari 26.5.2。白い背景に黒い見出しと本文、青いリンク、白い入力欄とボタンが表示されている

OSをダーク表示に切り替えると、見出しと本文が消えた。
見出しと本文の位置は画素が白(#FFFFFF)になり、文字は背景と同じ真っ白で読めない。
表示が残ったのは薄紫のリンクと、黒いダーク用の外観に変わった入力欄とボタンだけで、白い背景から目立っている。

OSがダーク表示のときのSafari 26.5.2。見出しと本文は白い背景と同じ色で見えず、薄紫のリンクと黒い入力欄とボタンだけが表示されている

宣言を追加するなら、ダーク用の背景色と文字色も一緒に用意しておく。

ダークモードに対応した最小のコード例

1ファイルで試せる最小のコード例はこんな感じ。
ロゴ画像(logo-light.svg と logo-dark.svg)を同じフォルダーに置くと切り替えに対応でき、画像がない場合は代替テキストが表示される。
保存してブラウザで開き、OSの外観設定をライトとダークで切り替えると、配色が変わる。

<!doctype html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <!-- ダークモードに対応していると宣言する。CSSより前に置く -->
  <meta name="color-scheme" content="light dark">
  <title>color-schemeの例</title>
  <style>
    :root {
      color-scheme: light dark;
      /* light-dark(ライトのときの色, ダークのときの色) */
      --bg: light-dark(#ffffff, #121212);
      --text: light-dark(#1a1a1a, #e6e6e6);
      --muted: light-dark(#5f6368, #a0a4a8);
      --link: light-dark(#0b57d0, #8ab4f8);
      --card: light-dark(#f4f5f7, #1e1f22);
      --border: light-dark(#d9dce1, #3a3c40);
    }

    body {
      margin: 0;
      background: var(--bg);
      color: var(--text);
      font-family: system-ui, sans-serif;
      line-height: 1.7;
    }

    main {
      max-width: 40rem;
      margin: 0 auto;
      padding: 24px 16px;
    }

    a {
      color: var(--link);
    }

    .card {
      background: var(--card);
      border: 1px solid var(--border);
      border-radius: 8px;
      padding: 16px;
    }

    .note {
      color: var(--muted);
      font-size: 0.875rem;
    }
  </style>
</head>
<body>
  <main>
    <!-- ロゴはライト用とダーク用を出し分ける -->
    <picture>
      <source srcset="logo-dark.svg" media="(prefers-color-scheme: dark)">
      <img src="logo-light.svg" alt="サイトのロゴ" width="160" height="40">
    </picture>

    <h1>color-schemeの例</h1>
    <div class="card">
      <p>OSの外観設定を切り替えると、背景と文字の色が変わる。</p>
      <p><a href="#">リンクの色</a>もダーク用に変わる。</p>
      <p><input type="text" placeholder="入力欄もダーク用の見た目になる"></p>
      <p class="note">補足の文字は少し薄い色にしている。</p>
    </div>
  </main>
</body>
</html>

light-dark() は、ページの配色がライトのときは1つ目の色、ダークのときは2つ目の色を返すCSSの関数だ。
MDNによると、使うには color-scheme を light dark に設定しておくのが前提で、ふつうは :root に書く。
ロゴの出し分けに使っている <picture> と media="(prefers-color-scheme: dark)" の組み合わせは、WebKitの発表でもダークモード対応の手段として案内されている。

このページをSafari 26.5.2で開き、OSの外観設定をライトとダークで切り替えた。
画像ファイルがない状態では、ロゴ位置に代替テキストの「サイトのロゴ」が表示される。
ライト表示のときは白い背景に灰色のカードが並ぶ。

OSがライト表示のときの最小のページ。白い背景に薄い灰色のカード、黒い文字、青いリンク、白い入力欄が表示されている

ダークに切り替えると、背景、カード、文字、リンクが light-dark() の2つ目の色に変わり、入力欄もダーク用の外観になった。

OSがダーク表示のときの最小のページ。黒い背景に濃い灰色のカード、明るい文字、水色のリンク、黒い入力欄が表示されている

light-dark() に未対応のブラウザもサポートする場合は、メディアクエリで色を上書きする。
<style> の :root 部分を次のように変更する。

:root {
  color-scheme: light dark;
  --bg: #ffffff;
  --text: #1a1a1a;
  --muted: #5f6368;
  --link: #0b57d0;
  --card: #f4f5f7;
  --border: #d9dce1;
}

/* OSがダーク表示のときだけ上書きする */
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #121212;
    --text: #e6e6e6;
    --muted: #a0a4a8;
    --link: #8ab4f8;
    --card: #1e1f22;
    --border: #3a3c40;
  }
}

切り替えボタンでライトとダークを選ぶコード例

OSの設定に従うだけでなく、ページのボタンでライトとダークを選べるようにしているサイトも多い。
その場合も、<meta name="color-scheme" content="light dark"> はHTMLに最初から書いておく。
JavaScript側はユーザーが選んだ配色の反映に絞って処理させる。

<!doctype html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <!-- 宣言はHTMLに最初から書いておき、スクリプトで追加しない -->
  <meta name="color-scheme" content="light dark">
  <script>
    // 描画前に、保存済みの選択をhtml要素へ反映する(一瞬白く光るのを防ぐ)
    (() => {
      let saved = null;
      try {
        saved = localStorage.getItem('theme');
      } catch {}
      if (saved === 'light' || saved === 'dark') {
        document.documentElement.dataset.theme = saved;
      }
    })();
  </script>
  <title>切り替えボタンの例</title>
  <style>
    :root {
      color-scheme: light dark; /* 未選択のときはOSの設定に従う */
      --bg: light-dark(#ffffff, #121212);
      --text: light-dark(#1a1a1a, #e6e6e6);
    }

    /* ボタンで選んだときは配色を固定する */
    :root[data-theme="light"] {
      color-scheme: light;
    }

    :root[data-theme="dark"] {
      color-scheme: dark;
    }

    body {
      margin: 0;
      padding: 24px 16px;
      background: var(--bg);
      color: var(--text);
      font-family: system-ui, sans-serif;
    }
  </style>
</head>
<body>
  <button type="button" id="theme-toggle">ライト/ダークを切り替える</button>
  <p>ボタンで選んだ配色は次に開いたときも使われる。</p>

  <script>
    const root = document.documentElement;
    document.getElementById('theme-toggle').addEventListener('click', () => {
      // いま表示されている配色を調べて、反対側に切り替える
      const current = root.dataset.theme
        ?? (matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
      const next = current === 'dark' ? 'light' : 'dark';
      root.dataset.theme = next;
      try {
        localStorage.setItem('theme', next);
      } catch {}
    });
  </script>
</body>
</html>

色は light-dark() で定義しておき、ボタンでは color-scheme の値だけを切り替えている。
color-scheme: light にすると light-dark() は1つ目の色を返し、スクロールバーや入力欄もライト用の見た目になる。
OSがダーク表示でも利用者がライトを選んだ場合、フォームなどの部品まで含めてライト表示になる。

Safari 26.5.2で、OSをダーク表示にした状態でこのページを開いた。
最初は黒い背景に明るい文字で表示され、ボタンを押すとページ全体がライトに切り替わった。
ボタン自体もライト用の見た目になり、再読み込みしてもライトのまま維持されていた。

OSがダーク表示のまま、ボタンでライトを選んだあとのページ。白い背景に黒い文字、ライト用の見た目のボタンが表示されている

この例は <head> のmetaタグで light dark を宣言しているので、WebKitの説明に従えば、ダーク対応のページとして扱われて変換されない。
ただ、ユーザーがライトを選ぶと、CSS側では <html> の color-scheme が light だけになり、metaタグの宣言と食い違う。
metaとCSSの指定が食い違ったときにSafariがどちらを優先して判定するかは、WebKitの発表には書かれていない。
この組み合わせでどう扱われるかは、Safari 27.3 betaの実機で確認しておきたい。

一部だけ変換させない light only

特定の部分だけ変換を避けたい場合もある。
グラフの色分け、商品写真の背景、ブランドカラーで塗ったバナーなどがそれに当たる。

WebKitの発表では、light only を宣言すると変換の対象から外れる。
metaタグならページ全体、CSSなら要素を選んで指定できる。
ただし、Safari 27.3 beta 1の時点ではこの指定はまだ反映されない。

<!-- ページ全体を変換の対象から外す -->
<meta name="color-scheme" content="light only">
/* グラフと商品写真の枠だけ、ライトのまま表示させる */
.sales-chart,
.product-photo-frame {
  color-scheme: light only;
}

only はもともとCSSの仕様にあるキーワードで、仕様では「ブラウザがその要素の配色を上書きするのを禁じる」と定義されている。
MDNには、ChromeのAuto Dark Themeによる色の上書きを止める用途も書かれている。
仕様の文法では only は色の指定の前にも後ろにも置けるので、only light と light only は同じ意味になる。

ただし、WebKitの発表には「Safari 27.3 beta 1では only キーワードに対応していない」との注記がある。
ベータの更新に合わせて状況を確認する案内になっており、beta 1の時点では、部分的に外したい要素でも light dark を宣言したうえで自前のダーク配色を指定する形になる。

/* beta 1で変換を止める場合:その要素でダーク対応を宣言し、配色を自分で決める */
.sales-chart {
  color-scheme: light dark;
  background: light-dark(#ffffff, #1e1f22);
  color: light-dark(#1a1a1a, #e6e6e6);
}

変換に任せる場合に直しておくところ

自前でダーク用の配色を作らず、Adaptive Dark Modeの変換に任せる方法もある。
その場合でも変換後の崩れを防ぎやすいよう、WebKitの発表では以下の対策が挙げられている。

直すところ理由
ロゴやアイコンのビットマップ画像をSVGにするSVGは必要に応じて色を変換できるが、ビットマップは白黒の単純なロゴしか反転しない
タイル状の背景画像をCSSの単色やグラデーションにするCSSの色は変換できるが、背景画像はそのまま残る
画像のスプライトを最新のCSSに置き換えるスプライトもビットマップ画像なので、白黒の単純なロゴ以外はそのまま残る
本文の画像は背景を透過にし、背景色を画像データ内に含めない透過していない白い背景だけが暗いページの中で浮く
コンテナに余白(padding)を設ける要素同士が詰まるのを防ぐ

サイト側からの変換検出

WebKitの発表によると、SafariはAdaptive Dark Modeが適用されたことをサイト側から検出できないようにしている。
JavaScriptでCSSの色を読み出すと、サイトが指定した元の色がそのまま返る。
<canvas> から画像を取り出した場合も、元の色のまま描かれる。

そのため、アクセス解析のスクリプトなどでAdaptive Dark Modeの適用ユーザー数を集計することはできない。
実際の表示を確認するには、Safari 27.3 betaの実機でページを開いて確かめる形になる。

表示が乱れたページを見つけたときの報告先も、WebKitの発表に案内されている。
サイトの運営者はApple宛ての web-evangelist@apple.com へ、Safariの利用者はFeedback Assistantから報告できる。