- contrast-color() 関数を使うと、ボタンなどさまざまな背景色に合わせてブラウザが 黒または白の文字色 を自動で選択する
- 大規模プロジェクトでも テキストの可読性維持 が容易になり、保守効率を高められる
- 現在 Safari Technology Preview では WCAG 2 の公式アルゴリズムを使っているが、これは実際の人間の知覚とずれる可能性がある
- 次世代の APCA アルゴリズム導入の議論が WCAG 3 の開発過程で進んでおり、より良い 明度コントラスト評価 が期待されている
- 単純な白黒コントラスト以外にも、今後はさまざまな色オプションや アクセシビリティ改善 機能が追加される見込みである
概要と contrast-color() 導入の背景
- 複数のボタンやインターフェース要素に多様な背景色が使われるデザインでは、文字色(テキストカラー) の可読性が重要である
- これまでは開発者が背景色と文字色を一つひとつ適切に組み合わせる必要があったが、大規模プロジェクトでは 管理の複雑さとエラー発生 のリスクが高かった
- contrast-color() CSS 関数を使えば、開発者は背景色だけを指定すればよく、ブラウザが黒または白の文字色のうちコントラストの高い方を自動で選ぶ
- この方法により 保守とデザイン作業の効率 が大きく向上する
- 簡単に
color: contrast-color(色); のように宣言して使える
contrast-color() の使い方の例
- ボタンの背景色変数に任意の色を指定し、テキスト色は
contrast-color() を使って自動的に対照的な白黒のどちらかが選ばれる
- 一度に1つの色だけを管理すればよいため、デザインポリシー変更やダーク/ライトモード対応時の maintenance が容易になる
button {
background-color: var(--button-color);
color: contrast-color(var(--button-color));
}
- Relative Color Syntax を活用すると、hover 状態についても背景色とテキスト色を一貫して管理できる
アクセシビリティ上の考慮事項とアルゴリズムの説明
contrast-color() を使っても、すべての アクセシビリティ(Accessibility)問題 が自動的に解決されるわけではない
- 特定の中間的な明るさの背景色では、黒・白のどちらも必要基準を満たさない場合がある
- 現在 Safari Technology Preview で使われている WCAG 2 アルゴリズム は公式なウェブアクセシビリティ標準である
- このアルゴリズムはコントラスト比に基づいて選択するが、実際に見える明度コントラストと一致しない結果になることもある
- 例として、#317CFF の青い背景では機械的には黒のほうが高コントラストと計算されるが、実際には白のほうが読みやすい
- これに対する批判と改善要求を受け、次世代アクセシビリティ標準(WCAG 3) では、より優れた APCA(Accessible Perceptual Contrast Algorithm) の導入が議論されている
- APCA は 人間の知覚特性 を反映して色コントラストを計算するため、実際の可読性をよりよく保証する
実際の環境で十分なコントラストを提供する
- CSS の
@media (prefers-contrast: more) メディアクエリを使うと、ユーザーのアクセシビリティ設定 に応じて追加の高コントラストスタイルを適用できる
@media (prefers-contrast: more) {
/* 더 높은 대조 스타일 정의 */
}
- たとえば、ブランドの基調色が #2DAD4E のような明るい緑である場合、将来的に
contrast-color() が白を選ぶようになっても、小さな文字では依然として十分なコントラストが得られない可能性がある
- APCA アルゴリズムを適用すると、フォントサイズや太さに応じて必要な最小コントラスト基準を詳細に参照でき、実務でのデザイン判断に役立つ
- 実際に 24px/400 ウェイトの文字には白の適用が適しているが、さらに細い FONT や小さな文字には、より濃い背景色の使用が推奨される
- デザインチームは light/dark mode、prefers-contrast の設定などを考慮し、各条件に合ったカラーパレットを変数で簡単に管理できる
--button-color: #2DAD4E;
@media (prefers-contrast: more) {
@media (prefers-color-scheme: light) {
--button-color: #419543;
}
@media (prefers-color-scheme: dark) {
--button-color: #77CA8B;
}
}
button {
background-color: var(--button-color);
color: contrast-color(var(--button-color));
font-size: 1.5rem;
font-weight: 500;
}
- 要するに
contrast-color() のおかげで、背景色を中心に色だけを管理すればよく、テキスト色のコントラストの組み合わせはブラウザが自動生成してくれる
黒と白を超えて
- 現在の
contrast-color() は白黒2種類からしか選べないが、初期バージョンでは複数色から選ぶことも可能だった
- CSS Working Group は将来のアルゴリズム変更や互換性のため、単純なバージョン(白黒のみ選択)を先に提供し、将来的にはユーザー指定の色オプション や希望する最小コントラスト基準の指定などの拡張も計画している
- 単純な用途にはすでに十分有用である
- この関数は 背景色だけでなく枠線やその他の視覚要素 にも幅広く活用できる
結論と参考情報
- 次世代アクセシビリティ標準が反映された後、
contrast-color() はアルゴリズムを置き換えて、より良いコントラストの自動選択をサポートするようになる
- それまでは、基調となる背景色が明確に明るいか暗い場合に特に有用である
- テキスト以外のさまざまな UI 要素にも幅広く適用できる
- APCA(Accessible Perceptual Contrast Algorithm) のような最新のアクセシビリティアルゴリズムにも継続して注目するのが望ましい
参考資料
- APCA 公式文書および APCA Contrast Calculator でさまざまな例や評価基準を確認できる
- CSSWG の contrast-color 関数 に関する標準化議論が進行中
- WebKit や関連コミュニティで意見共有やフィードバック参加が可能
1件のコメント
Hacker Newsのコメント
この問題を解決するために、設計段階で色の組み合わせがシンプルで予測可能な WCAG/APCA コントラスト比を持つように、パレットを作るツールを開発中です。https://www.inclusivecolors.com/ ではデスクトップでより多くの機能を提供しています。1つの方法として、100(明るい色)から 900(暗い色)まで段階別の色見本を作り、たとえば 700 段階の色は 100 段階と、800 段階は 200 段階と明確なコントラストが出るように明度を調整する設計です。こうすると red-700 vs gray-100、green-800 vs yellow-200 のような組み合わせが、明度チェックなしでも確実に対比を提供すると分かります。Contrast メニューでは、WCAG と比べて APCA アルゴリズムがどれだけ厳しいか、特に明るい背景の暗い文字に対してどれだけ厳格かも確認できます。これがダークテーマで WCAG を使うべきでない理由です。Examples メニューで Tailwind や IBM Carbon のパレット事例を見ると、各段階で彩度と色相(Hue)が非線形に変化しているため、単純に白黒のうち最適なコントラストを選ぶのは簡単でも、ブランディングが重要なパレットでは単なる明度調整だけでは色を作れない、より複雑な問題だと分かります.
lchを使って似たことをする方法があります出典: https://til.jakelazaroff.com/css/…
LCH もすばらしいですが、OKLCH はさらに優れています。https://evilmartians.com/chronicles/oklch-in-css-why-quit-rgb-hsl/… この記事が私の考えを完全に変えるきっかけになりました。本当にすごいツールです。驚いたことに、私のデザイナー仲間の中で OKLCH を知っている人は誰もいませんでした。この方式は多くの問題を解決します。
こういうふうにコールバック的にパラメータを受け取れる CSS 関数は初めて見ました。本当に興味深い概念です。
lch以外にもこういうスタイルの関数があるのか気になります。Lea Verou がこれに似た回避策について書いた良い記事があります。https://lea.verou.me/blog/2024/contrast-color/
この記事は、コントラストの自動選択方式の長所と短所を見事に概観しています。シンプルなサイトを作るなら、この方法は手軽かつ簡単に適切なコントラストを得られます。
ただし、大規模に WCAG コンプライアンスが必要な場合は避けるべきで、本当に必要なのは意味ベースのフォーマットトークン階層です。意味トークンは開発速度を上げ、単なる黒/白の切り替えよりも視覚的に見栄えの良いコントラストを保証できます。意味トークン階層の良い点は、テーマ作成が非常に簡単で、ライト/ダークテーマもほぼ追加コストなしで実現できることです。ブランドカラーが WCAG2 を満たさない場合は、WCAG2/APCA 専用の別テーマを作ることで、コンプライアンスを確保しつつより良いコントラストを提供できます。
私は Figma で variables/tokens 周りを担当しており、Figma と Atlassian のダークモード実装にも関わりました。トークン、テーマ、アクセシビリティカラーについて質問があれば歓迎します。
意味トークンというのが具体的にどういうものなのか気になります。こうした機能がないので、私が関わった大きなプロジェクトでは色の相対計算やコントラスト色のために CSS-in-JS を使っていました。こういう技術が近いうちに広く使われることを期待しています。
最後の 2/3 は冗長すぎて衒学的に見えます。企業サイトやアプリでは結果の色が予測不能なので、こういう関数に依存するのは危険です。WebKit がバグを直しただけで色の結果が変わるかもしれないからです。
コントラスト色がブラウザベンダーの判断で決まるのが、常に正しいとも予測可能ともまだ思えません。すべてのブラウザが同じ結果を出す決定的な基準が整うのか気になります。この関数は実際には UX チームのデザイン段階を支援するツールに見えます。
記事によると、標準では計算方法が明確に規定されているとのことです。
「選ぶ(choose)」という表現は曖昧に感じます。実際にはアルゴリズムが色を算出しています。
リンク先にある APCA の例の式で、誤りや紛らわしい点を除けば 100% 正確に動作します。完全に一貫させるなら、2つの候補色(より明るいもの/暗いものの両方)が同時に許容される場合、背景色の明るさ(L*)を基準に、たとえば L* が 60 以上なら明るい方を選ぶようにすればよいです。そうすれば 100% の一貫性が得られます。
大規模プロジェクトでボタンが見えない色(たとえば暗いのに黒文字)に変わってしまわないよう個別に面倒を見るのは大変ですが、実際にはリリース前にボタンを全部点検すればよいのではとも思います。あるいは、チーム全体で暗いボタンに黒いテキストは絶対禁止だと事前ルールを決めて共有する方法もあります。知覚上のコントラストと数学的なコントラストの違いが興味深かったです。ワークフローに取り入れる予定です。
実際、ボタンの全件確認は不可能ではありませんが、こういうやり方だと事前の回帰テスト期間が数週間、ひどいと数か月かかることもあります。大規模プロジェクトならボタンが数千個を超えるのは珍しくなく、特定のオプションの組み合わせやワークフローでしか現れないボタンも多いです。
APCA を参照すれば、知覚ベースのコントラスト計算が可能です。
システムカラーが人気だった頃にボタンスタイルを作っていた経験があります。見た目は良かったのですがコントラスト比が分からなかったので、誰かが JavaScript の
getComputedStyleで計算してくれるようにしていました。コントラストが不十分なら第2候補の色を使い、どうしてもだめな場合はtext-shadowで文字の周囲にコントラスト効果を足していました。計算方法は忘れましたが、3つの RGB 値を平均して比較すればよさそうな気もします。青では平均値が低くなるので、白文字を優先しやすいかもしれません。少なくとも light/dark テーマで、active、focus、hover、link、visited のような疑似クラスごとに良い色の推奨を示してくれるといいですね。Material UI はこれに disabled、before、after 状態まで追加しています。
以前、背景色に応じて黒/白のテキストを選ぶ方法で動画チュートリアルを作ったことがあります。私のやり方は単純で、色をグレースケールに変換してから黒/白のどちらを使うか決めていました。楽しい作業でした。動画制作の腕前はいまひとつですが。
https://youtu.be/tUJvE4xfTgo?si=vFlegFA_7lzijfSR (ポルトガル語注意)
https://news.ycombinator.com/item?id=44015990
動画も悪くなさそうです。コードは良さそうですが、私はポルトガル語が分からないので内容の評価はできません。
配色全体を自分で選ぶのに、なぜボタンのコントラスト用テキスト色だけは最初から自分で選ぶより簡単だと言えるのか疑問です。この機能が必要になるのは、背景色は任意にばらばら選ぶのに前景色(ボタンの文字色)だけは選べない、というかなり極端な状況だけに思えます。本当に問題になるのは、画像や多様な背景の上に置かれるテキストのように常に見えなければならないものですが、この機能ではまったく対応できません。なので、かなり限定的な場面でしか役立たなそうな機能のために新しい動詞まで作り、しかも機能は白黒選択だけで、さらに最も良くないコントラスト選択アルゴリズム(WCAG 2)を使ったのは残念です。いやはや見事ですね。
どんなツールでも、自分が使う場面に遭遇したことがないからといってすぐに切り捨てる見方は残念です。ウェブサイトの中には、ユーザーが任意に色を選んだり、アップロードされた素材から色を抽出したりするケースが多くあります。アクセシビリティを重視するサイトでは、こういう場合に自動コントラスト計算が必須になります。こうした CSS の組み込み機能が出てくれば、基本的なアクセシビリティも簡単に確保できます。もちろん、より高度な体験を作りたい開発者の自由を妨げるものでもありません。
contrast-colornpm パッケージのように、もっとカスタマイズ可能ならなお良いですが、ブログによればまずは白黒だけを選ぶアルゴリズムを第一段階として導入し、今後の改善計画もあるそうです。例: https://coolors.co/8fbfe0-7c77b9-1d8a99-0bc9cd-14fff7
コントラスト選択アルゴリズムがいまひとつだという指摘については、WCAG 2 アルゴリズムに従っており、今後 WCAG 3 が標準化されればそのアルゴリズムへ容易に切り替えられることを明確に述べています。
SASS や Tailwind などに適用できる、この種の機能のビルド時代替手段があるのか気になります。この機能が全面的に導入されるまでには時間がかかりそうですし、プラットフォームごとに実装が同じになるのかも心配です。