コハム

Webクリエイターのコハムが提供する、Web制作に役立つ情報をまとめたブログです。

最新のHTMLではスイッチが進化!ネイティブHTMLによるスイッチインターフェイスの実装方法

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-colorcolor-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-modedirectionプロパティに適応するからです。つまり、左から右の環境ではスイッチの右端の位置が「オン」状態となり、右から左の環境では左端の位置が「オン」状態となります。

<div style="direction: ltr">
  <input type="checkbox" switch checked />
</div>

<div style="direction: rtl">
  <input type="checkbox" switch checked />
</div>

最後に

私たちがWebを前進させ続けるにつれて、ツールも私たちと同様に進化するのは自然なことです。スイッチコントロールは、長年にわたってチェックボックスのハックに頼らざるを得なくなった問題を解決する、歓迎すべき追加機能です。

しかし、チェックボックスとスイッチを単一のインプットにまとめると、マークアップの組み合わせに関する懸念が生じる可能性があります。それでも、最終的にはこの問題はリンターやブラウザ自体の機能で解決できると考えています。

結局のところ、スイッチコンポーネントにネイティブなアプローチを持つことで、このコントロールのアクセシビリティと使いやすさがはるかに一貫したものになると期待できます。ただし、それは広く普及し、採用されることが前提条件です。

©コハム