--- title: 'ARIA: grid ロール' slug: Web/Accessibility/ARIA/Roles/Grid_Role tags: - ARIA - ARIA Role - Accessibility translation_of: Web/Accessibility/ARIA/Roles/Grid_Role ---
\{{ariaref}}
grid
ロールは、1つ以上のセルの行を含むウィジェット用です。 各セルの位置は重要であり、キーボード入力を使用してフォーカスすることができます。
<table role="grid" aria-labelledby="select-your-seat"> <caption>座席を選んでください</caption> <tbody role="presentation"> <tr role="presentation"> <td></td> <th>列 A</th> <th>列 B</th> </tr> <tr> <th scope="row">島 1</th> <td tabindex="0"> <button id="1a" tabindex="-1">1A</button> </td> <td tabindex="-1"> <button id="1b" tabindex="-1">1B</button> </td> <!-- More Columns --> </tr> <tr> <th scope="row">島 2</th> <td tabindex="-1"> <button id="2a" tabindex="-1">2A</button> </td> <td tabindex="-1"> <button id="2b" tabindex="-1">2B</button> </td> <!-- More Columns --> </tr> </tbody> </table>
(オプション)上記の例の簡単な説明を含めます。
グリッドウィジェットには、テーマに関連するインタラクティブなコンテンツの1つ以上のセルを持つ1つ以上の行が含まれています。 それは特定の視覚的プレゼンテーションを意味するわけではありませんが、要素間の関係を意味します。 これは、チェックボックスやナビゲーションリンクなどのような単純なグループ化に使用します。 複雑なスプレッドシートアプリケーションにも使用できます。
セル要素には、行ヘッダーや列ヘッダーでない限り、gridcell
ロールがあります。 ヘッダー要素ではそれぞれ rowheader
ロールと columnheader
ロールです。 セル要素は、row
ロールを持つ要素によって所有される必要があります。 行は rowgroup
を使用してグループ化できます。
グリッドをインタラクティブなウィジェットとして使用する場合は、{{anch("Keyboard interactions","キーボードインタラクション")}}を実装する必要があります。
row
を含むグループ。aria-multiselectable
が true
に設定されている場合、グリッド内の複数の項目を選択できます。 デフォルト値は false
です。aria-readonly
を true
に設定するべきです。 デフォルト値は false
です。多くのユースケースでは、HTML の table
要素で十分であり、その要素にはすでに多くの ARIA ロールが含まれています。
キーボードユーザーはグリッドに出会うと、左、右、上、下のキーを使用して行と列をナビゲートします。 インタラクティブなコンポーネントをアクティブにするには、リターンキーとスペースキーを使用します。
キー | 動作 |
---|---|
→ | 1セル右にフォーカスを移動します。 フォーカスが行の右端のセルにある場合、フォーカスは移動しません。 |
← | 1セル左にフォーカスを移動します。 フォーカスが行の左端のセルにある場合、フォーカスは移動しません。 |
↓ | 1セル下にフォーカスを移動します。 フォーカスが列の最下部のセルにある場合、フォーカスは移動しません。 |
↑ | 1セル上にフォーカスを移動します。 フォーカスが列の最上部のセルにある場合、フォーカスは移動しません。 |
Page Down | 作成者が決定した行数だけ下にフォーカスを移動します。 通常、現在表示されている行セットの一番下の行が最初に表示される行の1つになるようにスクロールします。 フォーカスがグリッドの最後の行にある場合、フォーカスは移動しません。 |
Page Up | 作成者が決定した行数だけ上にフォーカスを移動します。通常、現在表示されている行セットの一番上の行が最後に表示される行の1つになるようにスクロールします。 フォーカスがグリッドの最初の行にある場合、フォーカスは移動しません。 |
Home | フォーカスを含む行の最初のセルにフォーカスを移動します。 |
End | フォーカスを含む行の最後のセルにフォーカスを移動します。 |
ctrl + Home | 最初の行の最初のセルにフォーカスを移動します。 |
ctrl + End | 最後の行の最後のセルにフォーカスを移動します。 |
セル、行、列を複数選択できる場合は、次のキーの組み合わせが一般的に使用されます。
キーの組み合わせ | 動作 |
---|---|
ctrl + Space | フォーカスを含む列を選択します。 |
shift + Space | フォーカスを含む行を選択します。 グリッドに行を選択するためのチェックボックス付きの列が含まれている場合、このキーの組み合わせを使用して、フォーカスがチェックボックスにない場合でもそのボックスをチェックできます。 |
ctrl + A | すべてのセルを選択します。 |
shift + → | 選択範囲を1セル右側に拡張します。 |
shift + ← | 選択範囲を1セル左側に拡張します。 |
shift + ↓ | 選択範囲を1セル下側に拡張します。 |
shift + ↑ | 選択範囲を1セル上側に拡張します。 |
<table role="grid" aria-labelledby="calendarheader" aria-readonly=true> <caption id="calendarheader">September 2018</caption> <thead role="rowgroup"> <tr role="row"> <td></td> <th role="columnheader" aria-label="Sunday">S</th> <th role="columnheader" aria-label="Monday">M</th> <th role="columnheader" aria-label="Tuesday">T</th> <th role="columnheader" aria-label="Wednesday">W</th> <th role="columnheader" aria-label="Thursday">T</th> <th role="columnheader" aria-label="Friday">F</th> <th role="columnheader" aria-label="Saturday">T</th> </tr> </thead> <tbody role="rowgroup"> <tr role="row"> <th scope="row" role="rowheader">Week 35</th> <td>26</td> <td>27</td> <td>28</td> <td>29</td> <td>30</td> <td>31</td> <td role="gridcell" tabindex="-1">1</td> </tr> <tr role="row"> <th scope="row" role="rowheader">Week 36</th> <td role="gridcell" tabindex="-1"> 2 </td> <td role="gridcell" tabindex="-1"> 3 </td> <td role="gridcell" tabindex="-1"> 4 </td> <td role="gridcell" tabindex="-1"> 5 </td> <td role="gridcell" tabindex="-1"> 6 </td> <td role="gridcell" tabindex="-1"> 7 </td> <td role="gridcell" tabindex="-1"> 8 </td> </tr> <tr role="row"> <th scope="row" role="rowheader">Week 37</th> <td role="gridcell" tabindex="-1"> 9 </td> <td role="gridcell" tabindex="-1"> 10 </td> <td role="gridcell" tabindex="-1"> 11 </td> <td role="gridcell" tabindex="-1"> 12 </td> <td role="gridcell" tabindex="-1"> 13 </td> <td role="gridcell" tabindex="-1"> 14 </td> <td role="gridcell" tabindex="-1"> 15 </td> </tr> <tr role="row"> <th scope="row" role="rowheader">Week 38</th> <td role="gridcell" tabindex="-1"> 16 </td> <td role="gridcell" tabindex="-1"> 17 </td> <td role="gridcell" tabindex="-1"> 18 </td> <td role="gridcell" tabindex="-1"> 19 </td> <td role="gridcell" tabindex="-1"> 20 </td> <td role="gridcell" tabindex="-1"> 21 </td> <td role="gridcell" tabindex="-1"> 22 </td> </tr> <tr role="row"> <th scope="row" role="rowheader">Week 39</th> <td role="gridcell" tabindex="-1"> 23 </td> <td role="gridcell" tabindex="-1"> 24 </td> <td role="gridcell" tabindex="-1"> 25 </td> <td role="gridcell" tabindex="-1"> 26 </td> <td role="gridcell" tabindex="-1"> 27 </td> <td role="gridcell" tabindex="-1"> 28 </td> <td role="gridcell" tabindex="-1"> 29 </td> </tr> <tr role="row"> <th scope="row" role="rowheader">Week 40</th> <td role="gridcell" tabindex="-1"> 30 </td> <td>1</td> <td>2</td> <td>3</td> <td>4</td> <td>5</td> <td>6</td> </tr> </tbody> </table>
body { margin: 2rem; font-family: "Helvetica Neue", sans-serif; } table { margin: 0; border-collapse: collapse; font-variant-numeric: tabular-nums; } tbody th, tbody td { padding: 5px; } tbody td { border: 1px solid #000; text-align: right; color: #767676; } tbody td[role="gridcell"] { color: #000; } tbody td[role="gridcell"]:hover, tbody td[role="gridcell"]:focus { background-color: #f6f6f6; outline: 3px solid blue; } }
var selectables = document.querySelectorAll('table td[role="gridcell"]'); selectables[0].setAttribute('tabindex', 0); var trs = document.querySelectorAll('table tbody tr'), row = 0, col = 0, maxrow = trs.length - 1, maxcol = 0; Array.prototype.forEach.call(trs, function(gridrow, i){ Array.prototype.forEach.call(gridrow.querySelectorAll('td'), function(el, i){ el.dataset.row = row; el.dataset.col = col; col = col + 1; }); if (col>maxcol) { maxcol = col - 1; } col = 0; row = row + 1; }); function moveto(newrow, newcol) { var tgt = document.querySelector('[data-row="' + newrow + '"][data-col="' + newcol + '"]'); if (tgt && (tgt.getAttribute('role')==='gridcell') ) { Array.prototype.forEach.call(document.querySelectorAll('[role=gridcell]'), function(el, i){ el.setAttribute('tabindex', '-1'); }); tgt.setAttribute('tabindex', '0'); tgt.focus(); return true; } else { return false; } } document.querySelector('table').addEventListener("keydown", function(event) { switch (event.key) { case "ArrowRight": moveto(parseInt(event.target.dataset.row, 10), parseInt(event.target.dataset.col, 10) + 1); break; case "ArrowLeft": moveto(parseInt(event.target.dataset.row, 10), parseInt(event.target.dataset.col, 10) - 1); break; case "ArrowDown": moveto(parseInt(event.target.dataset.row, 10) + 1, parseInt(event.target.dataset.col, 10)); break; case "ArrowUp": moveto(parseInt(event.target.dataset.row, 10) - 1, parseInt(event.target.dataset.col, 10)); break; case "Home": if (event.ctrlKey) { var i = 0; var result; do { var j = 0; var result; do { result = moveto(i, j); j++; } while (result == false); i++; } while (result == false); } else { moveto(parseInt(event.target.dataset.row, 10), 0); } break; case "End": if (event.ctrlKey) { var i = maxrow; var result; do { var j = maxcol; do { result = moveto(i, j); j--; } while (result == false); i--; } while (result == false); } else { moveto(parseInt(event.target.dataset.row, 10), document.querySelector('[data-row="' + event.target.dataset.row + '"]:last-of-type').dataset.col); } break; case "PageUp": var i = 0; var result; do { result = moveto(i, event.target.dataset.col); i++; } while (result == false); break; case "PageDown": var i = maxrow; var result; do { result = moveto(i, event.target.dataset.col); i--; } while (result == false); break; case "Enter": alert(event.target.textContent); break; } event.preventDefault(); });
{{EmbedLiveSample("Calendar_example", "100%", "300")}}
<table role="grid" aria-labelledby="calendarheader"> <caption id="calendarheader">September 2018</caption> <thead role="rowgroup"> <tr role="row"> <td></td> <th role="columnheader" aria-label="Sunday">S</th> <th role="columnheader" aria-label="Monday">M</th> <th role="columnheader" aria-label="Tuesday">T</th> <th role="columnheader" aria-label="Wednesday">W</th> <th role="columnheader" aria-label="Thursday">T</th> <th role="columnheader" aria-label="Friday">F</th> <th role="columnheader" aria-label="Saturday">T</th> </tr> </thead> <tbody role="rowgroup"> <tr role="row"> <th scope="row" role="rowheader">Week 35</th> <td>26</td> <td>27</td> <td>28</td> <td>29</td> <td>30</td> <td>31</td> <td role="gridcell" tabindex="-1">1</td> </tr> <tr role="row"> <th scope="row" role="rowheader">Week 36</th> <td role="gridcell" tabindex="-1"> 2 </td> <td role="gridcell" tabindex="-1"> 3 </td> <td role="gridcell" tabindex="-1"> 4 </td> <td role="gridcell" tabindex="-1"> 5 </td> <td role="gridcell" tabindex="-1"> 6 </td> <td role="gridcell" tabindex="-1"> 7 </td> <td role="gridcell" tabindex="-1"> 8 </td> </tr> <!-- … Additional Rows … --> </tbody> </table>
table { margin: 0; border-collapse: collapse; font-variant-numeric: tabular-nums; } tbody th, tbody td { padding: 5px; } tbody td { border: 1px solid #000; text-align: right; color: #767676; } tbody td[role="gridcell"] { color: #000; } tbody td[role="gridcell"]:hover, tbody td[role="gridcell"]:focus { background-color: #f6f6f6; outline: 3px solid blue; }
var selectables = document.querySelectorAll('table td[role="gridcell"]'); selectables[0].setAttribute('tabindex', 0); var trs = document.querySelectorAll('table tbody tr'), row = 0, col = 0, maxrow = trs.length - 1, maxcol = 0; Array.prototype.forEach.call(trs, function(gridrow, i){ Array.prototype.forEach.call(gridrow.querySelectorAll('td'), function(el, i){ el.dataset.row = row; el.dataset.col = col; col = col + 1; }); if (col>maxcol) { maxcol = col - 1; } col = 0; row = row + 1; }); function moveto(newrow, newcol) { var tgt = document.querySelector('[data-row="' + newrow + '"][data-col="' + newcol + '"]'); if (tgt && (tgt.getAttribute('role')==='gridcell') ) { Array.prototype.forEach.call(document.querySelectorAll('[role=gridcell]'), function(el, i){ el.setAttribute('tabindex', '-1'); }); tgt.setAttribute('tabindex', '0'); tgt.focus(); return true; } else { return false; } } document.querySelector('table').addEventListener("keydown", function(event) { switch (event.key) { case "ArrowRight": moveto(parseInt(event.target.dataset.row, 10), parseInt(event.target.dataset.col, 10) + 1); break; case "ArrowLeft": moveto(parseInt(event.target.dataset.row, 10), parseInt(event.target.dataset.col, 10) - 1); break; case "ArrowDown": moveto(parseInt(event.target.dataset.row, 10) + 1, parseInt(event.target.dataset.col, 10)); break; case "ArrowUp": moveto(parseInt(event.target.dataset.row, 10) - 1, parseInt(event.target.dataset.col, 10)); break; case "Home": if (event.ctrlKey) { var i = 0; var result; do { var j = 0; var result; do { result = moveto(i, j); j++; } while (result == false); i++; } while (result == false); } else { moveto(parseInt(event.target.dataset.row, 10), 0); } break; case "End": if (event.ctrlKey) { var i = maxrow; var result; do { var j = maxcol; do { result = moveto(i, j); j--; } while (result == false); i--; } while (result == false); } else { moveto(parseInt(event.target.dataset.row, 10), document.querySelector('[data-row="' + event.target.dataset.row + '"]:last-of-type').dataset.col); } break; case "PageUp": var i = 0; var result; do { result = moveto(i, event.target.dataset.col); i++; } while (result == false); break; case "PageDown": var i = maxrow; var result; do { result = moveto(i, event.target.dataset.col); i--; } while (result == false); break; case "Enter": alert(event.target.textContent); break; } event.preventDefault(); });
他の例を以下で見つけることができます。
{{anch("Keyboard interactions","キーボードインタラクション")}}が適切に実装されていても、矢印キーを使用する必要があることに気づかないユーザーもいます。 grid
ロールを使用して、必要な機能とインタラクションが最善にアーカイブできることを確認してください。
仕様 | 状態 |
---|---|
{{SpecName("ARIA","#grid","Role Grid")}} | {{Spec2('ARIA')}} |
{{SpecName("ARIA Authoring Practices","#grid","Role Grid")}} | {{Spec2('ARIA Authoring Practices')}} |
TBD