1つの状態が計算される流れ
各状態はRGBAピクセルに順に適用する操作の一覧です。アウトラインがあれば先にキャンバスを広げ、明るさは値 × 255をR・G・Bに足し、コントラストは中間のグレー(128)を中心に広げ、彩度は各チャンネルをそのピクセルの輝度(0.2126 R + 0.7152 G + 0.0722 B)から遠ざけたり近づけたりします。続いて任意の色のオーバーレイ、ピクセルの移動、形を正方形に膨らませたアウトラインを描き、最後にアルファを掛けます。完全に透明なピクセルは塗り替えません。
エンジンはこれらの画像を決まった枠で受け取ります。Godot 4のTextureButtonにはtexture_normal、texture_hover、texture_pressed、texture_disabled、texture_focusedがあり、専用のテクスチャがないdisabledのボタンはnormalを表示し、focusedのテクスチャは基本のテクスチャの上に重ねて描かれます。UnityのUI ButtonはTransitionをSprite Swapにすると、Target Graphicの基本スプライトとHighlighted・Pressed・Disabledのスプライトを受け取ります。
ゲームはWebページではありませんが、WCAG 2.2の2つの規定は知っておく価値があります。達成基準1.4.3は無効(disabled)なコンポーネントの一部であるテキストをコントラストの最低基準から除外しているので、薄くしたdisabledは許容されます。2.4.13 Focus Appearance(AAA)は、コンポーネントの外周2 CSS px以上の大きさのフォーカス表示と、フォーカス前後のピクセル間で3:1のコントラストを求めます。既定のリングは2pxで、#3182f6は白に対して3.71:1と測定されます。
- 明るさ
- すべてのチャンネルに足す値。+0.1は+25.5段階です。
- 彩度
- +0.08は各チャンネルを輝度から8%遠ざけ、−1はピクセルをグレーにします。
- オフセット
- 同じキャンバスの中でピクセルを移動。はみ出た分は捨て、入ってくる側は透明です。
- アウトライン
- 不透明な形の周りに付く指定の色・太さのリング。キャンバスがその太さ分広がります。
例:1ピクセルが既定の5状態を通ると
色(200, 120, 40)で塗った40 × 16のボタンです。書き出したPNGに実際に入る値です。
状態 ピクセル (R, G, B, A) サイズ 操作
normal (200, 120, 40, 255) 40 × 16 なし
hover (231, 145, 58, 255) 40 × 16 明るさ +0.1 (+25.5)、彩度 +0.08
pressed (174, 94, 14, 255) 40 × 16 明るさ −0.1、オフセット 0,1 → 0行目が透明に
disabled (131, 131, 131, 128) 40 × 16 彩度 −1、アルファ × 0.5
focus (200, 120, 40, 255) 44 × 20 キャンバス各辺 +2px、2pxのリング (49, 130, 246)
disabledのグレー 0.2126 × 200 + 0.7152 × 120 + 0.0722 × 40 = 131.2 → 131;アルファ 255 × 0.5 = 127.5 → 128
hoverの緑 輝度 156.7 + (145.5 − 156.7) × 1.08 = 144.6 → 145
focusの画像はほかより縦横4px大きく、アウトラインが正方形の膨張なので角のピクセルまでリングが覆います。states.jsonに状態ごとのサイズと余白が記録されるので、違いに驚くことはありません。