スイッチコンポーネントのRTL対応:見た目とキーボード操作を両立

shoelace-style/webawesome

WebAwesomeのスイッチコンポーネントに、RTL(右から左)レイアウト向けの対応が追加されました。AndroidやiOSのネイティブスイッチと同様に、RTL環境ではスイッチを左右反転させ、さらにキーボードの矢印キー操作もRTL方向に合わせて動作するようになります。

背景

モバイルOSのネイティブスイッチはRTLロケールで左右を反転する慣習があり、WebAwesomeのスイッチもその挙動に揃える必要がありました。RTL言語(アラビア語やヘブライ語など)のユーザーにとって、スイッチの「オン」が右側にある操作感は直感に反します。AndroidとiOSがどちらもRTL時にスイッチを反転していることを根拠として、本PRはWebAwesomeも同じ振る舞いを採用しています。

これまでは視覚的な反転もキーボード操作のRTL考慮も実装されておらず、RTL環境でのUX上の問題が残っていました。

技術的な変更

変更は switch.styles.tsswitch.ts の2ファイルにまたがり、それぞれ「見た目の反転」と「キーボード操作の反転」を担当します。

CSSによる視覚的反転として、switch.styles.ts:dir(rtl) 擬似クラスを使った2つのルールが追加されました。

// 未チェック状態(RTL): サムを右端に配置
.switch .thumb:dir(rtl) {
  translate: calc((var(--width) - var(--height)) / 2);
}

// チェック済み状態(RTL): サムを左端に配置
.checked .switch .thumb:dir(rtl) {
  translate: calc((var(--width) - var(--height)) / -2);
}

LTRでは未チェック時に / -2(左端)、チェック時に / 2(右端)でサムを配置していますが、RTLではこの符号が入れ替わります。ネイティブCSSの :dir() 擬似クラスを使うことで、JavaScriptを介さずにスタイルのみで方向を切り替えています。

キーボード操作のRTL反転として、switch.ts では LocalizeController を導入し、ArrowLeft / ArrowRight キーの動作をRTL環境で逆転させています。

// 変更前
if (event.key === 'ArrowLeft') {
  this.checked = false;
}
if (event.key === 'ArrowRight') {
  this.checked = true;
}

// 変更後
const isRtl = this.localize.dir() === 'rtl';
if (event.key === 'ArrowLeft') {
  this.checked = isRtl;      // RTLなら右方向(オン)に相当
}
if (event.key === 'ArrowRight') {
  this.checked = !isRtl;     // RTLなら左方向(オフ)に相当
}

LTRでは ArrowRight がオン、ArrowLeft がオフですが、RTLではその意味が逆転します。isRtl フラグを使ったシンプルな条件式で、方向の語義とチェック状態の対応を正しく保っています。

設計判断

CSSとJavaScriptの責務を明確に分離した設計が採用されています。視覚的なサムの位置はCSSの :dir(rtl) で宣言的に制御し、キーボードの論理的な方向解釈はJavaScriptの LocalizeController で動的に判定しています。

CSSの :dir() 擬似クラスはHTML要素の dir 属性や言語設定から方向を継承するネイティブ機能であり、コンポーネント内部での明示的なRTL状態管理が不要になります。一方、キーボードイベントはJavaScript側でしか捕捉できないため、LocalizeController.dir() を通じて同じ方向情報を参照する形になっています。両者が同じ情報源(ドキュメントの文字方向)から派生することで、視覚と操作の一貫性が保たれます。

まとめ

本PRは、CSS :dir() 擬似クラスと LocalizeController を組み合わせることで、スタイルとロジックそれぞれに最適な手段でRTL対応を実現しています。ネイティブのモバイルスイッチと同等の直感的な操作感を、最小限のコード変更で達成した実用的な改善です。

記事メタデータ

Generated by:
Claude Sonnet 4.6 for DiffDaily
LLM Trace:
fd24faf9

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
Gemini 2.5 Pro for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

リード文(総論)→ 背景・技術詳細・設計判断(各論)→ まとめ(結論)の3部構成が明確に守られており、非常に分かりやすい記事構成です。

カスタムMarkdown構文 ✓ PASS

シンタックスハイライト・GitHubリンク記法の正確性

ファイル名付きシンタックスハイライト(```typescript:path/to/file.ts)とPR番号のリンク記法([#2330](URL))が正しく使用されています。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

CSSの擬似クラスやJavaScriptのイベントハンドリングなど、専門知識を持つエンジニアを対象とした内容であり、過度な説明がなく適切です。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションが総論→各論の構成になっており、各段落もトピックセンテンスで始まるなど、パラグラフ・ライティングの原則が守られています。段落の長さも適切で読みやすいです。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

記事内で引用されているCSSとTypeScriptのコードは、提供されたDiffの内容を正確に反映しています。変更前後の比較形式も変更点を理解しやすく効果的です。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

「:dir() 擬似クラス」「LocalizeController」「RTL」といった技術用語が正確かつ文脈に沿って適切に使用されています。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

CSSによる視覚的な反転と、JavaScriptによるキーボード操作のロジック反転に関する説明は、コードの動作と完全に一致しており、技術的に正確です。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

「AndroidやiOSの挙動に合わせる」という背景や、具体的なコード変更に関する記述は、すべてPRのDescriptionやDiffの内容で裏付けられており、ハルシネーションはありません。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR番号(#2330)やファイルパスが正確に記載されています。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事のタイトル「スイッチコンポーネントのRTL対応:見た目とキーボード操作を両立」は、PRの主題「Fix switch RTL direction」を的確かつ具体的に表現しています。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

PR情報に含まれない外部知識(バージョンサポート情報、リリース日程など)の追加はなく、すべての記述が提供された情報に基づいています。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

記事内にはPR情報と矛盾するような時間表現(「近い将来」など)は使用されておらず、事実関係が正確に記述されています。