Switching It Up With HTML’s Latest Control
記事は上記記事を意訳したものです。
※当ブログでの翻訳記事は元サイト様に許可を得て掲載しています。
はじめに
Webは、HTMLの要素を取り入れ、見た目、動作、感触を完全に異なるものに変換することに慣れ親しんでいます。この一般的な例がスイッチ(トグル)コンポーネントです。複数のスタイルレイヤーの下にチェックボックスを隠し、ARIAの役割を「スイッチ」として定義し、そして出荷していました。しかし、この手法には不確定な状態における使いやすさの問題がありました。結局のところ、言葉にあるように、最高のARIAはARIAがないことです。
しかし、ネイティブHTMLスイッチが普及するための新たな希望が生まれました。
ネイティブHTMLスイッチの登場
Safari Technology Preview(TP) 185とSafari 17.4がリリースされ、うわさの新機能、ネイティブHTMLスイッチコントロールが導入されました。これは隠れたチェックボックスのアプローチから進化し、コントロールのアクセシビリティと使いやすさをより一貫したものにすることを目指しています。
<!-- これはネイティブチェックボックスをレンダリングします --> <input type="checkbox" /> <!-- `switch`属性を追加するとスイッチ要素をレンダリングします --> <input type="checkbox" switch /> <input type="checkbox" checked switch />
注: WebKitブログによると、@supports(::thumb)
を使ってブラウザのサポートを確認できます。ただし、::thumb
は実験的な機能で、Safariの「::thumbと::trackの疑似要素」の機能フラグを有効にする必要があります。そうしないと、デモでサポート通知が表示される偽陽性の状況になる可能性があります。
Safariのデフォルトスタイルは、驚くことなくiOSのスイッチのようです。幸いにも、新しいswitch
属性に加えて、スイッチをWebで最も美しいものにするための新しい疑似要素によるスタイル付けが可能になりました。
疑似要素によるスタイル付け
switch
属性の導入とともに、新しい::thumb
と::track
の疑似要素のサポートが追加されました。これらの疑似要素を使って、コントロールをスタイル付けするだけでなく、CSSでサポートを条件付きでチェックすることができます。ただし、一度に一つずつ行いましょう。
スタイル付け
スイッチコントロールはデフォルトでaccent-color
とcolor-scheme
プロパティをサポートしています。これにより、すでにある程度のテーマサポートが用意されています。しかし、疑似要素にスタイルを付けることで、スイッチを完全にコントロールできるようになります。
基本的なインプットスタイル
スタイル付けする前に、appearance: none
をスイッチに追加する必要があります。
input[type="checkbox"][switch] { appearance: none; }
appearanceを削除すれば、想像力次第でコントロールにスタイルを付けられます。もちろん、大きな力には大きな責任が伴います。appearanceを削除すると、オンとオフの状態で部品を配置する責任も生じます。
ベースのinputに適用するスタイルは、疑似要素のコンテナスタイルとして扱えます。ただし、ここで適用したスタイルは、非サポート環境のフォールバックスタイルになる可能性があることに注意してください。
input[type="checkbox"][switch] { /* スイッチのスタイル上書きに必要 */ appearance: none; display: inline-grid; position: relative; background-color: var(--color-aux-400); block-size: 2rem; inline-size: 4rem; border-radius: var(--border-radius-pill); transition: background 0.25s ease; padding-inline: var(--spacing-1x); }
さらに柔軟性を加えるため、コントロール自体にスタイルを付けると、その::after
と::before
の疑似要素にもアクセスできます。
::thumb
疑似要素
新しい::thumb
の疑似要素を使うと、スイッチのハンドルにスタイルを付けられます。これは一般的に、コントロールの切り替え時に操作する要素です。円形のつまみが最も一般的ですが、私たちのスタイルはそれに限定されません。しかし、再び一度に一つずつ行いましょう。
input[type="checkbox"][switch] { appearance: none; display: inline-grid; position: relative; background-color: var(--demo-color-aux-400); block-size: 2rem; inline-size: 4rem; border-radius: var(--demo-border-radius-pill); transition: background 0.25s ease; padding-inline: 0.25rem; /* つまみのスタイル */ &::thumb { block-size: 1.5rem; inline-size: 1.5rem; border-radius: var(--border-radius-circle); background: var(--color-aux-600); transition: translate 0.25s ease; } /* スイッチの「オン」状態のスタイル定義 */ &:checked { background: var(--color-blue-400); } &:checked::thumb { /* 状態間でのつまみの移動は私たちが責任を持つ */ translate: 2rem 0; } }
このデモでは、::thumb
要素への移行とアニメーションの適用を実験しています。appearance: none
を適用すると、異なる状態でのつまみの位置決めが私たちの責任になるため、これらの状態間の移行も自由に設定できます。
::track
疑似要素
コントロール自体にスタイルを付けるのと同様に、::track
の疑似要素はつまみが移動するバックグラウンドのトラックとして機能します。もちろん、クラシックなWebの様式として、このトラックを必ずしもそのように見せ掛ける必要はありません。この余分な要素は、別の創造的な方法で使用できます。
input[type="checkbox"][switch] { /* 上記のスタイルに加えて... */ /* トラックのスタイル */ &::track { block-size: 1rem; background: var(--color-aux-300); border-radius: var(--border-radius-pill); } /* オン状態のトラックスタイル */ &:checked::track { background: var(--color-blue-200); } }
確かに、これらの例はかなり基本的なものです。しかし、私たちが今やコントロールのスタイリングを非常に細かくコントロールできるようになったことが分かります。もちろん、このようなスタイリングは素晴らしいものですが、すべての卵を一つの言わば籠に入れる前に、サポートをチェックする必要があります。
スイッチサポートの検出
すべての新しくて素晴らしいものと同様に、あまり素晴らしくない考慮事項が存在します。この場合、switch
属性はSafariでのみサポートされています。これが他の主要ブラウザでも採用されれば、このスイッチ要素が広く使われるようになるでしょう。しかし、そうなるまでは、スイッチをレンダリングできるかどうかを検出する必要があります。
CSSでの検出
スイッチ属性のサポートをCSSで検出することはできますが、私が好むほど直接的ではありません。スイッチ要素には::thumb
と::track
の疑似要素が付随するため、これらのサポートをチェックすることで、スイッチ自体のサポートを推測できます。
@supports selector(::thumb) { /* スイッチがサポートされています。思う存分スタイリングしましょう! */ }
スイッチサポートされている場合にデフォルトのスタイルを適用したい場合は、not
キーワードを使って逆の条件をチェックできます。
@supports not selector(::thumb) { /* スイッチは_サポートされていません_。ここにフォールバックのスタイルを記述します。 */ }
JavaScriptでの検出
CSSの外でスイッチ属性の使用を検出する必要がある場合は、JavaScriptでinput要素を作成し、switch
属性をチェックすることができます。属性が存在する場合は、後でCSSスタイリングを行うためにドキュメントのルート要素にクラスを追加します。
function checkForSwitchSupport() { const input = document.createElement('input'); input.type = 'checkbox' if ('switch' in input) { return true; } return false } if (checkForSwitchSupport()) { document.documentElement.classList.add('has-switch'); }
.has-switch input[type="checkbox"][switch] { accent-color: var(--brand-color-accent-primary); }
スイッチの考慮事項
新しい機能には、それがどのように動作し、どのように使用されるかを学ぶ期間が伴います。その機能が特に実験的で、主要ブラウザの1つでしかサポートされていない場合、さらに詳細を発見し理解する必要があります。
チェックボックス: 同じでも違う
チェックボックスインプットにswitch
属性を追加するのは便利ですが、いくつかの前提が伴います。この構文の核心は、スイッチとチェックボックスは同じもので、視覚的には異なるということを意味しています。しかし、実際はそうではありません。
2つのインプットの間には、マークアップにおいて2つの主要な違いがあります。
- チェックボックスには不確定な状態を設定できますが、スイッチにはできません。
- スイッチは required とマークできますが、チェックボックスにはできません。
両方のコントロールが同じinputで作成できるため、これらの属性が混在し、予期せぬ動作をする可能性があります。
これらの違いはマークアップの規約だけにとどまりません。補助技術がチェックボックスとスイッチを伝える方法も異なります。チェックボックスの状態は「チェックされた」または「チェックされていない」と伝えられます。一方で、スイッチは「オン」または「オフ」と伝えられます。これは大きな違いには見えないかもしれませんが、これら2つのコントロールをグループ化すると曖昧さが残ります。これは、:checked
疑似セレクターを使ってオンのスイッチをターゲットするスタイリングでも明らかです。微妙な違いですが、違いはあるのです。
スイッチとチェックボックスは似ていますが、これら2つのコントロールを組み合わせるのが正しいアプローチなのでしょうか?
アクセシビリティ(A11Y): 違いの理解
従来、チェックボックスにスタイルを適用してスイッチを作成する際、(おそらく)role="switch"
をコンポーネントに付加していました。これにより、補助技術がコントロールをよりよく理解できるようになりました。では、新しいスイッチコントロールは補助技術にどのように解釈されるのでしょうか?
VoiceOver communicates the switch control while using Safari on Mac from Smashing Magazine on Vimeo.
このビデオでは、MacのSafariでVoiceOverがスイッチコントロールをどのように伝えるかを確認できます。ただし、VoiceOverはスクリーンリーダーの中でも代表的なものではなく、他のスクリーンリーダーでのテストも行う必要があります。
Adrian Roselliは、すでに2022年時点でさまざまなブラウザとスクリーンリーダーの組み合わせでの徹底的なテストを公開しており、プラットフォームの更新に合わせて維持されています。ネタバレをすると、結果は全く混沌としており、現時点ではスイッチを本番環境で使用すべきではありません。Adrian Roselliはさらに詳しい背景を提供しています。
「背景をもう少し説明すると、switch要素はWHATWGのHTMLで2018年に提案されました。Googleがしばらく取り組み、WICGでもいくつか議論がありましたが、最終的に断念しました。Open-UIが2021年に議論を開始しましたが、不確定な使用例に関するコメント以外はほとんど行われていません。
そして2023年7月[...]、新しい貢献者がWHATWGにcheckboxにswitch属性を追加するPRを提出し、現在に至っています。ただし、これはまだWHATWG HTMLにマージされていないことに注意してください。つまり、AppleのSafariはこれに大きく先行していることになります。」
興味深いことに、VoiceOverはスイッチを「オン」または「オフ」と発音しますが、Safariの開発者ツールでスイッチを検査してアクセシビリティプロパティを確認すると、「チェック済み」の参照が残っています。
コントロールのアクセシビリティの側面は通信だけではありません。2024年初頭には、スイッチがページの拡大縮小レベルに適切に対応できず、コントロールの可視性が低下または破損する問題がありました。しかし、私が書いている現在では、Safariがこれらの問題を解決したようです。拡大縮小を行ってもスイッチの視覚的な一体性が維持されます。
switch
属性はアクセシビリティの必要性を考慮に入れているようですが、アクセシブルでない方法で使用することを防ぐわけではありません。前述のように、不確定なプロパティと必須をスイッチとチェックボックスで混在させると、コントロールをナビゲートしようとする人々に予期せぬ動作をもたらす可能性があります。再びAdrianがうまくまとめています。
「スイッチの役割では混在状態は許されません。スイッチを混在状態に設定しないように注意しましょう。そうしないと、問題が発生します。」
- Adrian Roselli
国際化(I18N):オンはどちら側?
スイッチコントロールのアクセシビリティ以外にも、異なる文字モードとどのように対話するかという問題があります。
スイッチを作成する際、異なる文字モードと方向をサポートするために論理的なCSSを使用する必要がありました。これは、スイッチが右端(または行インライン終端)の位置が必ずしも「オン」を意味しない環境があるためです。一部の言語(右から左へ書く言語など)では、スイッチの左端(または行インライン開始)の位置が「オン」状態を意味する可能性が高いのです。
現在では常に論理的CSSを書くべきですが、新しいスイッチコントロールによりその必要性がなくなりました。なぜなら、コントロールは最も近いwriting-mode
とdirection
プロパティに適応するからです。つまり、左から右の環境ではスイッチの右端の位置が「オン」状態となり、右から左の環境では左端の位置が「オン」状態となります。
<div style="direction: ltr"> <input type="checkbox" switch checked /> </div> <div style="direction: rtl"> <input type="checkbox" switch checked /> </div>
最後に
私たちがWebを前進させ続けるにつれて、ツールも私たちと同様に進化するのは自然なことです。スイッチコントロールは、長年にわたってチェックボックスのハックに頼らざるを得なくなった問題を解決する、歓迎すべき追加機能です。
しかし、チェックボックスとスイッチを単一のインプットにまとめると、マークアップの組み合わせに関する懸念が生じる可能性があります。それでも、最終的にはこの問題はリンターやブラウザ自体の機能で解決できると考えています。
結局のところ、スイッチコンポーネントにネイティブなアプローチを持つことで、このコントロールのアクセシビリティと使いやすさがはるかに一貫したものになると期待できます。ただし、それは広く普及し、採用されることが前提条件です。