コンテンツにスキップ

ADR-0066: コードを動かす画面の詰めたペイン、木の行の中の名前の欄、SplitPane の仕切りで、フォーカスの輪を要素の内側に引く

Status

承認

Context

コードを動かす画面のペインを隙間なく並べ、行を 24px に詰めたときの、フォーカスの表示を決める必要がある。

  • フォーカスの表示は、要素から 2px 離して引く墨の 2px の輪で、focus-ring の 1 つのユーティリティで書くと決めている。例外は検索の欄だけである。
  • コードを動かす画面だけ、文字を 12px と 13px まで、押せる領域を 24×24 CSS px まで小さくすると決めている。
  • コードを動かす画面は、ペインの間の隙間と外側の余白をなくし、木の行を 24px、HTTP の流れの行を約 44px に詰めた。
  • 外へ広がる輪は、次の所で欠けるか、隣に掛かる。
    • スクロールする領域の中で、領域の幅いっぱいの木の行と HTTP の流れの行の輪は、左右が領域の端で切れる。
    • 24px の木の行が隙間なく並ぶので、輪が上下の行に 4px 掛かる。
    • ペインの全体を占める、スクロールする領域(コンソールの行の領域、エディタのエンジン)の輪は、隣のペインと題の帯に出るか、ペインの端で切れる。
    • エディタのタブの並びは横にスクロールするので、タブの輪の上下が切れる。
  • VS Code と Chrome の DevTools は、一覧の行のフォーカスを、行の内側に引く枠で示す。
  • ファイルの木(FileTree)は、作成と名前の変更を、木の行の中の名前の欄で行う。
    • 木の行は 24px で、上下に 2px の余白がある。名前の欄は 20px の高さで、1px の枠(border-field)を持つ。
    • 欄のある行に内側の輪を引くと、輪の内側の線が欄の枠の上辺と下辺に接する。
      • 上下は、墨の 2px の輪と 1px の枠がつながり、3px の帯に見える。右は、6px をあけて縦の線が 2 本並ぶ。
      • 名前に誤りがあるときは、赤の枠が墨の輪の中に見え、二重の枠になる。
      • 欄のある行の輪は 1 重の輪にならず、ほかの行の輪とも見え方が違う。
    • VS Code のエクスプローラーは、行の中の名前の欄のフォーカスを、欄の 1 本の枠で示し、行には輪を出さない。名前に誤りがあるときは、その枠を赤に替える。 どちらも記憶によるもので、実物で比べていない(未確認)。
  • フォーカスの表示は、1 つのユーティリティ(墨の 2px の 1 重の輪)だけを使い、コンポーネントごとに色や太さを変えない(FOCUS-ONE)。
  • 分割の幅を変える SplitPane の仕切りは、マウスで押す端末の PC の配置では、ペインの間の 8px の余白に置く。8px の幅の外に 2px 離して輪を引くと、両側のペインの面に重なる。

Decision

  • テーマ変数のファイルに、focus-ring-inset のユーティリティを足す。色と太さは focus-ring と同じ墨の 2px で、輪を要素の内側に 2px 入れて引く(outline-offset: -2px)。
  • 使う所は、コードを動かす画面のコンポーネントの次の要素に限る。
    • TreeView の density="compact" の項目。名前の欄を描いている行には、フォーカスの輪を引かない。欄が、自分のフォーカスの表示を持つ。
    • FileTree の名前の欄。輪は欄の 1px の枠に重ねて、欄の内側に引く。
      • 名前に誤りがあるときも、輪は墨のままにする。誤りは、欄の下の印と理由の文と、aria-invalid で示す。
    • Tabs の density="compact" のタブと、マウスで押す閉じるボタン
    • HttpExchangeList の行
    • 分割の幅を変える SplitPane の仕切り
    • ペインの全体を占める、フォーカスできるスクロールする領域。当たるのは、ConsoleEntryList の行の領域と、カタログの見本のエンジン(DummyEngine)である。
      • この領域には focus-ring-inset を付けない。領域自身に輪を引かない。中の行や帯の背景が、領域自身の輪を上から塗って欠けさせるためである。領域を 1 つだけ直下に置く外側の要素に focus-ring-frame を付け、直下の領域にフォーカスが来たときに、外側の要素の ::after へ同じ輪を内側に重ねて引く。
  • プレイグラウンドの実物のエディタと端末のエンジンは、コードを動かす画面の ToolPane に入れるときに、同じ内側の輪にする。付ける作りは、エンジンごとに、その画面を作る issue(#95、#99、#100)で決める。
  • ほかの要素は、focus-ring のままにする。
  • 理由は次のとおり。
    • 輪が要素の中に収まるので、隣の行に掛からず、領域の端で切れない。行の密度も変えずに済む。
    • VS Code と DevTools の一覧の行と同じ表示で、利用者が見慣れている。
    • 名前の欄は、欄の枠と輪が重なるので、表示が 1 重の輪になる。
    • 名前の欄の輪の位置が、名前を打つ範囲と同じになる。
    • 名前に誤りが無いときは、記憶にある VS Code の行の中の欄と同じ表示になる(実物で比べていない。未確認)。
  • FOCUS-ONE の例外に、focus-ring-inset と focus-ring-frame の 2 つを足す。

Verification

カタログの「画面/コードを動かす画面」を、Chromium の 1600x900 で開いて確認した。

  • 木の行と HTTP の流れの行にキーボードでフォーカスを置くと、輪は行の中に収まり、上下の行とペインの端に掛からなかった。ライトとダークの両方で見た。
  • compact のタブは、コンポーネントのテストで、フォーカスしたときの輪が要素の内側(outline-offset: -2px)に引かれることを確認した。
  • コンソールの行の領域とカタログの見本のエディタのエンジンは、コンポーネントのテストで、外側の要素の ::after に内側の輪が引かれ、領域自身の輪が出ないことを確認した。エンジンの輪が、カーソルのある行の帯と行番号の列で欠けないことは、画面でも撮って確認した。端末の見本のエンジンも、テストで同じことを確認した。
  • 内側の輪が WCAG 2.2 の達成基準 2.4.13(AAA)を満たすかを、次のとおり確認した。
    • 太さ: focus-ring-inset と focus-ring-frame の輪は、どちらも outline: 2px solid で、2px 以上である(theme.css の値)。
    • 面積: 輪は要素の外周の内側 2px に引くので、面積は外周の 2px の帯と等しい。
    • コントラスト: pnpm run check:contrast が、輪の色と面の組を 3:1 以上で確認する。組には、選んだ行(primary-surface)、コードの面、warning-surface、danger-surface を含み、ライトとダークの 108 組が届いた。
    • 隠れ: 外側の要素の ::after が最前面に出るので、カーソルのある行の帯と行番号の列に隠れない。画面で確認した。
    • 画素単位の、フォーカスの前後の同じ画素のコントラストは、測っていない(未確認)。面の色との組で代える。
  • 実物のエディタと端末のエンジンの現状は、次のとおり。どちらも、この ADR の対象のコンポーネントには入っていない。
    • SQL のエディタ(apps/playground/src/sql-console/SqlConsole.tsx)は、囲む要素に has-[.cm-focused]:focus-ring を付け、輪を外へ引く。.cm-focused は、フォーカスを受ける .cm-content の外側の要素に付く。
      • そのため、focus-ring-frame の「直下の :focus-visible」の条件に当たらない。
    • Go の端末(apps/playground/src/go/GoPage.tsx)は、スクロールする pre に focus-visible:focus-ring を付け、輪を外へ引く。この pre は、focus-ring-frame の直下に置けば、同じ内側の輪になる。
    • 実物のエンジンを ToolPane に入れたときの輪の見た目は、撮っていない(未確認)。
  • 選んだ木の行(primary-surface)の上でも、墨の輪は見えた。輪と面の組は、ADR-0061 でコントラストのチェックに入れてある。
  • Safari と Firefox での確認はしていない。

名前の欄は、次のとおり確認した。

  • 単体テストで、名前の欄の輪が outline: 2px solid で outline-offset: -2px であり、欄の行に輪が無いことを確認した。
  • カタログの コンポーネント/Case/FileTree を Chromium で開き、作成、名前の変更、名前の誤りの 3 つを、ライトとダークで静止画に撮って見た。輪は欄の枠に重なって 1 重に見え、欄の文字は輪に欠けなかった。
  • ハイコントラストでの見え方は、画面で見ていない(未確認)。輪は outline なので残るが、枠と輪が同じ色になり、フォーカスの前後の違いは線の太さだけになる見込みである。

Considered Options

詰めたペインの行と枠の輪の案は、次の 3 つ。

選択肢 強み 弱み
採用: 詰めたペインの行と枠だけ、内側に輪を引く 輪が欠けず、隣にも掛からない。行の密度を変えない。VS Code と DevTools と同じ表示 フォーカスの表示が 2 つになる。内側の輪は、行の中の文字や印に近づく
スクロールする領域と行の間に 4px の余白を足し、外へ広がる輪のままにする フォーカスの表示が 1 つのまま 木の行の間が広がり、DevTools と VS Code に近い密度にならない
今のまま、欠けた輪を受け入れる 変更が無い 左右が欠けた輪は上下の 2 本の線になり、輪の形で見つけにくい。上下の行の文字に掛かる

木の行の中の名前の欄の輪の案は、次の 3 つ。

選択肢 強み 弱み
採用: 欄に内側の輪を引き、行には引かない 1 重の輪になる。輪の位置が打つ範囲と同じ。記憶にある VS Code の表示と同じ(未確認) 欄は開いている間ほぼ常にフォーカスを持つので、誤りの赤の 1px の枠は、ほかのウィンドウへ移ったときのほかは見えない。focus-ring-inset を使う所が 1 つ増える
行の輪を残し、欄を低くして輪との間を空ける 行に輪を引く形を変えない 欄が 16px になり、13px の文字が欠けるおそれがある
今のまま、行の輪と欄の枠を並べる 変更が無い 二重の枠に見え、1 重の輪にならない

Consequences

Positive

  • 詰めたペインで、どの行と枠にフォーカスがあるかを、欠けない輪で示せる。
  • 名前の欄のフォーカスを、ほかの要素と同じ 1 重の輪で示せる。

Negative

  • フォーカスの表示のユーティリティが 3 つになる。focus-ring-inset と focus-ring-frame をコードを動かす画面の外で使っていないかは、レビューで見る。
  • 内側の輪は、行の背景の面の上に出る。行の面とのコントラストは、ADR-0061 がコントラストのチェックに入れた、輪と面の組で確認する。
  • 名前の欄は、フォーカスが外れると確定か取り消しで閉じるので、開いている間ほぼ常にフォーカスを持つ。そのため、ほかのウィンドウへ移ったときのほかは、名前の誤りを赤の枠で示せない。誤りは、欄の下の印と理由の文と、aria-invalid で示す。
  • TreeView の editor に欄を渡す側が、欄のフォーカスの表示を受け持つ。