Salesforce Lightning Web Components (LWC) のリンティング
Salesforce Lightning Web Components を例に、コンポーネントの設定を段階的に構築する方法
Salesforce Lightning Web Component (LWC) テンプレートは、カスタム要素から構築される HTML ファイルです。Salesforce のベースコンポーネント、例えば <lightning-button> や <lightning-icon> などや、c- 名前空間内で自ら作成したコンポーネントである、例えば <c-my-image> などです。Axe DevTools Linter は、これらの要素が何をレンダリングするのかを設定オプション global-components を使って知らせると、カスタム要素をチェックします。
この記事では、LWC の設定をゼロから構築します。LWC は、自身では要素をレンダリングしないコンポーネントを含む、すべてのマッピング構文を適用するための良い例です。この方法は任意のコンポーネントライブラリに適用できます。各コンポーネントが何をレンダリングするかを説明し、その説明をテストファイルと照合し、両者が一致しないところを修正します。
カスタムコンポーネントマッピングの概要については カスタムコンポーネントのリンティング を参照してください。完全な構文リファレンスについては Axe DevTools Linter の設定 を参照してください。
始める前に
プロジェクトのルートに axe-linter.yml ファイルを追加します。以下のすべての例はそのファイルに記載されます。エディタ拡張機能の代わりに REST エンドポイントを使用する場合は、config オブジェクト内に同じ設定を書き込む必要があります。詳細は Axe DevTools Linter REST エンドポイントでのカスタムコンポーネントのリンティング を参照してください。
マッピングはブラウザが受け取るものを説明します
これは他のすべての決定を簡単にするアイデアです: マッピングは、コンポーネントがレンダリングする要素を説明します。テンプレート上で記述するタグではありません。
<lightning-button label="Save"> は、テキストコンテンツが「保存」となる button をレンダリングします。マッピングとして記述すると、次のようになります。
global-components:
lightning-button:
element: button
attributes:
- label: <text>The special <text> value says that the label attribute becomes the element's text content, which is what gives a button its accessible name. With that mapping in place, Axe DevTools Linter reports a button-name violation for <lightning-button> used with no label, exactly as it would for an empty <button>.
ステップ 1: 要素をレンダリングするコンポーネントをマッピングする
まず、単一のネイティブ要素にクリーンにマップされるコンポーネントから始め、アクセシビリティ情報を持つ属性のみをマッピングします。
global-components:
# Salesforce base components
lightning-button:
element: button
attributes:
- label: <text>
lightning-icon:
element: img
attributes:
- alternative-text: alt
# Components you author yourself
c-my-image:
element: img
attributes:
- alternative-text: altコンポーネント名は大文字と小文字を区別し、テンプレートで記述するタグと一致するため、LWC のケバブケース名はそのまま使用されます。
ARIA 属性を通過させるための aria-*、出力される要素を属性で選択できる <element>、常にレンダリングされる値を宣言する default などのその他の特別な値については、VS Code 用 Axe Accessibility Linter 拡張機能または JetBrains プラグインでのカスタムコンポーネントのリンティング のガイドを参照してください。
ステップ 2: レンダリングしないラッパーを宣言する
LWC は <template> をコンポーネントのルート要素に使用し、繰り返しと条件に再利用します。
<template>
<ul>
<template for:each={items} for:item="item">
<li key={item.id}>{item.name}</li>
</template>
</ul>
</template>HTML では、<template> 要素の内容は不活性です。ブラウザはそれらをレンダリングせず、支援技術はそれらにアクセスできません。Axe DevTools Linter は、ユーザーが実際に取得するマークアップを評価するため <template> 内のコンテンツを報告しません。LWC はコンパイル時に全く要素を生成しない命令として同じタグ名を使用しているため、リンターにラッパーが何に変換されるかを知らせる必要があります。上記のマークアップはブラウザに次のように届きます。
<ul>
<li>…</li>
<li>…</li>
</ul>構成に template を宣言することで、リンターはそのラッパーの内側を透過してマークアップを見ることができます。マッピングは何らかの要素を名前にしなければならず、マッピングはタグが現れるすべての場所に適用されるため、選択する要素は重要です。上記のリストを使って 2 つの選択を行うとその理由がわかります。
一般的なコンテナを試す
div は、ラッパーが一般的なコンテナのように聞こえるので最初の推測として自然です。
global-components:
template: divAxe DevTools Linter は、今やそのリストを <template> を div として記述したかのように評価します。
<ul>
<div>
<li>…</li>
</div>
</ul>そして <ul> 行に違反を報告します。
list: <ul> and <ol> must only directly contain <li>, <script> or <template> elements報告されたことは与えられたマークアップに対して正しいですが、そのマークアップはブラウザが受け取るものではありません。LWC はラッパーを削除するため、レンダリングされたリストにはリストアイテムが直接含まれ、完全に有効です。違反は代替要素から来ており、あなたのテンプレートではありません。
レンダリングされた関係に一致させる
template をブラウザが実際にリスト内で見つける要素にマップします。
global-components:
template: liリンターは同じリストを次のように評価します。
<ul>
<li>
<li>…</li>
</li>
</ul>list 違反は報告されません。なぜなら、<ul> が直接 li を含んでおり、それは上記のルールメッセージが許可している要素の一つであり、それがブラウザも受け取る関係だからです。li が二重に存在するのはリンターのあなたのファイルの表示だけであり、それは何もレンダリングしないラッパーの代わりとしてあり、あなたはそれをテンプレートで書くことは決してありません。
構成から template を除外することでも違反を避けられますが、その場合、テンプレート内の何も評価されません。これはステップ 2 が解決しようとした問題です。
両方の選択が内部コンテンツをチェックする
代替要素はラッパー自体がリンターにどのように表示されるかにのみ影響します。どちらの場合も内部のマークアップは評価されます。同じリストに代替テキストのない画像を追加します。
<template>
<ul>
<template for:each={items} for:item="item">
<li key={item.id}><img src={item.url}></li>
</template>
</ul>
</template>template: div と template: li の両方が画像の代替テキスト欠如を報告します。
image-alt: Images must have alternative texttemplate: div を使用すると、その結果に加えて誤りのある list 違反も発生します。これが両者の実用的な違いです。リストアイテムの繰り返しが <template> の最も一般的な使用法であるため、li にマッピングすることがレンダリングされた出力と最も一致し、推奨される出発点です。
3 つのルールは、コンテナが適切な種類の直接の子を持っているかを確認します: <ul> と <ol> に対する list、<dl> に対する definition-list および <details> に対する summary-name です。それらの 4 つのコンテナの1つの直下に <template> がある場合、あなたの代替要素がそれに代わります。そのため、これらの 3 つのルールは、同等のプレーン HTML について報告されるであろうことを報告しないかもしれません。他のルールは影響を受けず、テンプレート内のコンテンツは完全にチェックされます。
ステップ 3: 設定を確認する
マッピングが意図されたとおりに動作するとは限りません。最も信頼できるチェックは、同じマークアップを2回書き、1つはコンポーネントと、もう1つはそれらがレンダリングすると予想されるプレーン HTML として、両方が同じ結果をもたらすことを確認することです。
どこでも Axe DevTools Linter がチェックするプロジェクトに小さなテストファイル scratch.html を作成します。
<template>
<c-my-image src="cat.jpg"></c-my-image>
<lightning-button></lightning-button>
</template>次に、そのコンポーネントがレンダリングすると予想するマークアップを含むプレーン HTML の双子の scratch-expected.html を作成します。
<img src="cat.jpg">
<button></button>ステップ 1 と 2 のマッピングを適用すると、両方のファイルは同じ 2 つの違反を報告します。代替テキストのない画像に対する image-alt と、アクセシブル名のないボタンに対する button-name です。結果が一致するということは、マッピングがコンポーネントを正しく説明していることを意味します。一方のファイルだけが違反を報告する場合、それは設定が原因であり、マークアップではありません。
このペアはチェックを行う価値がある理由も示しています。ステップ 2 の template マッピングがない場合、scratch.html は何も報告しませんが、scratch-expected.html は両方の違反を報告します。この不一致が設定の何かが欠けているというシグナルです。
結果を確認する便利な方法は 3 つあります。
- VS Code または JetBrains IDE でファイルを開き、VS Code 用 Axe Accessibility Linter 拡張または JetBrains プラグインでのカスタムコンポーネントのリンティング で説明されているように、ハイライトされたエラーを確認します。
- Axe DevTools Linter コネクターを使用して、両方のファイルに対して一つのコマンドで実行します。
- RESTエンドポイントを使用して、各ファイルの内容をあなたの設定と共に
configオブジェクトで投稿してください。Axe DevTools Linter REST エンドポイントでのカスタムコンポーネントのリンティングを参照してください。
コンポーネント名を各結果に追加すると、どのマッピングが違反を生じたかが分かりやすくなり、より大きな設定もデバッグしやすくなります。カスタムコンポーネント違反の分析を参照してください。
マッピングに何を要求すべきかを決定する
一部のコンポーネントは使用方法によって異なるマークアップをレンダリングし、これらをマッピングすることは単なる翻訳ではなく方針の決定になります。<lightning-icon>は良い例です。alternative-textのないアイコンは装飾的であり、alternative-textのあるアイコンは意味を伝えます。
<lightning-icon>をimgにマッピングするということは、リンターがすべてのアイコンに代替テキストを宣言するよう要求することを意味します。明示された空の値でその要求は満たされます:
<!-- Reported: an image with no alternative text -->
<lightning-icon icon-name="utility:check"></lightning-icon>
<!-- Not reported: explicitly decorative -->
<lightning-icon icon-name="utility:check" alternative-text=""></lightning-icon>これは便利な慣習です。なぜなら、それにより各アイコンの意図がテンプレート内で明示され、省略によって暗示されることがないからです。もしそれを採用したくない場合は、<lightning-icon>を設定から除外し、リンターが評価しないようにします。
コンポーネントが常に属性の同じ値をレンダリングする場合、例えば固定されたrole、その値を記録するためにdefaultを使用します。defaultは値が空でない場合にのみ効果を発揮し、defaultは属性を設定することはできても<text>コンテンツを提供することはできません。デフォルト属性を参照してください。
アクセシビリティ情報を持つ属性のみをマッピングし、マッピングする前に各コンポーネントが何をレンダリングするかを確認してください。この記事の例はSalesforceベースのコンポーネントが生成するマークアップに沿ったものですが、あなた自身のコンポーネントやラップするコンポーネントも同じ確認が必要です。
これを自分自身のコンポーネントに適用する
上記のステップは、どのコンポーネントライブラリにも一般化できます:
- インタラクティブまたは意味のある要素をレンダリングするコンポーネントをリストする、例えばボタン、リンク、画像、フォームコントロール、見出しなど。それらは最小限の設定で最大の価値を提供します。
- それぞれについて、何をレンダリングし、どの属性がアクセシビリティ情報を含むかを記録する、そしてそれらの属性だけをマッピングします。
- 自分自身の何もレンダリングしないラッパーを宣言する、ブラウザーが見る関係を保持する代替要素を選択します。
- プレーンHTML同等物に対して各マッピングを検証する、それを当てにする前に。
- コンポーネントが変更されたときに設定を再確認する マッピングは、その日コンポーネントがどのように動作していたかを反映するに過ぎません。
もしあなたのライブラリがAxe DevTools Linterがすでに知っているライブラリの一つであるなら、これらの作業のほとんどをスキップできます。プリコンフィグされたコンポーネントライブラリを参照してください。
