白い背景なら黒い字にする等を自動化する。
成果物
See the Pen Untitled by ytyaru (@ytyaru) on CodePen.
特徴
- 背景と文字の色から見やすさの指標を算出する
- WCAG2と3の指標を両方算出する
- 背景から文字色を白黒のいずれか算出する
- 色と太さから見やすい最小サイズを算出する
デザインに詳しくなくても適当にUIをイジっていれば適切な色やサイズを提示してくれる。あるいは見やすさの指標を提示するので目安にできる。
要件
任意の背景色を指定したら自動的に見やすい文字色を白黒のいずれかで返して欲しい。
それを実現するために見やすさの指標が欲しい。
解答
WCAG ver | name | range | 指標 |
---|---|---|---|
2.2 | Contrast | 1〜21 | 7, 4.5, 3 |
3.0 | Luminance Contrast(Lc ) |
0〜106(-108) | 90, 75, 60, ... |
Lc
は背景のほうが明るいと+106
、背景のほうが暗いと-108
を返す。これを絶対値にして用いる。
WCAG 2.2
対象 | AA |
AAA |
---|---|---|
テキスト | 4.5 | 7 |
大きな字 | 3 | 4.5 |
UI | 3 | 3 |
フォーカス有無差 | 3 | 3 |
ロゴ、非活性UI | - | - |
WCAG 2.2 & 3
2 | 3 | 概要 |
---|---|---|
7.0 | 90 | 本文に推奨される |
4.5 | 75 | 本文が満たすべき最小値 |
3.0 | 60 | 非本文が満たすべき最小値 |
- | 45 | 見出しなど大きく太ければ見える |
- | 30 | テキスト最小値 |
- | 15 | 非テキスト最小値 |
- | - | 人には見えないものと扱うべき |
以下参考。
WCAG? APCA?
略語 | 用語 | 意味 |
---|---|---|
WCAG | Web Content Accessibility Guidelines | 老人や障害者でも認識しやすいWebコンテンツを作る方法 |
APCA | Advanced Perceptual Contrast Algorithm | WCAG3におけるコントラスト基準。 |
WCAGはUXを実現する方法論。今Web業界ではアクセシビリティ関係が盛んに更新されている。色盲などのハンデがある人でも参照しやすいコンテンツを作るための方法論を体系化している。それがWCAG。次の四大原則がある。
No | 原則 | 詳細 |
---|---|---|
1 | 知覚可能(Perceivable) | ユーザーが情報を知覚できる形式で提供すること。例えば、テキストの代替テキストを提供したり、色覚特性を持つユーザーのために十分なコントラスト比を確保したりすること。 |
2 | 操作可能(Operable) | ユーザーがUIを操作できる状態にすること。例えば、キーボードで全ての機能が操作できるようにしたり、十分な時間制限を提供したりすること。 |
3 | 理解可能(Understandable) | ユーザが情報や操作方法を理解できるようにすること。例えば、コンテンツの言語を明確にしたり、予測可能なインターフェースを提供したりすること。 |
4 | 堅牢(Robust) | ユーザーエージェント(ブラウザや支援技術)と互換性があるようにコンテンツを開発すること。例えば、HTMLのマークアップを適切に使用したり、支援技術がコンテンツを正しく解釈できるようにすること。 |
WCAGに従えばクオリティの高いコンテンツが作れる。とりあえずWCAG 2.2 仕様書の目次だけでも流し読みすれば、どこに気をつけるべきか見当が付く。
既存ライブラリ
じつは自分で実装しなくても済む。
chroma.js
規格 | メソッド |
---|---|
WCAG2 | chroma.contrast() |
WCAG3 | chroma.contrastAPCA() |
実装
自分が欲しい機能だけを持った小さなライブラリを作りたかった。
Google先生に聞けばAIが答えてくれた。特にWCAG2に関してはコードが短いため丸ごとコピペできるレベル。
- WCAG2コントラスト比(4.5以上)
- APCA(90以上)
1. WCAG2コントラスト比(4.5以上)
js 色 コントラスト差 算出
でググったらコードが出た。
function getContrast(color1, color2) { const lum1 = relativeLuminance(color1); const lum2 = relativeLuminance(color2); const brightest = Math.max(lum1, lum2); const darkest = Math.min(lum1, lum2); return (brightest + 0.05) / (darkest + 0.05); } function relativeLuminance(color) { const r = parseInt(color.substring(1, 3), 16) / 255; const g = parseInt(color.substring(3, 5), 16) / 255; const b = parseInt(color.substring(5, 7), 16) / 255; const a = [r, g, b].map((v) => { return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4); }); return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722; } // 使用例 const color1 = "#ff0000"; // 赤 const color2 = "#0000ff"; // 青 const contrastRatio = getContrast(color1, color2); console.log(`コントラスト比: ${contrastRatio}`); // コントラスト比が4.5以上であれば、WCAGのAA基準を満たすと判断できる if (contrastRatio >= 4.5) { console.log("AA基準を満たしています"); } else { console.log("AA基準を満たしていません"); }
もう自分でコード書かなくていいやん。全部Google先生にやってもろたらええやん。
私から趣味を奪わないで! AI優秀すぎィ!
ありがたくパクらせてもらおう。
2. APCA(90以上)
js APCA contrast 算出
でググるとAPCA算出ライブラリが提示された。そのコードであるapca-w3.jsを見ると外部ライブラリに依存したNode.jsコードだったので、これをブラウザで動作する依存しないPure JSコードに書き直した。
ふ、AI君もまだまだだね。人間様がいなければコードを出せないらしい。やれやれ、仕方ないな。私がコードを読んでパクって整理してやろう。
コードの詳細はCODE参照。主要なコードは以下。
color.js
color.jsには3つのクラスがある。
クラス | 概要 |
---|---|
Color |
整数配列や文字列から色データを取得できる |
WCAG |
WCAG2.2のコントラスト比を算出する |
APCA |
WCAG3.0のLcを算出する |
WCAG.contrast(color1, color2); // 1〜21
APCA.calc(fore, back); // 0〜106(-108)
名前が微妙。APCAはWCAGに含まれるので適切ではない。以下のようにするほうが正確だが、長くなるので上記のようにした。WCAG自体よく知らないので適切な名付けができない。
WCAG | メソッド | 値 |
---|---|---|
2.2 | WCAG.contrast(color1, color2) |
1〜21 |
3.0 | WCAG.luminanceContrast(fore, back) |
0〜106(-108) |
Color.of([R,G,B]) Color.of([R,G,B,A])
Color.of('#RGB') Color.of('#RGBA') Color.of('#RRGGBB') Color.of('#RRGGBBAA')
WCAG
やAPCA
の内部でColor
を使っているため、色は数列、文字列、Colorインスタンスの3種類のいずれかの方法で入力できる。
[R,G,B]
は0
〜255
の整数値、#RGB
はR
,G
,B
それぞれ0
〜F
までの16進数で表す文字列。
たとえば以下のようになる。
WCAG.contrast('#000', '#fff'); // 21
APCA.calc('#000', '#fff'); // 106
あとは以下の基準値に照らし合わせて適時適切にお好みで色々やればいい。たとえばAPCAの90以上のみ許容するようにするとか。デザイン知識ゼロでも見やすい色を設定できるはず。
WCAG | APCA | 概要 |
---|---|---|
7.0 | 90 | 本文に推奨される |
4.5 | 75 | 本文が満たすべき最小値 |
3.0 | 60 | 非本文が満たすべき最小値 |
- | 45 | 見出しなど大きく太ければ見える |
- | 30 | テキスト最小値 |
- | 15 | 非テキスト最小値 |
- | - | 人には見えないものと扱うべき |
ちなみに生成したColor
に対する反対色/補色/白黒を返すゲッターも用意した。
const c = Color.of('#000'); c.mono.code // 白黒のいずれかコントラストが強いほうを返す c.reversal // 反対色 c.complementary // 補色
これらを使ってDEMOを作った。
所感
本番では素直にchroma.js使ったほうが良いかもね。今回は自分で実装してみたくて書いたけど。