HTMLとWAI-ARIAについてのまとめと気を付けるポイントメモ
WAI-ARIAについては何となく存在を知っていましたが、その程度の知識しかありませんでした。もう少しきちんと知識を整理して対応していこうと思い、個人的な対応方針を決定するまでの情報整理や思考した軌跡と結論を備忘メモとして残しておきます。
この記事に書かれている内容は個人の解釈・主観が多分に含まれていることに加えて情報の行間等も全てを記せていません。情報を整理している中で、私が認識したためその時に気を付ければいいか、と思い記載していない内容等もあります。解釈が誤っている可能性もあるため、全体像をある程度把握するための参考程度にすることをおすすめします。
WAI-ARIAについて
概要
HTML文書等で著者の意図する以下のような内容を論理的に解釈可能とするための情報を付与した文書。意図を論理的に解釈可能とすることでスクリーンリーダー等の他ソフトウェアが文書をより適切に取り扱うことが可能になる。
- 意味的な文書構造
- 文章の構成
- 対話的文脈の操作性
- コンテンツの動的な状態
これを実現するためWAI-ARIA RoleやWAI-ARIA States and Propertiesといった仕様に加えて、HTML文書等のマークアップ定義に高い親和性を持つための追加的な仕様が設けられた。具体的には特別な情報を付与しない場合でも特定のHTMLタグ等の要素には特定のRoleが内包されていると見なしたり、要素の属性として追加的に情報を付与可能であることなど。仕様では適切な文書要素を使用することで意図を論理的に解釈可能とすべきで追加的な情報付与はしないことが望ましく、必要になった場合にのみ追加的に情報を付与するという方針となっている。これは裏を返せば、WAI-ARIAを用いてアクセシビリティ対応をするためには各要素が標準で何を意味するのかを網羅的に把握し、文書著者が情報を追加付与する条件を理解しなければならないということになる。
対応は必要か
法改正によりコンプライアンス的に負担が重すぎない範囲で対応が必要となった[1]ため、プロジェクトにより対応内容の決定が必要。「他のソフトウェア」は典型的にはOS,ブラウザ,スクリーンリーダーが挙げられるがそれ以外に無いと断定することはできないし、ターゲットユーザーとそれに関する「他のソフトウェア」は無数にあるためどこまでをスコープに含めるのかを先に検討する必要がある。
前提
この記事について
- WAI-ARIAを用いてアクセシビリティ対応を行うことを目的とする
- WAI-ARIA適用先文書はHTML文書と定義する
- WAI-ARIA1.3のドラフト文書とARIA in HTMLのドラフト文書がベース
- 日本語版MDNは内容が異なる(誤っている?)場合がある (英語版は一致していたりする)
- 例: MDN ja / ARIA in HTML
- ARIA in HTMLとこの記事の内容が異なる場合がある
- ARIA in HTMLの記載に違和感があった場合のみ個別に検証して内容を置換
- 検証はChromeブラウザで実施
- 例)
mark
タグやdt
タグの暗黙のARIAロール
- ARIA in HTMLの記載に違和感があった場合のみ個別に検証して内容を置換
- 日本語版MDNは内容が異なる(誤っている?)場合がある (英語版は一致していたりする)
- この辺やこの辺程度の知識がある前提
- Accessible Nameについても知っている前提
- Deprecatedとなっている項目には対応していない
- "WAI-ARIA Role"は「ロール」、"WAI-ARIA States and Properties"はまとめて「プロパティ」と表記する
- HTMLタグのことを単にタグと表記する場合がある
- "presentation"ロールは取り扱わず"none"ロールのみ取り扱う
- "img"ロールは"image"ロールと表記する
- "暗黙のARIAロール"は暗黙ロールと表記する
- 文書構造における構造概要を把握するための指針となる区域をランドマーク(Landmark)と表記する
-
h1
-h6
タグはh0
と表記する -
input
タグのようなユーザーが操作可能な要素を対話的要素と表記する - 空要素は
<tag />
のように表記する
目標
WAI-ARIAを用いて最小労力である程度のアクセシビリティを担保したページを作成できるようになる。
- できる限り覚えることを減らし認知負荷を軽減する
- 特定用途は認識だけして覚えず、その時に詳細を調べることにする
- 何が特定用途かは主観によって決めた
- 特定用途の内容の全てを記載しているわけではない
- できるだけ正確な理解と使用を心がけつつ、問題なさそうな部分は極力省く
基本方針
- 可能な限り標準のHTMLで表現する
- 対話的要素はHTML標準の要素を用いる
- 要素の親子関係表現はHTML階層を用いる
- 要素を列挙する場合は列挙と内容で構造を分離する
- 適切なHTMLタグを用いれば考慮しなくてよい制約等は考慮しない
- 状況に応じて適切なHTMLタグを使用するようにする
- 各HTMLタグの用途を自ら制限し、タグとロールの紐付けを強くする
- 情報を付与する条件を簡略化して認知負荷を下げる
- 紐付けによりロールとタグの各制約を整合性を保ちつつ統合・簡略化するため
- HTMLタグに付与された暗黙ロールを尊重する
- 言い換えると特に必要でない限りHTMLタグに
role
属性を使用しない
- 言い換えると特に必要でない限りHTMLタグに
- 特定タグにわざわざ
role="none"
を付与して使用せず素のdiv
,span
を使用する- どうしても特定タグを使用する理由がある場合はこの限りでない
- 以下例等は特定用途と見なして考慮外とする
- 動的テーブル,grid系,tree系ロール
- live-regionの詳細設定
暗黙ロールの尊重について
以下のような例の場合でも暗黙ロールを尊重する。
- "generic"ロールは使用すべきでないとされている
Authors SHOULD NOT use this role in content.
(generic role) - しかし
body
タグやdiv
タグ等暗黙ロールに"generic"が割り当てられている - わざわざ
role="none"
とする方が冗長な情報付与となるため、指定しないことにする- なぜ"No correspoinding role"にしなかったのかは謎
タグとロール紐付け
ロール間の関係性
ロールにはHTMLタグに指定できない抽象ロール(Abstract Role)とそれ以外のロール(この記事では以下 具象ロール)がある。抽象ロール間の対応と具象ロールの関係性の表は以下。複数の具象ロールから多重継承している具象ロールはどちらか片方の親からしか派生していないような表になっている(省いている)。
- Abstract Roleは
(role)
で記載 - 1が上位で4が下位の抽象層
- 上位抽象層に記載がない場合はその行より上の行の抽象ロールと同じ
- 例) "(range)"抽象ロールは"(structure)"抽象ロールから派生
- 下位抽象層に記載がない場合はその層に抽象ロールが無い
- 例) "generic"ロールは"(structure)"抽象ロールから派生
- 上位抽象層に記載がない場合はその行より上の行の抽象ロールと同じ
- 具象ロールから具象ロールへの継承は親ロールの下の行に
>
から始まるように記載- 例) "article"ロールは"document"ロールから派生
- 例) "comment"ロールは"article"ロールから派生
Table of role inheritance
1 | 2 | 3 | 4 | 具象ロール |
---|---|---|---|---|
(roletype) | (structure) | document | ||
> article | ||||
>> comment | ||||
generic | ||||
none | ||||
rowgroup | ||||
separator | ||||
application | ||||
(range) | meter | |||
progressbar | ||||
scrollbar | ||||
(slider) | ||||
(spinbutton) | ||||
(sectionhead) | columnheader | |||
heading | ||||
rowheader | ||||
tab | ||||
(section) | alert | |||
> alertdialog | ||||
blockquote | ||||
caption | ||||
cell | ||||
code | ||||
definition | ||||
deletion | ||||
emphasis | ||||
figure | ||||
group | ||||
> toolbar | ||||
> (select) | ||||
image | ||||
insertion | ||||
list | ||||
> feed | ||||
listitem | ||||
> treeitem | ||||
log | ||||
mark | ||||
marquee | ||||
math | ||||
note | ||||
paragraph | ||||
status | ||||
> timer | ||||
strong | ||||
subscript | ||||
suggestion | ||||
superscript | ||||
table | ||||
tabpanel | ||||
term | ||||
time | ||||
tooltip | ||||
(landmark) | banner | |||
complementary | ||||
contentinfo | ||||
form | ||||
main | ||||
navigation | ||||
region | ||||
search | ||||
(widget) | gridcell | |||
row | ||||
(progressbar) | ||||
(scrollbar) | ||||
(separator) | ||||
(tab) | ||||
(input) | checkbox | |||
> switch | ||||
combobox | ||||
option | ||||
radio | ||||
slider | ||||
spinbutton | ||||
textbox | ||||
> searchbox | ||||
(command) | button | |||
link | ||||
menuitem | ||||
> menuitemcheckbox | ||||
> menuitemradio | ||||
(composite) | grid | |||
> treegrid | ||||
tablist | ||||
(spinbutton) | ||||
(select) | listbox | |||
menu | ||||
> menubar | ||||
radiogroup | ||||
tree | ||||
(window) | dialog |
ロール間の親子制約
-
-
は特に制約がない事を表す -
,
は "または" の意 -
role1/role2
のような表記は以下を表す-
role1
ロールの直下にrole2
ロールがある
-
ロール | 親 | 子 |
---|---|---|
table | caption, row, rowgroup/row | - |
grid | caption, row, rowgroup/row | - |
treegrid | caption, row, rowgroup/row | - |
caption | - | figure, group, radiogroup, table, grid, treegrid |
rowgroup | row | table, grid, treegrid |
row | - | table, grid, treegrid, rowgroup |
columnheader | - | row |
rowheader | - | row |
cell | - | row |
gridcell | - | row |
menu | menuitem, group/menuitem, separator | - |
menubar | menuitem, group/menuitem, separator | - |
menuitem | - | menu, menubar, menu/group, menubar/group |
list | listitem | - |
listitem | - | list |
tree | treeitem, group/treeitem | - |
treeitem | - | tree, treeitem/group |
tablist | tab | - |
tab | - | tablist |
tabpanel | - | - |
suggestion | insertion, deletion | - |
insertion | - | - |
deletion | - | - |
feed | article | - |
article | - | - |
listbox | option, group/option | - |
option | - | listbox, listbox/group |
似たようなロールの違い
- グルーピング
- region: その他のランドマークとなる区域
- group: ランドマークにならない対話的要素のグルーピング
- 追加的な情報
- note: 著者の追加的・補助的な内容
- comment: 閲覧者の内容・コメントへの反応
- suggestion: 閲覧者の内容の変更提案1件
- 操作バー
- menubar: デスクトップUIで見られるようなメニューバー
- toolbar: 機能ボタン等の集まりをコンパクトな形式で表現したもの
- 選択式入力
- combobox: 入力+選択可能なフォームコントロール
- listbox: 選択肢から1つ以上の項目を選択できるコントロール
- リスト
- menu: コンテキストメニュー等のアクションリスト
- list: listitem要素を含む区域
- 情報表示
- log: 情報蓄積型の静的区域で情報が追加されていくチャット,エラーログ等
- marquee: 情報移動型の動的区域で情報が上書きされていく株価スクロール表示等
- 重要度の高い通知
- alert: ユーザーの操作を必要としない通知区域
- alertdialog: ユーザーの操作を必要とする通知
- 表形式
- table: 対話的な操作が不可能な表形式の表示
- grid: 対話的な操作が可能な表形式の表示
使用しないロール
以下の具象ロールは一部を除きこの記事では取り扱わない。
- application
-
可能な限り標準のHTMLで表現することが基本方針のため
-
ロール定義
A structure containing one or more focusable elements requiring user input, such as keyboard or gesture events, that do not follow a standard interaction pattern supported by a widget role.
(application role) -
MDNの記載
このロールは、とても動的でデスクトップ的なウェブアプリケーションを定義するためにのみ使用するべきです。
このモードでは、ウェブ作成者は、キーボード入力、フォーカス管理、その他のインタラクションを全て処理する責任があり、支援技術が最終的に何らかの処理を行うとは想定できません。
(ARIA: application ロール)
-
- scrollbar
- ブラウザのスクロールバーを絶対に使用できない状況が通常想定できないため
- MDNの記載
It is always best to use native scroll bars.
(ARIA: scrollbar role)
- menuitemcheckbox
- 列挙と内容で構造を分離すれば不要なロールと思われるため
- menuitemradio
- 列挙と内容で構造を分離すれば不要なロールと思われるため
タグの基本情報
- Interface列の表記
-
HTMLElement
は-
と表記 - 先頭の
HTML
と末尾のElement
は省略
-
- 空列が
o
となっているタグは空要素 - カテゴリ列は代表的なカテゴリのみ記載
HTML tag list
タグ | Interface | 空 | 親 | 子 | カテゴリ |
---|---|---|---|---|---|
html | Html | - | head, body | - | |
head | Head | html | title, Metadata | - | |
base | Base | o | head | - | Metadata |
link | Link | o | Metadata | - | Metadata |
meta | Meta | o | head | - | Metadata |
style | Style | Metadata | "text/css" | Metadata | |
title | Title | head | "text" | Metadata | |
body | Body | html | Flow | - | |
address | - | Flow | Flow | Flow, Palpable | |
article | - | Flow | Flow | Flow, Sectioning, Palpable | |
aside | - | Flow | Flow | Flow, Sectioning, Palpable | |
footer | - | Flow | Flow | Flow, Palpable | |
header | - | Flow | Flow | Flow, Palpable | |
h0 | Heading | Flow | Phrasing | Flow, Heading, Palpable | |
hgroup | - | Flow | h0, p | Flow, Heading, Palpable | |
main | - | Flow | Flow | Flow, Palpable | |
nav | - | Flow | Flow | Flow, Sectioning, Palpable | |
section | - | Flow | Flow | Flow, Sectioning, Palpable | |
search | - | Flow | Flow | Flow, Palpable | |
blockquote | Quote | Flow | Flow | Flow, Sectioning root, Palpable | |
dd | - | dl | Flow | - | |
div | Div | Flow | Flow | Flow, Palpable | |
dl | DList | Flow | dt, dd, div | Flow | |
dt | - | dl | Flow | - | |
figcaption | - | figure | Flow | - | |
figure | - | Flow | figcaption, Flow | Flow, Palpable | |
hr | HR | o | Flow | - | Flow |
li | LI | ul, ol, menu | Flow | - | |
menu | Menu | Flow | li, script, template | Flow, Palpable | |
ol | OList | Flow | li, script, template | Flow, Palpable | |
ul | UList | Flow | li, script, template | Flow, Palpable | |
p | Paragraph | Flow | Phrasing | Flow, Palpable | |
pre | Pre | Flow | Phrasing | Flow, Palpable | |
a | Anchor | Flow | Transparent | Flow, Phrasing, Interactive, Palpable | |
abbr | - | Phrasing | Phrasing | Flow, Phrasing, Palpable | |
b | - | Phrasing | Phrasing | Flow, Phrasing, Palpable | |
bdi | - | Phrasing | Phrasing | Flow, Phrasing, Palpable | |
bdo | - | Phrasing | Phrasing | Flow, Phrasing, Palpable | |
br | BR | o | Phrasing | - | Flow, Phrasing |
cite | - | Phrasing | Phrasing | Flow, Phrasing, Palpable | |
code | - | Phrasing | Phrasing | Flow, Phrasing, Palpable | |
data | Data | Phrasing | Phrasing | Flow, Phrasing, Palpable | |
dfn | - | Phrasing | Phrasing | Flow, Phrasing, Palpable | |
em | - | Phrasing | Phrasing | Flow, Phrasing, Palpable | |
i | - | Phrasing | Phrasing | Flow, Phrasing, Palpable | |
kbd | - | Phrasing | Phrasing | Flow, Phrasing, Palpable | |
mark | - | Phrasing | Phrasing | Flow, Phrasing, Palpable | |
q | Quote | Phrasing | Phrasing | Flow, Phrasing, Palpable | |
rp | - | ruby | "text" | - | |
rt | - | ruby | Phrasing | - | |
ruby | - | Phrasing | Phrasing | Flow, Phrasing, Palpable | |
s | - | Phrasing | Phrasing | Flow, Phrasing | |
samp | - | Phrasing | Phrasing | Flow, Phrasing, Palpable | |
small | - | Phrasing | Phrasing | Flow, Phrasing, Palpable | |
span | Span | Phrasing | Phrasing | Flow, Phrasing, Palpable | |
strong | - | Phrasing | Phrasing | Flow, Phrasing, Palpable | |
sub | - | Phrasing | Phrasing | Flow, Phrasing, Palpable | |
sup | - | Phrasing | Phrasing | Flow, Phrasing, Palpable | |
time | Time | Phrasing | Phrasing | Flow, Phrasing, Palpable | |
u | - | Phrasing | Phrasing | Flow, Phrasing, Palpable | |
var | - | Phrasing | Phrasing | Flow, Phrasing, Palpable | |
wbr | - | o | Phrasing | - | Flow, Phrasing |
area | Area | o | map, Phrasing | - | Flow, Phrasing |
audio | Audio | Embedded | source, track, Transparent | Flow, Phrasing, Embedded(, Interactive, Palpable) | |
img | Image | o | Embedded | - | Flow, Phrasing, Embedded, Palpable |
map | Map | Phrasing | Transparent | Flow, Phrasing, Palpable | |
track | Track | o | audio, video | - | - |
video | Video | Embedded | source, track, Transparent | Flow, Phrasing, Embedded(, Interactive, Palpable) | |
embed | Embed | o | Embedded | - | Flow, Phrasing, Embedded, Interactive, Palpable |
fencedframe | FencedFrame | Embedded | - | Flow, Phrasing, Embedded, Interactive, Palpable | |
iframe | IFrame | Embedded | - | Flow, Phrasing, Embedded, Interactive, Palpable | |
object | Object | Embedded | Transparent | Flow, Phrasing, Embedded, Palpable | |
picture | Picture | Embedded | source, img | Flow, Phrasing, Embedded | |
source | Source | o | audio, video, picture | - | - |
svg | SVGElement | - | - | - | |
math | - | - | - | ||
canvas | Canvas | Phrasing | Transparent | Flow, Phrasing, Embedded, Palpable | |
noscript | - | head, Flow | link, style, meta | Metadata, Flow, Phrasing | |
script | Script | Metadata, Phrasing | "text/javascript" | Metadata, Flow, Phrasing | |
del | Mod | Phrasing | Transparent | Flow, Phrasing, Palpable | |
ins | Mod | Phrasing | Transparent | Flow, Phrasing, Palpable | |
caption | TableCaption | table | Flow | - | |
col | TableCol | o | colgroup | - | - |
colgroup | TableCol | table | col | - | |
table | Table | Flow | caption, colgroup, thead, tbody, tr, tfoot | Flow | |
tbody | TableSection | table | tr | - | |
td | TableCell | tr | Flow | Sectioning root | |
tfoot | TableSection | table | tr | - | |
th | TableCell | tr | Flow | - | |
thead | TableSection | table | tr | - | |
tr | TableRow | table, thead, tbody, tfoot | td, th | - | |
details | Details | Flow | summary, Flow | Flow, Sectioning root, Interactive, Palpable | |
dialog | Dialog | Flow | Flow | Flow, Sectioning root | |
summary | - | details | Phrasing, Heading | - | |
slot | Slot | Phrasing | Transparent | Flow, Phrasing | |
template | Template | Metadata, Phrasing, Script-supporting | ANY | Metadata, Flow, Phrasing, Script-supporting | |
button | Button | Phrasing | Phrasing | Flow, Phrasing, Interactive, Form-assosciated, Palpable | |
datalist | DataList | Phrasing | option, Phrasing | Flow, Phrasing | |
fieldset | FieldSet | Flow | legend, Flow | Flow, Sectioning root, Form-assosciated, Palpable | |
form | Form | Flow | Flow | Flow, Palpable | |
label | Label | Phrasing | Phrasing | Flow, Phrasing, Interactive, Form-assosciated, Palpable | |
legend | Legend | fieldset | Phrasing, Heading | - | |
meter | Meter | Phrasing | Phrasing | Flow, Phrasing, Palpable | |
optgroup | OptGroup | select | option | - | |
option | Option | select, optgroup, datalist | "text" | - | |
output | Output | Phrasing | Phrasing | Flow, Phrasing, Interactive, Form-assosciated, Palpable | |
progress | Progress | Phrasing | Phrasing | Flow, Phrasing, Palpable | |
select | Select | Phrasing | option, optgroup, hr | Flow, Phrasing, Interactive, Form-assosciated, Palpable | |
textarea | TextArea | Phrasing | "text" | Flow, Phrasing, Interactive, Form-assosciated, Palpable | |
input | Input | o | Phrasing | - | Flow, Phrasing, Interactive, Form-assosciated, Palpable |
タグに設定されたロール
- 暗黙ロールの"No corresponding role"は"-"と表記
- 設定可能なロールが無い場合は"-"と表記
-
,
は "または" の意 - "*"等が付いている部分は別記条件の場合
-
type
属性が"xxx"
であるinput
タグをinput [xxx]
と表記
Role of implicit and available on HTML tag
タグ | 暗黙ロール | 設定可能ロール | 条件 |
---|---|---|---|
html | document | - | |
head | - | - | |
base | - | - | |
link | - | - | |
meta | - | - | |
style | - | - | |
title | - | - | |
body | generic | - | |
address | group | ANY | |
article | article | none, application, document, feed, main, region | |
aside | complementary | none, feed, note, region, search | |
footer | contentinfo (generic *) | none, group | * article, aside, main, nav, sectionの各要素、又はroleがarticle, complementary, main, navigation, regionの要素の子孫である場合 |
header | banner (generic *) | none, group | * article, aside, main, nav, sectionの各要素、又はroleがarticle, complementary, main, navigation, regionの要素の子孫である場合 |
h0 | heading | none, tab | |
hgroup | group | ANY | |
main | main | - | |
nav | navigation | none, menu, menubar, tablist | |
section | region (generic *) | none, alert, alertdialog, application, banner, complementary, contentinfo, dialog, document, feed, group, log, main, marquee, navigation, note, search, status, tabpanel | * accessible nameを持たない場合 |
search | search | none, form, group, region | |
blockquote | blockquote | ANY | |
dd | definition | - | |
div | generic | ANY (none *) | * dl要素の直下にある時 |
dl | - | none, group, list | |
dt | term | listitem | |
figcaption | - | none, group | |
figure | figure | - (ANY *) | * 子孫にfigcaption要素がない場合 |
hr | separator | none | |
li | listitem | none, menuitem, menuitemcheckbox, menuitemradio, option, radio, separator, tab, treeitem (- *) | * 親のroleがlistの場合 |
menu | list | none, group, listbox, menu, menubar, radiogroup, tablist, toolbar, tree | |
ol | list | none, group, listbox, menu, menubar, radiogroup, tablist, toolbar, tree | |
ul | list | none, group, listbox, menu, menubar, radiogroup, tablist, toolbar, tree | |
p | paragraph | ANY | |
pre | generic | ANY | |
a | link (generic *) | button, checkbox, menuitem, menuitemcheckbox, menuitemradio, option, radio, switch, tab, treeitem (ANY *) | * href属性がない場合 |
abbr | - | ANY | |
b | generic | ANY | |
bdi | generic | ANY | |
bdo | generic | ANY | |
br | - | none | |
cite | - | ANY | |
code | code | ANY | |
data | generic | ANY | |
dfn | term | ANY | |
em | emphasis | ANY | |
i | generic | ANY | |
kbd | - | ANY | |
mark | mark | ANY | |
q | generic | ANY | |
rp | - | ANY | |
rt | - | ANY | |
ruby | - | ANY | |
s | deletion | ANY | |
samp | generic | ANY | |
small | generic | ANY | |
span | generic | ANY | |
strong | strong | ANY | |
sub | subscript | ANY | |
sup | superscript | ANY | |
time | time | ANY | |
u | generic | ANY | |
var | - | ANY | |
wbr | - | none | |
area | link (generic *) | - (button, link *) | * href属性がない場合 |
audio | - | application | |
img | image (none *1) | button, checkbox, link, math, menuitem, menuitemcheckbox, menuitemradio, meter, option, progressbar, radio, scrollbar, separator, slider, switch, tab, treeitem (- *1, *2) | *1 空のalt属性がある場合; *2 alt属性がない場合 |
map | - | - | |
track | - | - | |
video | - | application | |
embed | - | none, application, document, image | |
fencedframe | - | none, application, document, image | |
iframe | - | none, application, document, image | |
object | - | none, application, document, image | |
picture | - | - | |
source | - | - | |
svg | graphics-document | ANY | |
math | math | - | |
canvas | - | ANY | |
noscript | - | - | |
script | - | - | |
del | deletion | ANY | |
ins | insertion | ANY | |
caption | caption | - | |
col | - | - | |
colgroup | - | - | |
table | table | ANY | |
tbody | rowgroup | ANY | |
td | cell (gridcell *1; - *2) | - (ANY *2) | *1 親のtableのroleがgrid又はtreegridである場合; *2 親のtableのroleがtable, grid, treegridのいずれでもない場合 |
tfoot | rowgroup | ANY | |
th | columnheader, rowheader, cell (columnheader, rowheader, gridcell *1; - *2) | - (ANY *2) | *1 親のtableのroleがgrid又はtreegridである場合; *2 親のtableのroleがtable, grid, treegridのいずれでもない場合 |
thead | rowgroup | ANY | |
tr | row | - (ANY *) | * 親のtableのroleがtable, grid, treegridのいずれでもない場合 |
details | group | - | |
dialog | dialog | alertdialog | |
summary | - | - | |
slot | - | - | |
template | - | - | |
button | button | checkbox, combobox, gridcell, link, menuitem, menuitemcheckbox, menuitemradio, option, radio, separator, slider, switch, tab, treeitem | |
datalist | listbox | - | |
fieldset | group | none, radiogroup | |
form | form | none, search | |
label | - | - | |
legend | - | - | |
meter | meter | - | |
optgroup | group | - | |
option | option | - | |
output | status | ANY | |
progress | progressbar | - | |
select | combobox (listbox *) | menu (- *) | * multiple属性がある又は1よりも大きいsize属性がある場合 |
textarea | textbox | - | |
input [button] | button | checkbox, combobox, gridcell, link, menuitem, menuitemcheckbox, menuitemradio, option, radio, separator, slider, switch, tab, treeitem | |
input [checkbox] | checkbox | menuitemcheckbox, option, switch (button *) | * aria-pressed属性を使用する場合 |
input [color] | - | - | |
input [date] | - | - | |
input [datetime-local] | - | - | |
input [email] | textbox (combobox *) | - | * list属性がある場合 |
input [file] | - | - | |
input [hidden] | - | - | |
input [image] | button | - | |
input [month] | - | - | |
input [number] | spinbutton | - | |
input [password] | - | - | |
input [radio] | radio | menuitemradio | |
input [range] | slider | - | |
input [reset] | button | - | |
input [search] | searchbox (combobox *) | - | * list属性がある場合 |
input [submit] | button | - | |
input [tel] | textbox (combobox *) | - | * list属性がある場合 |
input [text] | textbox (combobox *) | - | * list属性がある場合 |
input [time] | - | - | |
input [url] | textbox (combobox *) | - | * list属性がある場合 |
input [week] | - | - |
select
タグがcombobox
ロールである理由
込み入った部分なので複数のAIの回答を比較・参考にした。(DeepSeekは簡潔な回答だったため割愛) 結論はブラウザがうまく対応しているため問題ない。逆に言うと標準のselect
タグを使用しない場合は細かな部分に配慮しながら適切に処置する必要があることになる。
- 質問
通常、
select
タグはoption
タグと共に用いてセレクトボックスを表現すると思います。wai-ariaでは、select
タグは属性に何も指定しない場合、comboboxロールになります。option
タグは何も指定しない場合optionロールになりますが、optionロールの定義内に記載のあるRequired Accessibility Parent Rolesは、listbox又はgroup with parent listboxとなっています。これは実体と矛盾しているように思えるのですが、どのように理解すべきでしょうか?
Claude 3.5 Sonnet
ご指摘の点について、WAI-ARIAとHTML標準の関係性から説明させていただきます。
実は、HTMLの<select>
要素は2つの異なるARIAセマンティクスを持っています:
- 単一選択の場合(multiple属性なし):
- デフォルトでは
role="combobox"
とrole="listbox"
の両方の特性を持ちます - これは
<select>
が閉じた状態ではcomboboxとして、開いた状態ではlistboxとして振る舞うためです
- 複数選択の場合(multiple属性あり):
- デフォルトで
role="listbox"
となります
つまり、単一選択の<select>
要素は以下のような二重の役割を持っています:
<!-- 以下のような <select> は -->
<select>
<option>選択肢1</option>
<option>選択肢2</option>
</select>
<!-- 内部的には以下のような構造として解釈されます -->
<div role="combobox">
<div role="listbox">
<div role="option">選択肢1</div>
<div role="option">選択肢2</div>
</div>
</div>
したがって、<option>
要素のRequired Accessibility Parent Rolesがlistboxとなっているのは、この内部構造を反映したものです。見た目上は矛盾しているように見えますが、実際には:
-
<select>
はcomboboxとしての外部インターフェース - その内部にlistboxとしての選択肢コンテナ
- さらにその中に個々のoption
という階層構造になっているということです。
この設計により、スクリーンリーダーなどの支援技術は:
- 閉じている状態ではcomboboxとして(「プルダウンメニューがあります」など)
- 開いている状態ではlistboxとして(「リストから選択してください」など)
適切に情報を提供することができます。
このように、一見矛盾しているように見える仕様も、実際のユーザーインタラクションとアクセシビリティの要件を満たすための設計的な配慮として理解することができます。
ChatGPT
WAI-ARIA の role="option"
の仕様を読むと、一見すると option
ロールの親要素は listbox
または group
(その親が listbox
である場合) でなければならないように思えます。しかし、HTML の select
タグとその option
タグの関係を考えると、矛盾があるように感じられるかもしれません。
1. WAI-ARIA の仕様と HTML の実装の関係
WAI-ARIA の仕様では、option
ロールの Required Accessibility Parent Roles に listbox
や group
(親が listbox
) が指定されています。これは、WAI-ARIA を手動で適用する場合のルールです。つまり、開発者が role="option"
を適用する場合、適切な親要素 (listbox
など) の下に配置しなければならないという意味になります。
一方、HTML の select
要素は、WAI-ARIA における combobox
として認識されることが多いですが、内部的にはユーザーエージェントが適切にアクセシビリティツリーを構築します。その際、option
要素の親として select
要素が直接来ることは問題になりません。
select
のデフォルトのアクセシビリティツリー
2. ブラウザの実装によっては、select
(特に size
属性なしの単純なドロップダウン) は、内部的に combobox
を持つ 独自のアクセシビリティ構造 を持ち、listbox
に相当する要素を作成して、その中に option
要素を配置する場合があります。そのため、開発者が明示的に WAI-ARIA を適用しなくても、適切な構造になることが多いです。
一方、size
属性が 2
以上の select
(<select size="2">
など) は、デフォルトで listbox
のように振る舞い、WAI-ARIA の role="listbox"
を明示的に指定しなくても、アクセシビリティツリー上は listbox
のように扱われることが一般的です。
3. 矛盾ではなく「ブラウザの適切な対応」
このように、HTML の select
要素は ブラウザが内部的に適切なアクセシビリティ構造を提供する ため、option
の親が明示的な listbox
でない場合でも、スクリーンリーダーなどは適切に解釈できます。
したがって、開発者が WAI-ARIA を手動で適用する場合 は、仕様に沿って listbox
の中に option
を配置するべきですが、ネイティブの select
を使う場合 は、ブラウザが適切に処理するため、矛盾のように見えても問題はないのです。
4. まとめ
-
option
の Required Parent Role にlistbox
があるのは WAI-ARIA を手動で適用する場合 のルール。 - ネイティブの
select
要素では、ブラウザが内部で適切なアクセシビリティツリーを作成するため、このルールを開発者が意識する必要はない。 -
select
のsize
属性が2
以上の場合、listbox
に近い動作をし、option
の親として適切な役割を果たす。
つまり、WAI-ARIA の仕様は「HTML の標準要素を置き換えるカスタム実装向けのガイドライン」として考えるのがよく、HTML の select
は適切に処理されるため、矛盾を感じる必要はないということです。
Gemini 2.0 Flash
おっしゃる通り、selectタグとoptionタグの関係性と、WAI-ARIAにおけるロールの定義の間には、一見すると矛盾があるように見えます。
WAI-ARIAにおけるselect要素の扱い
WAI-ARIAでは、select要素はデフォルトでcombobox
ロールを持つとされています。これは、select要素がユーザーの入力を受け付けるコンポーネントとして扱われるためです。一方、optionタグはデフォルトでoption
ロールを持ちますが、option
ロールの親ロールとして許可されているのはlistbox
またはgroup with parent listbox
のみです。
なぜこのような定義になっているのか?
この背景には、WAI-ARIAがWebアクセシビリティを向上させるために、セマンティクス(意味)とプレゼンテーション(見え方)を分離するという考え方があります。
- セマンティクス: select要素は、ユーザーに選択肢を提供し、その中から一つを選択させるという意味を持っています。
- プレゼンテーション: ブラウザは、この意味を理解し、select要素をドロップダウンリストとして表示します。
WAI-ARIAは、このプレゼンテーションをカスタマイズできるように、combobox
ロールを提供しています。例えば、JavaScriptなどを使って、select要素をautocomplete機能付きのテキストボックスとして表示したり、複数の選択肢をリスト表示したりすることができます。
矛盾の解消
では、なぜoption
ロールの親ロールがlistbox
に限定されているのでしょうか?これは、option
ロールがリストの中から選択される項目であるという意味を持つためです。select要素をカスタマイズしてlistbox
のような表示にした場合、その子要素はoption
ロールを持つことが適切となります。
つまり、WAI-ARIAのロールの定義は、select要素の意味と、その表示を柔軟に対応できるように設計されているのです。
まとめ
- select要素はデフォルトで
combobox
ロールを持ちますが、これはプレゼンテーションをカスタマイズするためのものです。 - optionタグはデフォルトで
option
ロールを持ち、その親ロールはlistbox
に限定されています。これは、option
ロールがリスト項目であることを意味するためです。 - WAI-ARIAのロールの定義は、セマンティクスとプレゼンテーションを分離し、柔軟なWebアクセシビリティを実現するためのものです。
ご不明な点がございましたら、お気軽にご質問ください。
紐付け
ロールとタグを紐付けてそれを制約とすることで覚える内容を減らす。また、ロールの内容とタグの意味付けを考慮した紐づけを行い覚えやすくする。
-
type
属性が"xxx"
であるinput
タグをinput [xxx]
と表記 -
scope
属性が"xxx"
であるth
タグをth [xxx]
と表記 - コンセプト列は公式のロールに書かれている以下項目のタグ
- Base Concept
- Related Concepts
- タグのロール列はそのロールに関連するタグ
- tag は暗黙ロールが設定されているタグ
- (tag) は設定可能なロールになっているタグ (暗黙ロールタグが存在しない)
- 主観設定列はいくつかの理由により紐付けた方がよいと思ったタグ
- メモ列に理由が書いてある
- これら3つの要素からタグ列のタグを決定している
- 基本的にコンセプト列,タグのロール列が尊重されている = 基本公式準拠
- タグ視点で説明すると以下のようになる
- 設定可能なロールがない場合 -> ロールのことは考えない
- 設定可能なロールがAnyの場合 -> 特別用途を指定されていないと見なす
- 暗黙ロールを尊重して通常指定しないと見なす (特別な事情がない限り指定しない)
- 暗黙ロールが"No correspoinding role"で、設定可能なロールがある場合 -> 通常指定しないと見なす
- 恣意的に暗黙ロールに設定していないと見なす (特別な事情がない限り指定しない)
Link of role and tag
ロール | タグ | コンセプト | タグのロール | 主観設定 | メモ |
---|---|---|---|---|---|
document | html | html | |||
article | article | article | article | ||
comment | div | - | div | ||
generic | * | div, span | * | * | * 特別な事情がない限り暗黙ロールのまま使用する |
none | * | * | * | * 文脈に応じて使用可能なタグで使用する | |
rowgroup | thead, tbody, tfoot | thead, tbody, tfoot | thead, tbody, tfoot | ||
separator | hr | hr | hr | ||
meter | meter | meter | meter | ||
progressbar | progress | progress | |||
columnheader | th [col] | th [col] | th [col] | ||
heading | h0 | h0 | h0 | ||
rowheader | th [row] | th [row] | th [row] | ||
tab | li | (h0, li, a, img, button, input [button]) | li | <li>以外は<li>の中に定義可能なため | |
alert | output | (section) | output | outputは多くのブラウザで"aria-live"領域として実装されているため | |
alertdialog | dialog | (dialog, section) | dialog | alertと違い対話型が想定されるため | |
blockquote | blockquote | blockquote | blockquote | ||
caption | caption | caption, figcaption, legend | caption | <figcaption>, <legend>はcaptionを選択不能 | |
cell | td | td | td, th | ||
code | code | code | code | ||
definition | dd, div, span | dd | dd, div, span | <div>, <span>は<dfn>に対応するため | |
deletion | s, del | s, del | s, del | ||
emphasis | em | em | em | ||
figure | figure | figure | figure | ||
group | hgroup, fieldset, optgroup, details, address, div | fieldset | hgroup, fieldset, optgroup, details, address | hgroup, fieldset, optgroup, details, address, div | <div>は汎用的なグルーピングのため |
toolbar | menu | (menu, ol, ul) | menu | 対話的要素が想定されるため | |
image | img | img | img | ||
insertion | ins | ins | ins | ||
list | ul, ol | ul, ol | ul, ol, menu | ||
feed | article | (article, aside, section) | article | feedの内容は<article>が想定され理解しやすいため | |
listitem | li | li | li | ||
treeitem | li | (li, a, img, button, input [button]) | li | <li>以外は<li>の中に定義可能なため | |
log | div | (section) | div | <section>の用途を限定するため | |
mark | mark | mark | mark | ||
marquee | div | (section) | div | <section>の用途を限定するため | |
math | math | math | math | ||
note | div | (aside, section) | div | <aside>, <section>はlandmarkと認識した方が覚えやすいため | |
paragraph | p | p | p | ||
status | output | output | output | ||
timer | div, span | - | div, span | ||
strong | strong | strong | strong | ||
subscript | sub | sub, sup | sub | ||
suggestion | div, span | - | div, span | ||
superscript | sup | sub, sup | sup | ||
table | table | table | table | ||
tabpanel | section | (section) | section | ||
term | dt, dfn | dfn | dt, dfn | dt, dfn | |
time | time | time | time | ||
tooltip | div | - | div | ||
banner | header | header | header | ||
complementary | aside | aside | aside | ||
contentinfo | footer | footer | footer | ||
form | form | form | form | ||
main | main | main | main | ||
navigation | nav | nav | nav | ||
region | section | section | section | ||
search | search | search | search | ||
gridcell | td | td | td, th | ||
row | tr | tr | tr | ||
checkbox | input [checkbox] | input [checkbox] | input [checkbox] | ||
switch | button, input [checkbox] | (a, img, button, input [button], input [checkbox]) | button, input [checkbox] | Form関連要素が理解しやすいため | |
combobox | select | select | select | ||
option | option | option | option | ||
radio | input [radio] | input [radio] | input [radio] | ||
slider | input [range] | input [range] | |||
spinbutton | input [number] | input [number] | |||
textbox | textarea, input [text] | textarea, input [text] | textarea, input [text] | ||
searchbox | input [search] | input [search] | input [search] | ||
button | button | button | button | ||
link | link, a, area | link, a | link, a, area | ||
menuitem | li | (li, a, img, button, input [button], input [checkbox], input [radio]) | li | <li>以外は<li>の中に定義可能なため | |
grid | table | table | (table) | ||
treegrid | table | (table) | table | ||
tablist | menu | (nav, menu, ol, ul) | menu | 基本的にtabは対話的要素であり<nav>はlandmarkと認識した方が覚えやすいため | |
listbox | select, datalist | select | select, datalist | ||
menu | menu | (nav, menu, ol, ul, select) | menu | role名と一致している方が覚えやすいため | |
menubar | menu | (nav, menu, ol, ul) | menu | 対話的要素が想定され<nav>はlandmarkと認識した方が覚えやすいため | |
radiogroup | fieldset | (menu, ol, ul, fieldset) | fieldset | ||
tree | ol | (menu, ol, ul) | ol | 順序が重要なため | |
dialog | dialog | dialog |
プロパティの厳選
使用しないプロパティ
以下のプロパティは基本的に使用しない。
プロパティ | 理由 |
---|---|
aria-activedescendant | Active=Focusと解釈すればFocus状態から推論可能なため |
aria-atomic | live regionの詳細設定用のため |
aria-autocomplete | Form系要素を使用する前提であれば推論可能なため |
aria-braillelabel | 点字について知らず使えないため |
aria-brailleroledescription | 点字について知らず使えないため |
aria-colcount | 文書構造から推論可能なため |
aria-colindex | 文書構造から推論可能なため |
aria-colindextext | 用途が限られるため |
aria-colspan | 文書構造から推論可能なため |
aria-disabled | Form系要素を使用する前提であれば推論可能であり、構造に対して必要な場合は限られるため |
aria-dropeffect | Deprecated in ARIA 1.1 |
aria-flowto | 文書構造やtabindexから推論可能なため |
aria-grabbed | Deprecated in ARIA 1.1 |
aria-level | 適切なHeadingタグや階層構造で推論可能なため |
aria-modal | dialogタグのメソッド使い分けで自動設定されるため |
aria-multiline | タグの使い分けで推論可能なため |
aria-multiselectable | selectタグを使用する前提であれば推論可能であり、その他の用途は限られるため |
aria-owns | 親子関係を文書構造で表現する前提であれば推論可能なため |
aria-placeholder | Form系要素を使用する前提であれば推論可能なため |
aria-readonly | Form系要素を使用する前提であれば推論可能なため |
aria-relevant | live regionの詳細設定用のため |
aria-required | Form系要素を使用する前提であれば推論可能なため |
aria-roledescription | Accessible Name等で代替可能なため |
aria-rowcount | 文書構造から推論可能なため |
aria-rowindex | 文書構造から推論可能なため |
aria-rowindextext | 用途が限られるため |
aria-rowspan | 文書構造から推論可能なため |
aria-sort | 動的テーブル系ロール用プロパティのため |
aria-valuemax | タグの属性から推論可能なため |
aria-valuemin | タグの属性から推論可能なため |
aria-valuenow | タグの属性から推論可能なため |
なぜaria-disabledを使用しないか
入力項目については、そもそも個人的にdisabled項目を表示するメリットがないと思うため、必要になった時に表示(要素追加)する方が良いように思っている。ミラーの法則やプログレッシブディスクロージャーの原則などもあるが、個人の体感としても表示されている項目は少なければ少ないほど圧迫感が少なく入力意欲が削がれないと感じる。また、フォーカスされないという点もreadonlyを使用せずdisabledにしている時点でフォーカス可能にする必要性を感じない。また、VoiceOverでは関係なく選択して読み上げできたという検証結果もあるため、わざわざaria-disabledを使用すべきだと思わない。
ボタンについても、押下可能になる条件が不明瞭になりがちなため、そもそもdisabledにするメリットがないと思っている。なぜユーザーが押下してはならない対話的要素がページに存在するようにしなければならないのか、と思ってしまうため今のところdisabledやaria-disabledの必要性を感じていない。見栄えだけ調整し、押下した時に条件に応じてアクセシブルな説明と実行停止をすれば良いだけだと思える。他要素との依存性をスクリプトだけに隔離できる事や、条件が実行スクリプト内で明示される点もより良いと感じる。
用途整理
動的更新区域(Live-region)定義用
プロパティ | 設定可能値 | 設定可能ロール | メモ |
---|---|---|---|
aria-live | off, polite, assertive | all | status,alertロールの設定で代用可能 |
aria-busy | false, true | all | 更新中のLive-region要素で使用 |
対話的要素の不正値用
プロパティ | 設定可能値 | 設定可能ロール | メモ |
---|---|---|---|
aria-invalid | false, true, grammar, spelling | textbox, searchbox, switch, checkbox, combobox, listbox, radiogroup, slider, spinbutton, columnheader, rowheader, gridcell, tree, treegrid | |
aria-errormessage | id | textbox, searchbox, checkbox, combobox, listbox, radiogroup, slider, spinbutton, switch, tree, columnheader, rowheader, gridcell, treegrid | Live-region要素のidを設定 |
Accesible Name設定用
プロパティ | 設定可能値 | 設定可能ロール |
---|---|---|
aria-label | "string" | all |
aria-labelledby | id | all |
別区域で詳細説明する用
プロパティ | 設定可能値 | 設定可能ロール | メモ |
---|---|---|---|
aria-description | "string" | all | |
aria-describedby | id | all | 構造化されていない文字列での説明 |
aria-details | id | all | 構造化されている文書区域での説明 |
Paging等の集合の一部だけを表示する用
全ての要素が文書上に現れている場合は設定不要。
プロパティ | 設定可能値 | 設定可能ロール |
---|---|---|
aria-posinset | "integer" | article, listitem, menuitem, tab, radio, option, comment, row, treeitem |
aria-setsize | "integer" | article, listitem, menuitem, tab, radio, option, comment, row, treeitem |
視覚や操作等の暗黙情報を明示する用
プロパティ | 設定可能値 | 設定可能ロール | メモ |
---|---|---|---|
aria-controls | id | all | 他要素を操作する場合に使用 |
aria-current | false, true, page, step, location, date, time | all | 現在位置を示すため参考のような用途で使用 |
aria-haspopup | false, true, menu, listbox, grid, tree, dialog | button, link, menuitem, tab, combobox, textbox, slider, gridcell, treeitem | Overlay表示のトリガー要素等で使用 |
aria-hidden | false, true, undefined | all | 装飾要素等で使用 |
aria-orientation | horizontal, vertical, undefined | separator, listbox, tablist, radiogroup, slider, menu, menubar, toolbar, tree, treegrid | ロールによって暗黙設定あり |
aria-keyshortcuts | "string" | all | ショートカットキーがある場合 |
特定の用途だけで使用する用
プロパティ | 設定可能値 | 使用ロール | メモ |
---|---|---|---|
aria-checked | false, true, mixed, undefined | switch | switchロールでのみ使用 |
aria-pressed | false, true, mixed, undefined | button | トグルボタンの実装でのみ使用 |
aria-selected | false, true, undefined | tab | tabロールでのみ使用 |
aria-expanded | false, true, undefined | tab | tabロールでのみ使用 |
aria-valuetext | "string" | meter, progressbar | aria-valuenowの数値として表現できない場合のみ使用 |
ロールとの関連
- 名列はAccessible Nameの設定について
-
o
は必須、x
は不可、空白は可能を表す
-
- 暗黙値列はそのロールを設定すると自動で設定されるプロパティ
- 設定要列はMUSTとして表現されているプロパティ
- 設定すべき列はSHOULDとして表現されているプロパティ
- メモ列は文章で記載されていた気を付ける事項
Role and properties
ロール | 名 | 暗黙値 | 設定要 | 設定すべき | メモ |
---|---|---|---|---|---|
document | - | - | - | ||
banner | - | - | - | ページに1つだけ設定すべき | |
complementary | - | - | - | ||
contentinfo | - | - | - | ページに1つだけ設定すべき | |
form | o | - | - | - | 検索フォームはsearchロールを使用すべき; 各要素にラベルを付けなければならない; 可視ラベルがある場合、aria-labelledbyを設定すべき; ラベルは見出しに含めるべき; 明示的なsubmit操作以外でsubmitする場合、事前に通知すべき |
main | - | - | - | ページに1つだけ設定すべき | |
navigation | - | - | - | ||
region | o | - | - | - | その他のランドマークが適切でない場合にのみ使用すべき; 可視ラベルがある場合、aria-labelledbyを設定すべき; ラベルは見出しに含めるべき |
search | - | - | - | ||
comment | - | - | - | コメントと被コメント要素の関連性を特定すべき | |
generic | - | - | - | コンテンツでこのロールを使用すべきでない; noneやgroupを使用してもよい | |
none | - | - | - | ||
image | o | - | - | - | |
link | o | - | - | - | |
figure | - | - | - | 本文からこのロールに参照を提供すべき; captionが説明の場合、aria-detailsを設定すべき | |
separator | aria-orientation="horizontal" | - | - | ||
heading | o | - | aria-level | - | Chromeではタグ種類に応じて自動的にaria-levelが付与されている |
group | - | - | - | 入れ子にしてもよい; 対話的要素の集合構造を構成するためにこのロールを使用すべき | |
log | aria-live="polite" | - | - | ||
marquee | aria-live="off" | - | - | ||
toolbar | aria-orientation="horizontal" | - | - | 複数存在する場合、ラベルを付けなければならない; Focusを管理してもよい | |
dialog | o | - | - | - | Focus可能な要素を持つべき; モーダルの場合、子要素にFocusを移動させるべき |
alertdialog | o | - | - | aria-describedby | モーダルにすべき; 子要素にFocusを移動させるべき; aria-describedbyを設定すべき |
note | - | - | - | 本文にaria-describedby,aria-detailsを設定するとよい | |
timer | aria-live="off" | - | - | 進行中はテキストを更新し続けるべき | |
tooltip | - | - | - | 参照元要素にaria-describedbyを設定すべき | |
button | o | - | - | - | トグルボタンにはaria-pressedを設定しなければならない |
checkbox | o | - | aria-checked | - | inputタグを使用する場合、aria-checkedは設定すべきでない |
switch | o | - | aria-checked | - | |
combobox | o | aria-haspopup="listbox" | aria-expanded | - | selectタグを使用しない場合、満たすべき条件あり |
radiogroup | o | - | - | - | |
radio | o | - | aria-checked | - | radiogroupを用いて明示的にグループ化されていることを保証すべき |
slider | o | aria-orientation="horizontal", aria-valuemin="0", aria-valuemax="100" | aria-valuenow | - | |
spinbutton | o | - | - | - | |
textbox | o | - | - | - | |
searchbox | o | - | - | - | |
meter | o | aria-valuemin="0", aria-valuemax="100" | aria-valuenow | - | 進行状況を表現するためにmeterを使用すべきでない |
progressbar | o | aria-valuemin="0", aria-valuemax="100" | - | - | 特定領域読み込み進行状況の場合、aria-describedbyを設定し、特定領域にaria-busy="true"を設定すべき |
alert | aria-live="assertive", aria-atomic="true" | - | - | Focusをメッセージに移す場合、alertdialogロールを使用すべき | |
status | aria-live="polite", aria-atomic="true" | - | - | このロールを制御する要素にaria-controlsを設定すべき | |
paragraph | x | - | - | - | このロールが無いと意味が変わってしまう場合にのみ使用すべき |
strong | x | - | - | - | 装飾のために使用すべきでない |
mark | x | - | - | - | このロールが無いと意味が変わってしまう場合にのみ使用すべき |
emphasis | x | - | - | - | |
code | x | - | - | - | このロールが無いと意味が変わってしまう場合にのみ使用すべき |
subscript | x | - | - | - | このロールが無いと意味が変わってしまう場合にのみ使用すべき |
superscript | x | - | - | - | |
time | x | - | - | - | |
blockquote | - | - | - | ||
math | - | - | - | 画像の場合は数式のラベル,説明を関連付けるべき | |
term | x | - | - | aria-describedby, aria-details | 対話的要素にこのロールを使用すべきでない |
definition | x | - | - | - | 定義されるtermロールを特定しなければならない; 対話的要素にこのロールを使用すべきでない |
table | o | - | - | - | ソートを含む対話的操作が可能な場合、gridかtreegridを使用すべき |
grid | o | - | - | - | 満たすべき条件あり |
treegrid | o | - | - | - | 満たすべき条件あり |
caption | x | - | - | - | このロールが名前を表す場合、親要素はaria-labelledbyを設定すべき |
rowgroup | - | - | - | ||
row | - | - | - | treegrid以外でaria-expanded,aria-level,aria-posinset,aria-setsizeを設定してはならない | |
columnheader | o | - | - | - | |
rowheader | o | - | - | - | |
cell | - | - | - | ||
gridcell | - | - | - | ||
menu | aria-orientation="vertical" | - | - | このロールの子孫含めFocusを管理すべき | |
menubar | aria-orientation="horizontal" | - | - | このロールの子孫含めFocusを管理すべき; デスクトップのメニューバーに似ていることを保証すべき | |
menuitem | o | - | - | - | サブメニューを持つ場合、aria-haspopup="true"を設定し、活性化時にサブメニューを表示すべき; separatorを用いて集合を分離してよい |
list | - | - | - | ||
listitem | - | - | - | ||
tree | o | aria-orientation="vertical" | - | - | このロールの子孫含めFocusを管理すべき |
treeitem | o | - | - | - | 通常aria-selected,aria-checkedの両方を設定すべきでない |
tablist | aria-orientation="horizontal" | - | - | 選択方式(単一,複数)により満たすべき条件あり; このロールの子孫含めFocusを管理すべき | |
tab | o | aria-selected="false" | - | aria-selected | 選択方式(単一,複数)により満たすべき条件あり |
tabpanel | o | - | - | - | aria-labelledbyを設定するか、tabにaria-controlsを設定すべき |
suggestion | x | - | - | - | 子を持たなければならない; 改訂された場合、その明示とこのロールの削除をすべき |
insertion | x | - | - | - | |
deletion | x | - | - | - | |
feed | - | - | - | ||
article | - | - | - | ||
listbox | o | aria-orientation="vertical" | - | - | 子孫のoptionロールのFocusを管理すべき |
option | o | - | - | - | optionタグを使用しない場合、満たすべき条件あり |
結論
以上の情報整理や紐付け制約をベースに、情報を追加付与する条件を纏めた。多くの場合ここに記載のないものは意識しなくても大きな問題はないと思われる。
制約
制約を設けた方が認知負荷が下がり大きな問題も起きないと総合的に判断した内容。
-
hr
タグ(separatorロール)はフォーカス不可とする -
a
,area
タグはhref
属性を設定する -
img
タグはalt
属性を設定し、空文字列以外の値を指定する - 親子関係がややこしい
template
,noscript
,script
は考慮外とする
文書構造としての枠組み
<html> <!-- role="document" -->
<head>
<title>text only</title>
<meta name="description" content="description text" />
...
</head>
<body>
<header> <!-- role="banner" (Landmark) -->
<search> <!-- role="search" (Landmark) -->
<input type="search" /> <!-- role="searchbox" -->
</search>
</header>
<nav></nav> <!-- role="navigation" (Landmark) -->
<main> <!-- role="main" (Landmark) -->
...
</main>
<aside></aside> <!-- role="complementary" (Landmark) -->
<footer></footer> <!-- role="contentinfo" (Landmark) -->
</body>
</html>
-
header
,footer
をLandmarkとするにはmain
やsection
等の外側に配置する必要がある- それらはページに1つだけ設置すべき
-
section
をLandmarkとするにはAccessible Nameを設定する必要がある (role="region")- 実際は
section
以外のLandmark系タグで十分と思われるため上記では省いた
- 実際は
-
form
もLandmarkとなる (role="form")
親子制約がある条件(セット)
- コメント内のロールは設定される暗黙ロールを表す
- タグの子部分のコメントは許容される内容を表す
HTMLによる制約
<details> <!-- role="group" -->
<summary><!-- Phrasing,Heading --></summary>
... <!-- Flow -->
</details>
<hgroup> <!-- role="group" -->
<h0></h0> <!-- parent is not limited to <hgroup>; role="heading" -->
<p></p> <!-- parent is not limited to <hgroup>; role="paragraph" -->
</hgroup>
<fieldset> <!-- role="group" -->
<legend><!-- Phrasing,Heading --></legend>
... <!-- Flow -->
</fieldset>
<textarea>text</textarea> <!-- role="textbox" -->
<picture>
<source />
<img alt="as acc name" /> <!-- parent is not limited to <picture>; role="image" -->
</picture>
<audio>
<source />
<track />
... <!-- Transparent -->
</audio>
<video>
<source />
<track />
... <!-- Transparent -->
</video>
<figure> <!-- role="figure" -->
<figcaption><!-- Flow --></figcaption>
... <!-- Flow -->
</figure>
<dl>
<!-- <div> can be put here -->
<dt><!-- Flow --></dt> <!-- role="term" -->
<dd><!-- Flow --></dd> <!-- role="definition" -->
<!-- </div> -->
</dl>
<ruby>
... <!-- Phrasing -->
<rp>text</rp>
<rt><!-- Phrasing --></rt>
<rp>text</rp>
</ruby>
<map> <!-- <map> is an ancestor of <area> -->
<area href="./path" /> <!-- role="link" -->
... <!-- Transparent -->
</map>
ロールによる制約
<div role="suggestion">
<ins></ins> <!-- parent is not litited to suggestion; role="insertion" -->
<del></del> <!-- parent is not litited to suggestion; role="deletion" -->
</div>
<article role="feed">
<article></article> <!-- parent is not litited to feed; role="article" -->
</article>
HTMLとロールの複合制約
<ul> <!-- role="list" -->
<li><!-- Flow --></li> <!-- role="listitem" -->
</ul>
<ol> <!-- role="list" -->
<li><!-- Flow --></li> <!-- role="listitem" -->
</ol>
<ol role="tree">
<!-- <div role="group"> can be put here -->
<li role="treeitem"><!-- Flow --></li>
<!-- <div role="group"> -->
</ol>
<menu role="menu">
<li role="menuitem"><!-- Flow --></li>
<li role="none"><hr /></li>
</menu>
<menu role="menubar">
<li role="menuitem"><!-- Flow --></li>
<li role="none"><hr aria-orientation="vertical" /></li>
</menu>
<menu role="toolbar">
<li role="none"><!-- Flow --></li>
<li role="none"><hr aria-orientation="vertical" /></li>
</menu>
<menu role="tablist">
<li id="xxx" role="tab" aria-selected="true" aria-expanded="true"><!-- Flow --></li>
</menu>
<section role="tabpanel" aria-labelledby="xxx"><!-- Flow --></section>
<select> <!-- role="combobox" -->
<!-- <optgroup> can be put here --> <!-- role="group" -->
<option>text</option> <!-- role="option" -->
<!-- </optgroup> -->
<!-- <hr role="none" /> can be put -->
</select>
<datalist> <!-- role="listbox" -->
<option>text</option> <!-- role="option" -->
<!-- or Phrasing -->
</datalist>
<!-- simple structure -->
<table> <!-- role="table" -->
<tr> <!-- role="row" -->
<td><!-- Flow --></td> <!-- role="cell" -->
</tr>
</table>
<!-- full structure -->
<table> <!-- if required, add role="grid" or role="treegrid" -->
<caption><!-- Flow --></caption> <!-- role="caption" -->
<colgroup>
<col span="2" />
</colgroup>
<thead> <!-- role="rowgroup" -->
<tr> <!-- role="row" -->
<th scope="col"><!-- Flow --><th> <!-- role="columnheader" -->
<th scope="col"><!-- Flow --><th> <!-- role="columnheader" -->
</tr>
</thead>
<tbody> <!-- role="rowgroup" -->
<tr> <!-- role="row" -->
<th scope="row"><!-- Flow --><th> <!-- role="rowheader" -->
<td><!-- Flow --></td> <!-- if change role of <table>, add role="gridcell" -->
</tr>
</tbody>
<tfoot> <!-- role="rowgroup" -->
<tr> <!-- role="row" -->
<th scope="row"><!-- Flow --><th> <!-- role="rowheader" -->
<td><!-- Flow --></td> <!-- if change role of <table>, add role="gridcell" -->
</tr>
</tfoot>
</table>
注意が必要な条件
- ややこしくなるため以下タグはLandmark以外で使用しない
-
header
,footer
,main
,nav
,aside
,search
-
-
section
はregion(Landmark)かtabpanelロールとして使用する- Landmarkとして使用するには以下のように記述する
<section aria-labelledby="xxx"> <!-- role="region" (landmark) --> <h1 id="xxx"></h1> <!-- role="heading" as accessible name of <section> --> ... </section>
- Landmarkとして使用するには以下のように記述する
-
form
はformロール(Landmark)になる- 目的を説明する簡単なラベルを付ける
- ラベルを見出しに含めて
aria-labelledby
属性を設定する
-
dl
,dt
,dd
を用いない単発の単語定義は例えば以下のように記述する<dfn aria-describedby="xxx"><!-- Phrasing --></dfn> <!-- role="term" --> <span id="xxx" role="definition"><!-- Phrasing --></span>
- 対話的要素にはラベル(Accessible Name)を付ける
-
table
にはcaption
(Accessible Name)を付ける -
a
には必ずhref
属性を設定する -
img
には必ずalt
属性を設定し、空文字列以外を指定する -
dialog
で警告やエラーメッセージを表示する場合はalertdialogロールを使用する- alertdialogロールとする時はモーダルダイアログとして表示する
-
aria-describedby
属性を設定すべき
-
meter
,progress
タグは必ずmax属性を設定する- HTMLではmaxのデフォルト値は
1.0
だが、WAI-ARIAのロールでは100
になる
- HTMLではmaxのデフォルト値は
-
meter
,progress
タグで現在値が数値で表現できない場合はaria-valuetext
を設定する -
input [radio]
をまとめるfieldset
にはradiogroupロールを使用する -
output
はその内容を変化させる対話的要素にaria-controls
属性を設定する -
output
でエラーメッセージを表示する場合はロールをalertに設定後、テキストを変更する -
output
以外に動的に表示が変化する区域にはdiv
にaria-live
属性を設定する- 読み込み中は
aria-busy
属性を設定する
- 読み込み中は
- タイマー表示をする場合はtimerロールを使用し、
aria-live
属性を適切に設定する - ツールチップを作る場合はtooltipロールを使用し、参照元要素に
aria-describedby
を設定する - トグルボタンを作る場合は
button
にaria-pressed
属性を設定して作成する - スイッチを作る場合は
button
かinput [checkbox]
でswitchロールを使用する-
button
の場合はaria-checked
属性を設定する
-
-
参考のようなUIを使用する場合は
aria-current
属性を設定する - 対話的要素で不正な値が存在する時は、
aria-invalid
,aria-errormessage
属性を設定する - 対話的要素でダイアログ以外のOverlay表示が増える場合は
aria-haspopup
属性を設定する - 対話的要素で親子関係でない要素に影響を与える場合は
aria-controls
属性を設定する - 完全に単なる視覚的な装飾である場合は
aria-hidden="true"
を設定する - ページングなど要素集合の全てが現れていない場合、
aria-setsize
,aria-posinset
属性を設定する - 以下のロールを使用したい場合は
div
を使用する- group,comment,log,note,tooltip,definition,timer,suggestion,marquee
- 便宜的に
div
やspan
を使用する場合は何もロールを付けずに使用する
雑記
非常に時間がかかりました。裏ではもう少しまとまったいくつかの表としているのですが、記事にすると相当見にくいですね。組織が違うので当たり前なのですが、文書を見ているとHTML Living StandardとWAI-ARIAで完璧に分かれているため両方の整合性を保った理解をするのが非常に面倒でした。罰則も軽いのでISO統合マネジメントシステムのような統合運用規約が無いと色々難しいように思います。5年以内にAGI,ASIが出てくるのでASIがAI記述用の完全に合理的な新Web仕様を策定してくれることを願います。
参考文献
- ウェブアクセシビリティとは? 分かりやすくゼロから解説!
- roletype role
- 6.8 Definitions of States and Properties (all aria-* attributes)
- Document conformance requirements for use of ARIA attributes in HTML
- Accessible name calculation
- HTML Living Standard
- HTML 要素リファレンス
- WAI-ARIA 実装の5つのルール
- WAI-ARIAを学ぶときに整理しておきたいこと
- aria-currentの値はいくつかあるけれど、それぞれどのUIで使うとよいのか整理してみた
- 「絶対にdisabled属性を避けて、aria-disabled属性を使わなければならない」わけではありません
-
令和6年(2024年)4月1日から、障害者差別解消法(障害を理由とする差別の解消の推進に関する法律)の改正により、国や地方公共団体などに義務付けられている合理的配慮の提供が、民間の事業者も義務化されました。 ウェブアクセシビリティとは? 分かりやすくゼロから解説! ↩︎
Discussion