スマホで潰れる日本語の表

はじめに

自分の記事をスマホで開いたら、表が読めなかった。

何が起きていたか

ユニバーサルデザイン7原則の非対称に、8つのゴールを並べた3列の表がある。ゴール名、内容、層。スマホで開くと、どの列も語の途中で折り返した。3列目は「身」「体・」「知覚」まで潰れ、5行目のゴール名は「Understanding(理」「解)」で割れる。切れた断片をつなぎ直しながら読むことになり、いちばん高い行は本文4行分の高さになる。行が伸びた分だけ画面に収まる行数は減って、表を見渡すという読み方ができない。

幅を100%に固定した表。どの列も数文字ずつで折り返し、いちばん高い行が4行分の高さになっている
図1: 幅を100%に固定していたときの表

横スクロールできる箱は、最初から用意してあった。overflow-x: auto の div で包んで、キーボードでも送れるように tabindex="0" も付けてある。表そのものに overflow を付けると display が変わって表として読まれなくなるので、外側の div で受ける形だ。用意はしてあったのに、スクロールバーは一度も出なかった。

原因は表の幅指定だった。table { width: 100% } と書いてある。これは「箱に収まれ」という意味になる。そして日本語は、どの文字の間でも改行できる。列が要求する最小の幅は、1文字分まで下がれる。つまり、はみ出す前に潰れる。はみ出さないので、横スクロールの箱は最後まで仕事をしない。

英語なら単語の途中で割れないから、ある幅から先は潰れずに素直にはみ出して、横スクロールになる。同じ CSS で、日本語だけが静かに壊れていた。

潰すか、はみ出させるか

横スクロールを出すのは後退のような気がしていた。調べたら逆で、表はもともと例外の側にいた。

1.4.10 リフローは、320px 相当の幅で2方向のスクロールを求めないことを要求する。ただし「利用や意味のために2次元の配置が必要な部分」は除く、と書いてある。行と列の交差そのものが情報になっている表は、その代表例だ。横スクロールする表は、それだけでは違反にならない。

やってはいけない側は、はっきりしている。狭い画面で display: block を当てて、1行を1枚のカードに組み替えるやり方だ。見た目は収まる。代わりに table・tr・td の display が変わって、表としての役割が落ちる。「何列目の値か」という読み上げの手がかりが消えるので、収まったのは見た目だけになる。

そこで、狭い画面では潰す代わりにはみ出させることにした。

@media (width < 44rem) {
  table {
    width: max-content;
    min-width: 100%;
    max-width: 160vw;
  }

  th,
  td {
    min-width: 6em;
  }
}

max-content で内容が要求する幅を優先し、min-width: 100% で短い表は今までどおり幅いっぱいに広げる。max-width: 160vw は横スクロールの量の上限で、画面1.6個分を超える分は折り返しに回す。長い文が1行のまま何画面も伸びるのを止めるためだ。セルの min-width は、その折り返しが起きたときに列が再び潰れないための下限。

名前のないタブ位置

スクロールできる箱には tabindex="0" が要る。ポインタを持たない人が、キーボードだけで横に送るための足がかりだ。

ただ、これだけだと別の問題が残る。役割も名前もない div にタブが止まる。読み上げの利用者には「何かに止まったが、それが何なのか分からない」状態になる。タブが止まる以上、名前と役割が要ると考えるのが自然だ(4.1.2 名前・役割・値)。

名前をどこから取るか。表の題を置く要素は caption で、これは表そのものの名前として読まれる。題を段落や見出しで書いても、表と題の結びつきは支援技術に伝わらない。ところが Markdown の表に caption を書く記法がない。

なので、表の直前に [8つのゴール] だけの行を置くと caption になる記法を足した。番号は出てきた順に振って「表1: 8つのゴール」になる。この下にある表も、そうやって題を付けている。

スクロールできることが、目で分からない

はみ出すようになったあとで、もっと素朴なことに気づいた。スクロールできると、どうやって分かるのか。

止まっている画面に残る手がかりは「右端でセルが切れている」だけだ。しかもそれは、文字が右端で折り返しているだけの見た目と区別がつかない。

スクロールバーは、環境によって出かたが違う。

表1: 環境ごとのスクロールバーの出かた
環境 止まっているとき
Windows・Linux のデスクトップ 出ている(場所を取る)
macOS 出ない(重ね表示。システム設定で常時表示にはできる)
Android Chrome 出ない
iOS Safari 出ない(変える設定もない)

つまりスマホでは、指を離した時点で手がかりが消える。

CSS だけで解けるかを探したが、行き止まりだった。「いま、はみ出しているか」を CSS が知る手段は長らく無く、最近入った @container scroll-state() は Chromium 系にしか来ていない。

結局、2つ重ねた。

1つは、スクロールバーを出しっぱなしにすること。Chromium と WebKit は ::-webkit-scrollbar にスタイルを当てると重ね表示をやめて、場所を取るバーに切り替わる。overflow-x: auto のままなので、はみ出していない表にバーは出ない。嘘の合図にはならない。

もう1つは、スクロールできる向きの端をぼかす JS。端まで送ったら、その側のぼかしを消すようにした。出しっぱなしにすると「まだ続きがある」という嘘になる。

バーが出ている環境では、この2つが同時に見える。

横スクロールを途中まで送った表。左右の端がぼけていて、表の下にスクロールバーが出ている
図2: バーとぼかしが同時に出ている状態

問題はバーが出ない側だ。iOS Safari のように ::-webkit-scrollbar が効かない環境で何が残るかを見たかったので、バーを消して撮ったのが下の1枚。表は左端にいるので、ぼけているのは右側だけ。この1つが、まだ続きがあることを示す唯一の合図になる。

スクロールバーを消して撮った表。右端だけがぼけていて、続きがある側を示している。左上に「表2: 8つのゴール」の題が見えている
図3: バーを消して撮った状態。ぼかしだけが残る

穴は残っている。JS が止まればぼかしは消え、バーの出ない環境と重なれば、セルの切れ目だけに戻る。

※ 画像はダークテーマでの表示。出かたは手元で確かめた範囲のもので、iOS の実機では未確認。

達成基準が無いところ

直し終えてから、今回触ったものを達成基準に並べ直してみた。

横スクロールそのものは 1.4.10 の例外で守られている。キーボードで送れることは 2.1.1 キーボードが要求する。名前と役割は 4.1.2 で拾える。では「スクロールできることが、見て分かるか」はどこにあるか。見つからなかった。

近いものはある。2.4.7 フォーカスの可視化は、いまどこにいるかが見えることを要求する。1.4.11 非テキストのコントラストは、UI 部品の輪郭が背景から見分けられることを要求する。けれどスクロールバーはブラウザが出す部品で、こちらが置いた UI 部品ではない。どちらの射程にも素直には入らない。

前の記事で、読解に関わる基準が AAA と参考文書に置かれている話を書いた。検証できる形に落ちるものが必須の側に来て、読み手によって割れるものが外に残る。今回も同じ形だった。「スクロールできることが伝わるか」は、ページを機械で見て判定できない。判定できないものは、達成基準にならない。

表は直った。スマホで開いても読める。ただ、直ったと言える根拠は「自分がスマホで見て読めた」でしかない。一周して、また同じ壁の前にいる。

記事一覧に戻る