複数選択コンポーネントの作成

並べ替えとフィルタのユーザー エクスペリエンスのために、レスポンシブで適応性が高く、アクセスしやすい複数選択のコンポーネントを構築する方法の基本的な概要。

この投稿では、複数選択コンポーネントを構築する方法についての考え方を共有します。ぜひ、 demo

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph> デモ

動画で視聴したい場合は、この投稿の YouTube バージョンをご利用ください。

概要

ユーザーに提示されるアイテムは多いものの、大量なアイテムで、 そのような場合は、リストを減らす方法を提示して、 選択肢の過負荷この ブログ投稿では、選択肢を減らす方法としてフィルタの UI について説明しています。これは、 ユーザーが選択または選択解除できるアイテム属性が表示され、結果が少なくなります 選択肢の過多を減らすことができます

インタラクション数

目標は、すべてのユーザーとユーザーのフィルタ オプションをすばやく 入力タイプもさまざまです。これは適応性が高くレスポンシブな コンポーネントのペアが必要です。デスクトップとキーボード用のチェックボックスからなる従来のサイドバー スクリーン リーダー、<select multiple> タッチユーザー向けです

パソコンのライトとダークの比較のスクリーンショット。サイドバーが
チェックボックス(複数選択要素を使用する iOS や Android のモバイルとの比較)

デスクトップ用ではなくタップ用の組み込みの複数選択を使用するという決定により、作業が節約され、作業が生まれますが、1 つのコンポーネントでレスポンシブ エクスペリエンス全体を構築するよりも、コード負債が少なく、適切なエクスペリエンスを提供できると考えています。

タップ

タップ コンポーネントはスペースを節約し、ユーザーによる操作の正確性を高めます。 対応しています。チェックボックスのサイドバー全体を <select> 組み込みのオーバーレイ タッチ エクスペリエンス。入力の正確さを助けるために、 システムが提供する大規模なタッチ オーバーレイ エクスペリエンス。


Android、iPhone、および Chrome の Chrome の複数選択要素のプレビューのスクリーンショット
iPad。iPad と iPhone では複数選択の切り替えが開いていて、
画面サイズに合わせて最適化した
独自のエクスペリエンスです

キーボードとゲームパッド

以下は、キーボードから <select multiple> を使用する方法のデモンストレーションです。

この組み込みの複数選択はスタイル設定ができず、コンパクト モードのみで利用できます 多数のオプションを表示するのに適さないレイアウトです。実際にやってみると、 この小さなボックス内には 幅広い選択肢があることにサイズも変更できますが、 チェックボックスのサイドバーほど使い勝手が良くありません

マークアップ

両方のコンポーネントが同じ <form> 要素に含まれます。結果: チェックボックスか複数選択かにかかわらず、このフォームを監視し、 サーバーに送信することもできます。

<form>

</form>

チェックボックス コンポーネント

チェックボックスのグループは、 <fieldset> 各要素に <legend>。 HTML をこのように構成すると、スクリーン リーダーと FormData は 要素の関係を自動的に把握します。

<form>
  <fieldset>
    <legend>New</legend>
    … checkboxes …
  </fieldset>
</form>

グループ化したら、<label><input type="checkbox"> を次のものに追加します: 表示されます。今回はこれを <div> でラップして、CSS の gap プロパティにします。 行を均等に分割して配置を維持できます。

<form>
  <fieldset>
    <legend>New</legend>
    <div>
      <input type="checkbox" id="last 30 days" name="new" value="last 30 days">
      <label for="last 30 days">Last 30 Days</label>
    </div>
    <div>
      <input type="checkbox" id="last 6 months" name="new" value="last 6 months">
      <label for="last 6 months">Last 6 Months</label>
    </div>
   </fieldset>
</form>

凡例に関する情報オーバーレイと
  fieldset 要素では、色と要素名が表示されます。

<select multiple> コンポーネント

<select> 要素でほとんど使用されない機能は、次のとおりです。 multiple。 この属性を <select> 要素で使用すると、ユーザーは次のことを行えます。 選択します。これはラジオのリストから操作を変更するようなものです チェックボックス リストに追加します。

<form>
  <select multiple="true" title="Filter results by category">
    …
  </select>
</form>

<select> 内にラベルを付けてグループを作成するには、 <optgroup> label 属性と値を指定します。この要素と属性は 値は <fieldset> 要素と <legend> 要素に似ています。

<form>
  <select multiple="true" title="Filter results by category">
    <optgroup label="New">
      …
    </optgroup>
  </select>
</form>

次に、 <option> フィルタの要素。

<form>
  <select multiple="true" title="Filter results by category">
    <optgroup label="New">
      <option value="last 30 days">Last 30 Days</option>
      <option value="last 6 months">Last 6 Months</option>
    </optgroup>
  </select>
</form>

複数選択要素のデスクトップ レンダリングのスクリーンショット。

支援技術に伝えるためにカウンタで入力を追跡する

ステータス ロール 技術を使用して、ユーザー エクスペリエンスの フィルタを使用できます。YouTube 動画 機能のデモを行います。統合は HTML と属性から始まります。 role="status"

<div role="status" class="sr-only" id="applied-filters"></div>

この要素では、コンテンツに加えられた変更が読み上げられます。新しい P-MAX キャンペーンを CSS を含むコンテンツ カウンタ ユーザーがチェックボックスを操作すると 認識されますそのためにはまず 入力と状態要素の親要素に名前が付けられたカウンタ。

aside {
  counter-reset: filters;
}

デフォルトでは、カウントは 0 になります。これは素晴らしいです。:checked この設計のデフォルト設定です

次に、新しく作成したカウンタをインクリメントするために、 :checked<aside> 要素。ユーザーが入力の状態を変更すると、 filters カウンタが集計されます。

aside :checked {
  counter-increment: filters;
}

CSS がチェックボックス UI の全般的な集計とステータスのロールを認識するようになりました 要素は空で、値を待機しています。CSS が総費用の集計を 維持するため メモリ、 counter() 関数を使用して、疑似関数から値にアクセスできます。 要素の内容:

aside #applied-filters::before {
  content: counter(filters) " filters ";
}

status ロール要素の HTML で「2 つのフィルタ」と読み上げられるようになりました。画面 読み取りますこれは良いスタートですが、 フィルタが更新された結果の数を表します。この処理は JavaScript から行います。 機能の範囲外です

アクティブなフィルタの数を通知する MacOS のスクリーン リーダーのスクリーンショット。

準備課程の高揚感

カウンタ アルゴリズムは CSS によって最適に感じられる nesting-1 には、すべての Pod を 1 つのブロックに統合しますポータブルで、読み取りや更新が一元化されていると感じられます。

aside {
  counter-reset: filters;

  & :checked {
    counter-increment: filters;
  }

  & #applied-filters::before {
    content: counter(filters) " filters ";
  }
}

レイアウト

このセクションでは、2 つのコンポーネント間のレイアウトについて説明します。ほとんどの レイアウト スタイルは、デスクトップのチェックボックス コンポーネント用です。

フォーム

ユーザーの読みやすさと読みやすさを最適化するために、フォームには 30 文字(基本的には各文字の光の線幅を設定) フィルタラベルを指定します。フォームでは、グリッド レイアウトと gap プロパティを使用して、 使用できます。

form {
  display: grid;
  gap: 2ch;
  max-inline-size: 30ch;
}

<select> 要素

モバイルでは、ラベルのリストとチェックボックスのリストの両方が多くのスペースを消費します。 そのため、レイアウトは、変更するユーザーのメイン ポインティング デバイスを確認し、 実現しています。

@media (pointer: coarse) {
  select[multiple] {
    display: block;
  }
}

coarse は、ユーザーが操作できないことを示します メイン入力デバイスで高い精度で画面を操作できます モバイル デバイスでは、ポインタの値はメインの操作として coarse であることが多い タッチです。デスクトップ デバイスでは、ポインタの値は一般的なため、多くの場合 fine になります。 マウスなどの高精度入力デバイスを接続します

フィールドセット

<legend> が指定された <fieldset> のデフォルトのスタイルとレイアウトは、以下のとおりです。

フィールドセットと凡例のデフォルト スタイルのスクリーンショット。

通常、子要素に間隔を空けるには gap プロパティを使用しますが、 <legend> の配置により、等間隔のセットを作成するのが難しくなる できます。gap ではなく、隣接する兄弟姉妹 セレクタmargin-block-start が使用されます。

fieldset {
  padding: 2ch;

  & > div + div {
    margin-block-start: 2ch;
  }
}

これにより、<legend> 子供 <div> 人。

入力間のマージンの間隔を示すスクリーンショット。凡例は表示されません。

フィルタラベルとチェックボックス

<fieldset> の直接の子として、フォームの 30ch。長すぎると、ラベルのテキストが折り返されることがあります。テキストを折り返すのは良いことですが、 テキストとチェックボックスの間の不整合は考慮されません。これには Flexbox が最適です。

fieldset > div {
  display: flex;
  gap: 2ch;
  align-items: baseline;
}
<ph type="x-smartling-placeholder">
</ph> チェックマークの位置付けを示すスクリーンショット
    複数行で折り返すシナリオで、テキストの 1 行目が空白になります。
この Codepen でもっとプレイする

アニメーション化されたグリッド

レイアウト アニメーションはアイソトープによって行われます。 インタラクティブな並べ替えとフィルタを行うための高性能で強力なプラグインです。

JavaScript

見栄えの良いアニメーションでインタラクティブなグリッド、JavaScript、 を使って、粗いエッジを研磨します。

ユーザー入力の正規化

この設計では、1 つのフォームで 2 種類の入力方法が使用されています。 してはいけないこと シリアル化する 同じですただし、JavaScript を使用すれば、 正規化します。

DevTools JavaScript コンソールのスクリーンショット
  正規化されたデータの結果を示します。

<select> 要素のデータ構造を、グループ化されたチェックボックスに合わせました。 構成します。そのために、 input イベント リスナーが <select> 要素に追加され、 selectedOptions マッピングされます。

document.querySelector('select').addEventListener('input', event => {
  // make selectedOptions iterable then reduce a new array object
  let selectData = Array.from(event.target.selectedOptions).reduce((data, opt) => {
    // parent optgroup label and option value are added to the reduce aggregator
    data.push([opt.parentElement.label.toLowerCase(), opt.value])
    return data
  }, [])
})

フォームを送信しても問題ありません。このデモの場合は、Isotope の フィルタ条件を指定します

ステータス ロール要素の終了

要素はチェックボックスに基づいてのみフィルタ数を集計、通知している メッセージの数も共有することをおすすめします <select> 要素の選択肢もカウントされます。

<select> 要素の選択が counter() に反映されました

データ正規化のセクションでは、入力に対するリスナーがすでに作成されています。ちなみに この関数の終了として、選択されたフィルタの数と結果の数が返されます。 定義しています。状態のロール要素に値を渡すことができます。 できます。

let statusRoleElement = document.querySelector('#applied-filters')
statusRoleElement.style.counterSet = selectData.length

role="status" 要素に反映された結果

:checked には、選択されたフィルタの数を ステータス ロールの要素を示していますが、フィルタされた結果の数は可視化されていません。 JavaScript は、チェックボックスの操作と、 <select> 要素と同様に textContent を追加します。

document
  .querySelector('aside form')
  .addEventListener('input', e => {
    // isotope demo code
    let filterResults = IsotopeGrid.getFilteredItemElements().length
    document.querySelector('#applied-filters').textContent = `giving ${filterResults} results`
})

これにより、「25 個の結果をもたらす 2 つのフィルタ」というお知らせが完成します。

結果を通知している macOS のスクリーン リーダーのスクリーンショット。

今後は、Google の優れた支援技術をすべての 操作方法が決まります。

まとめ

どのようにやり方をしたかわかったので、どのように感じますか? ‽ 🙂?

アプローチを多様化して、ウェブで構築するすべての方法を学びましょう。 デモを作成し、ツイートしてリンクを送ってください 下の [コミュニティリミックス]セクションに アクセスしてください

コミュニティ リミックス

ここにはまだ何も表示されません。