D2D アクセシビリティ勉強会 ~WAI-ARIAでアクセシブルにしてみよう~2017年03月20日 12時09分

先日大阪で開催された「D2D アクセシビリティ勉強会 ~WAI-ARIAでアクセシブルにしてみよう~」に参加しました。Web ページ (特に JavaScript を使った動的なもの) のアクセシビリティを高めていくための話と演習です。

前半

前半は SAWADA STANDARD DESIGN の澤田さんによる発表「WAI-ARIAの考え方と使い方を整理しよう」です。

  • WAI-ARIA は要素 (の役割) と属性を追加する
    • 構造や変化をユーザーエージェントに伝える
  • ロール (役割) にはランドマークロール、文書構造ロール、ウィジェットロールがある
    • HTML にもともと同じロールの要素があるのならそれを使えばいい (無理に WAI-ARIA のロールを指定する必要はない)
  • ロールは文書構造やウィジェットを示すだけであり、見た目や機能を変化させるわけではない
    • 見た目を変化させるには CSS が必要
    • 機能 (挙動) を変化させるには JavaScript が必要
  • 実際に支援ソフト (スクリーンリーダーなど) が対応しているか
    • macOS / iOS には VoiceOver、Android には TalkBack、Windows にはナレーターが標準で付属している
      • VoiceOver のローター機能でランドマークを読み上げられる
    • 日本では PC-Talker のシェアが高いので、そこを押さえておきたい

後半

後半はグループごとに分かれ、実際に WAI-ARIA を使ってみる演習です。グループごとに「新着情報」「アコーディオン」「タブメニュー」の三つのお題の中から二つを選び、WAI-ARIA の属性を適宜追加していきました。回答発表時には VoiceOver での読み上げ確認も行われました。

各グループでの議論のポイントおよび回答例はみるくさんの「D2D アクセシビリティ勉強会 ~WAI-ARIAでアクセシブルにしてみよう~を開催しました。 - White Stage」に掲載されています。

感想など

「新着情報」では「続きを読む」リンクにラベルや説明を追加するか議論し、私のグループでは「過不足なく」という観点から (説明過剰にならないように) 結局追加しませんでした。しかし、視覚障碍者は Tab キーでリンクだけたどっていくこともあるので、リンクにも何の続きかわかるようラベル (aria-labelledby 属性、aria-label 属性) や説明 (aria-describedby 属性) を付けたほうがいいとのこと。


回答例を見ると、

<dl>
  ...
  <dt id="day01">2016年5月8日</dt>
  <dd>
    <p id="headline01">第6回 D2D アクセシビリティ勉強会でアクセシブルなフォームを作成!</p>
    <a id="more01" href="news01" aria-labelledby="day01 headline01 more01">&gt;&gt;続きを読む</a>
  </dd>
</dl>

のように aria-labelledby 属性に自分自身の ID を指定しており、そんなこともできるのかとびっくりです。


CMS で生成された内容に適用しやすいよう、新着情報への WAI-ARIA の属性の指定を JavaScript で行うというチームもありました。サーバー側でやるかクライアント側で付与やるかはさておき、指定を (そしてできることなら検証も) 自動化していくのは、広く利用されるために重要なことでしょう。


WAI-ARIA のウィジェットロールの指定は React のような宣言的な UI 記述と相性がよさそうです。「WAI-ARIA 対応のアクセシブルなタブ UI を React で実装する ::ハブろぐ」という記事もあります。

一方、[aria-hidden="true"] { display: none !important; } のように CSS の属性セレクタを使うという話もありましたが、こちらは BEM などの命名規則と組み合わせるとどうなるのか、気になるところです。


懇親会では tabindex 属性に二つの意味があって分かりづらいという話が出ました。その要素にフォーカスできるかどうか (tabindex 属性が存在するかどうか) と、Tab ナビゲーションの順序はどうなるか (tabindex 属性の値が 0 以上のとき) です。この辺りは IE 5 の拡張 (HTML 4 ではリンクとフォームコントロール要素にしか付けられなかった tabindex 属性を、どんな要素にも付けられるようにした) に根差すことでしょうから、今考えるならもう少しうまくできるのではと思ってしまいますね。


勉強会後に Windows 用スクリーンリーダー NVDA をインストールしてみました。開発者向けには「ポータブル版を作成」し、必要に応じて起動したほうがよいとのことです。ポータブル版作成時に、指定したフォルダの直下にファイルが展開されるので、新規にフォルダを作ってそれを指定するのがよさそうです。

CSS の -webkit-line-clamp プロパティについて2016年12月02日 15時07分

結論からいうと、CSS の -webkit-line-clamp プロパティは使わないほうがいい。現状および今後の Web ブラウザでのサポートが望めないからである。

-webkit-line-clamp CSS プロパティとは何か

複数行でも3点リーダーをきかせることができるというもの。

このプロパティはどうやって使うか

-webkit-line-clamp プロパティ単体では効果を持たず、他のプロパティと組み合わせて使う。

selector {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
}

このプロパティは何のために存在するのか

おそらくは Apple 製アプリケーションでの内部的な利用のため。このプロパティは、Safari CSS ReferenceAdditional Unsupported Properties の項に記載がある。

WebKit provides partial support for a number of properties that are not supported for developer use. This list may include:

  • Properties designed for Apple internal use, such as properties specific to the way Mail and other applications use WebKit.
  • Properties that are in a very early stage of development and are not really usable yet.
  • Properties that are used within WebKit itself and cannot be parsed in a CSS file.
  • Properties that are parsed for historical reasons, but that are not actually used.

適当に訳すと、

WebKit は、開発者の使用に対してはサポートされないプロパティを、いくつか部分的にサポートしている。このリストには以下を含む:

  • Apple の内部的な利用 (Mail など、WebKit を使うアプリケーションに固有のもの) のために設計されたプロパティ。
  • 開発のごく初期段階であり、まだ実用に耐えないプロパティ。
  • WebKit 内部で使われ、CSS ファイルからはパースできないプロパティ。
  • 歴史的な理由でパースはされるが、実際には使われないプロパティ。

このプロパティの開発状況はどうなっているか

このプロパティは -webkit-box、すなわち旧式の flexbox (flexible box) と組み合わせる必要がある。現 flexbox 仕様とは相いれない。このことから、このプロパティは旧 flexbox 時代に内部利用のため、もしくは実験的に実装され、そのまま放置されたものではないかと推測される。実際に上述の文書ではこのプロパティが「サポートされない」ものとして挙げられている。

このプロパティをベンダ接頭辞なしで書く必要があるか

ない。display: -webkit-box というのは旧 flexbox 仕様の値にベンダ接頭辞をつけたものであり、そこからベンダ接頭辞を外して display: box と書いたところで、どのブラウザもサポートしていない。現 flexbox 仕様では display: flex という全く別の値を使うようになっている。なので、

selector {
  display: -webkit-box;
  display: box;
  -webkit-box-orient: vertical;
  box-orient: vertical;
  -webkit-line-clamp: 3;
  line-clamp: 3;
}

のようにベンダ接頭辞付きのプロパティを併記するのは無意味である。後述するように、line-clamp というプロパティが制定されることもない。

このプロパティは標準化されるのか

line-clamp というプロパティ名では標準化されない。2014 年 6 月の W3C CSS WG のミーティングにおいて、-webkit-line-clamp プロパティのことが議題に上がっている。そこでの結論としては、最大行数の指定とブロックに対する省略記号の問題は別々に議論していこうというものである。

-webkit-line-clamp プロパティの持つ、

  • 最大行数の指定
  • 最大行数をはみ出した内容の扱い
  • 省略記号の表示

という機能は別々のプロパティや疑似要素として CSS Overflow Module で検討されていくことになると思われる。(該当 issue)

余談: ベンダ接頭辞について

開発者が -webkit- ベンダ接頭辞付きのプロパティ / 値しか書かないという状況が蔓延したため、ベンダ接頭辞は無意味なものとなった。今やモバイル向けブラウザの多くは (WebKit でなくとも) -webkit- ベンダ接頭辞付きのプロパティを解釈する。(そうしないとモバイル向け Web サイトがまともに機能しない)

挙句の果てには、――これは CSS ではなく DOM の話だが――webkit 接頭辞付きのメソッドがエイリアスとして仕様に取り込まれるという体たらくである。

これらの反省から、現在のブラウザ開発ベンダはベンダ接頭辞を使わず、開発版ブラウザを使っているときや、ユーザーが明示的にオプションを有効にしたときのみ仕様策定中の機能を有効にするという方針になっている。ベンダ接頭辞は、かつて試験的に実装されたプロパティにつけることはあっても、今後新規に実装されていくプロパティにつける必要はない。

ベンダ接頭辞をつけるにしても、手動でつけていくのではなく、Autoprefixerのようなツールを使って自動的につけていくのが確実である。


この記事は、はてなエンジニアアドベントカレンダー 2016 の 2 日目の記事として公開された。翌日の担当は id:wtatsuru である。

flexbox レイアウトで内容がはみ出す理由2016年04月03日 02時23分

flex box layoutで中に長いテキストなどを含む幅可変要素のレイアウト - くらげだらけ」という記事が興味深いです。過去に「長い英単語を途中で折り返したいときの CSS の指定方法」にて、word-wrap: break-worddisplay: inline-block などの組み合わせには注意が必要 (word-wrap の指定が効かないように見えることがある) と述べたのですが、似たようなことが display: flex にも言えるようです。

この挙動は認識していなかったので CSS Flexible Box Layout Module Level 1 (flexbox 仕様草案、2016 年 4 月 2 日時点のもの) を見てみたところ、「4.5. Implied Minimum Size of Flex Items」(flex アイテムの暗黙的な最小サイズ) の項に記述がありました。

flex アイテム (display: flex または display: inline-flex を指定した要素の子要素) の最小幅 (flex アイテムが水平方向に並ぶ場合) は、(min-width プロパティで明示的に指定していなければ) flex アイテムの内容の最小幅または flex アイテムに width プロパティで明示的に指定された幅などのうち、最も小さいものになる (flex アイテムの幅がそれ以上縮むことはない) そうです。

ここで「内容の最小幅」を算出するときには word-wrap: break-word の影響を考慮できません (break-word は行ボックスの幅からあふれる単語に影響を与えるが、最小幅を算出しようという段階では行ボックスの幅も定まっていない)。なので、widthmin-width も明示的に指定していない flex アイテムの内容に長い英単語があると、その単語の幅まで flex アイテムの幅が拡張されるということのようです (そして min-width が明示的に指定されていればそのようなことは起こらない)。仕様の注意書きには以下のように書かれています。

文書中の主要な領域に flex を使うなら、min-width: 12em のように明示的に最小幅を指定したほうがよい。そうでないと巨大な表や画像があったときに内容がはみ出して読みづらくなることがある。

Note - 4.5. Implied Minimum Size of Flex Items - CSS Flexible Box Layout Module Level 1 より抄訳

ではなぜこのような仕様になっているのでしょうか? 最初はパフォーマンス上の理由かと思いましたがそうではなく (flex アイテムの内容が膨大なときには、むしろパフォーマンスに悪影響を及ぼしうる)、製作者の意図しない奇妙な表示結果を避けるためだそうです。fantasai (flexbox 仕様編集者の一人) による暗黙的な最小サイズの解説に、どんな場面でどんな挙動を想定しているかの例も載っていました。主には「複数のナビゲーション項目を flex で並べたいが、画面幅が狭くて収まりきらない場合」の救済措置を意図しているようです。

奇妙な表示結果を避けるための仕様が、ある場面では逆に制作者の意図しない「奇妙な表示結果」を生み出しているというのが面白いですね。

補足: CSS 仕様の導入の経緯の調べ方

この記事を書くにあたって特定の CSS 仕様が導入された経緯について調べたのですが、その具体的な手順は以下の通りです。

  1. 何はともあれまずは最新の仕様草案を確認する。
  2. flexbox 仕様草案を斜め読みしていく。
    • 4.5. Implied Minimum Size of Flex Items」で min-widthmin-height プロパティを再定義しているのを見つける。
    • 9. Flex Layout Algorithm」もざっと追おうとするが、分量も多く複雑なので断念。
    • 大元の記事に関する仕様草案の記述個所はわかったが、なぜそのような仕様になっているのかはわからない。
  3. その仕様がいつ導入されたのかを確認する。
  4. メーリングリストでの議論を追う。
    • 仕様草案の Status of this document から、W3C CSS メーリングリストのアーカイブページに移動。
      • 2012 年 3月、4 月、5 月のメール一覧ページ (by thread) を見る。
    • メール一覧ページを「css3-flexbox」でページ内検索し、関連しそうなスレッドがないか探すも見つからない
  5. 検索する。
  6. ミーティングでの議論を追う。
    • 仕様の方針決定は CSS ワーキンググループ (CSS WG) のミーティングでなされることも多いので、「CSS WG MTG」でググるもミーティング一覧が出てこない。
    • 「CSS WG F2F」(F2F は Face-to-Face の略、実際に顔を突き合わせてのミーティング) でググったらミーティング一覧ページが出てきた。
    • 時期的に近そうな 2012 年 5 月ハンブルグ F2F の議事録 (Part I) を見たところ、議題「Flexbox: Flex Property and Flex Sizing」の中に「Next Issue: Implied minimum size of flexbox items」という項目があった。
      • ここで flex アイテムの最小幅の問題について取り上げられている。

IE で a 要素を使って相対 URL からスキームを得る2014年11月09日 20時22分

いくつかのブラウザではURLがhttpの相対リンクであってもelm.protocolが「:」や空文字になったりする

JavaScriptでリンク先URLがhttp/httpsか確認する方法 - 葉っぱ日記

この「いくつかのブラウザ」とは IE のことを指していると思われますが、href プロパティに絶対 URL を設定しなおすことで、URL のスキーム部分を取得できるようになります。

// http://www.example.org/ 上で実行しているものとする。
var elm = document.createElement('a');
elm.href = '/foo?bar#baz';

// IE 6 / 7 で絶対 URL を設定。
// elm.href = elm.cloneNode(false).href でもよい。
elm.href = elm.getAttribute('href', 4);

// IE (少なくとも 8 ~ 11) で絶対 URL を設定。
elm.href += '';

elm.protocol // => "http:"
elm.hostname // => "www.example.org"
elm.href     // => "http://www.example.org/foo?bar#baz"

しかし IE 6 / 7 の、getAttribute メソッドの第 2 引数に値 4 を渡すことで絶対 URL の値が返るという挙動は、いつ実装されいつ文書化されたのでしょうか?

modern.IE で配布されている IE 6 SP 3 検証環境では確かに動作するのですが、「IE の getAttribute / setAttribute」を書いた時点 (2005 年 10 月) では文書化されていなかった気がします。文書化されていたのなら、「IE 6,7 で相対URL -> 絶対 URL の変換 - #生存戦略 、それは - subtech」にまとめられたような cloneNode メソッドを使った手法を考えることもなかったでしょうから。

なお、「続・IEでのa要素の各属性について - 文殊堂」で言及されていますが、IE 6 / 7 では iframe 要素内の文書で上述の相対 URL 解決手法を用いると、(a 要素を文書木に挿入しない限り) 解決結果のホスト部分が親文書のものになってしまうようです。(ホスト部分が親文書のものになるという現象自体は IE 11 でも発生します。)

長い英単語を途中で折り返したいときの CSS の指定方法2013年06月18日 09時32分

ヨーロッパ系の言語では基本的に単語の途中に折り返しを入れません。しかし、幅の狭い領域に長い英単語を記述するときや、笑いを表す「www…www」のように欧文文字を表現に組み込むときなど、欧文文字同士の合間で折り返したいと思うかもしれません。そのような折り返しの制御を CSS で行うにはどうすればよいのでしょうか。

  1. 2013 年 6 月時点の結論
  2. word-wrap: break-word を使うとどうなるのか
  3. word-break: break-all を使うとどうなるのか
  4. word-wrap: break-wordword-break: break-all を両方使うとどうなるのか
  5. なぜ word-break: break-all ではなく word-wrap: break-word を勧めるのか
  6. どこに word-wrap: break-word を指定するのか
  7. position: aboslutedisplay: inline-block との組み合わせ
  8. display: table-cell との組み合わせ
  9. display: flex との組み合わせ
  10. white-space: prewhite-space: nowrap との組み合わせ
  11. word-wrap というプロパティ名
  12. 参考文献

2013 年 6 月時点の結論

  • word-wrap: break-word を使ってください。
  • word-break: break-all使わないでください
  • display: table-celldisplay: inline-block と組み合わせるときは、明示的な最大幅の指定が必要かもしれません。

word-wrap: break-word を使うとどうなるのか

単語 (欧文文字の連続) の途中で折り返さないと行ボックスの幅からあふれてしまうときのみ、その単語の途中で折り返します。単語の途中で折り返しが発生するのは、その単語の幅が行ボックスの幅より大きいときのみです。単語の幅が行ボックスの幅より小さければ、その単語全体が次の行に送られることはあっても、その単語の途中で折り返されることはありません。

[word-wrap: break-word を指定した図] word-wrap: break-word を指定した例。単語 supercalifragilisticexpialidocious の途中で折り返される。

word-break: break-all を使うとどうなるのか

任意の文字間での折り返しが許容され、言語に関わらず一切の禁則処理が無効になります。英単語の途中で行ボックスの幅からあふれそうになれば、あふれる直前で折り返されます。開き括弧の直後や閉じ括弧の直前、句読点の直前でも折り返されます。

[word-break: break-all を指定した図] word-break: break-all を指定した例。単語 such 及び supercalifragilisticexpialidocious の途中で折り返される。

word-wrap: break-wordword-break: break-all を両方使うとどうなるのか

word-break: break-all を使った時点でどの文字の間でも折り返しが起こりうるので、word-wrap: break-word による折り返し発生条件に到達しません。つまり、両方指定するのは word-break: break-all だけの指定と実質変わりません。

なぜ word-break: break-all ではなく word-wrap: break-word を勧めるのか

禁則処理をできるだけ活用し、また単語途中での折り返しを可能な限り避けるためです。ヨーロッパ系の言語で単語途中での折り返しがあると、ひとつの単語がふたつの単語のように見えてしまいます。日本語でも句読点が行頭に来ていれば違和感を持つ人が多いでしょう。

どこに word-wrap: break-word を指定するのか

word-wrap プロパティも word-break プロパティもその値は継承します。言い換えれば、その効果は子孫要素にも及びます。ですから、これらのプロパティは (HTML 文書であれば) body 要素か html 要素に指定しておけば十分でしょう。

position: aboslutedisplay: inline-block との組み合わせ

ときとして長い単語が折り返されず、word-wrap: break-word が効いていないように思えるかもしれません。その単語の祖先要素に position: absolutefloat: leftfloat: rightdisplay: inline-block が指定されていると、このような状況が起こりえます。

これらのプロパティ・値を指定された要素 (で width プロパティの計算値が auto のとき) は、その内容の幅によって自身の幅を決めるのであり、自身の幅を先に決めて内容の幅をそれに合わせるのではありません。このとき、その要素の幅は shrink-to-fit width (内容に合うように縮んだ幅) であるといいます。shrink-to-fit な幅を算出するときに word-wrap プロパティの影響は考慮されないので、単語途中での折り返しは発生しません。

(「考慮されない」といいましたが、内容の幅を決めようというときには行ボックスの幅も定まっていないので、「折り返さないと行ボックスの幅からあふれてしまう」という判断ができません。「word-wrap: break-word の影響を考慮しようにも考慮できない」というのが実際のところでしょう。)

こうした要素に対しては、width プロパティに auto 以外の値を指定することで shrink-to-fit な幅ではなくなります。あるいは、max-width プロパティを指定するのもひとつの手です。いずれにしても行ボックスの最大の幅が定まり、単語の長さがその幅からあふれるときは、その単語の途中で折り返されるようになります。

display: table-cell との組み合わせ

display: table-cell を指定した要素 (セル) も shrink-to-fit な幅の要素と同様、内容の幅によって自身の幅が決まります。しかし、こちらは width プロパティを指定しても単語の途中での折り返されるようになるとは限りません。CSS 2.1 の自動テーブルレイアウトアルゴリズムにおいて、セルの width プロパティの値が最小セル幅として扱われるからです。

(ここで「CSS 2.1 の自動テーブルレイアウトアルゴリズム」と呼んでいるのは CSS 2.1 仕様で定義されているものですが、ブラウザにそのアルゴリズムの利用が強制されているわけではありません。実際に用いられるテーブルレイアウトアルゴリズムはブラウザごとに異なりえます。)

セル内でも word-wrap: break-word による単語途中での折り返しを実現させるためには、セルに max-width プロパティを指定するか (ただし、この方法は IE 8 で機能しないことがあるようです)、セルの子孫要素 (であり、かつ単語の祖先要素でもあるもの) に width プロパティを指定して幅を明示する必要があります。

display: flex との組み合わせ

flexbox レイアウトとの組み合わせでも折り返しが効かないように思えることがあるそうです。

white-space: prewhite-space: nowrap との組み合わせ

IE 8 以降では、word-wrap: break-wordwhite-space: pre の効果が重なると、なぜか (まるで word-break: break-all を指定したかのように) 任意の文字間で折り返しが発生しうるようです。どこでも折り返されるようになるのは white-space: nowrap と組み合わせたときも同じで、こちらは nowrap といっているのに折り返しが発生することになります。(white-space: pre-wrapwhite-space: pre-line のときは問題ありません。)

white-space: nowrap の使い方として、text-overflow: ellipsis を組み合わせ、行ボックスからはみ出した文字列を省略表示にすることがあります。

h1 {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

しかし、IE 8 以降 (少なくとも IE 10 まで) では、祖先要素に word-wrap: break-word が指定されているとこの省略表示が効かず、内容がひとつの行ボックスに収まりきらなければ複数行で表示されます。white-space プロパティに値 pre または nowrap を指定するときは、word-wrap プロパティの値を初期値に戻しておいたほうがいいでしょう。

h1 {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  word-wrap: normal;
}

word-wrap というプロパティ名

この記事の執筆時点の CSS3 Text 草案では、word-wrap プロパティは overflow-wrap プロパティに改称しています。とはいうものの、互換性のため word-wrap というプロパティ名でも受け付けることになっています。現状のブラウザ実装状況を鑑みるに、word-wrap という名前を使うか、word-wrapoverflow-wrap を併記するかがよいと思います。

参考文献