Présentation générale de la création d'un composant multi-sélection responsif, adaptatif et accessible pour trier et filtrer les expériences utilisateur.
Dans ce message, je vais vous expliquer comment créer un composant à sélection multiple. Essayez le demo.
<ph type="x-smartling-placeholder">Si vous préférez la vidéo, voici une version YouTube de cet article:
Présentation
Les utilisateurs voient souvent des éléments, parfois beaucoup d'éléments. Dans ces dans certains cas, il peut être judicieux de proposer un moyen de réduire la liste pour éviter la surcharge de choix. Ce article de blog explore le filtrage de l'interface utilisateur comme moyen de réduire les choix. Pour ce faire, Présenter des attributs d'article que les utilisateurs peuvent sélectionner ou désélectionner, ce qui réduit les résultats ce qui réduit la surcharge de choix.
Interactions
L'objectif est de permettre un balayage rapide des options de filtrage pour tous les utilisateurs et leurs
différents types d'entrées. Pour cela, elle devra adopter une approche
une paire de composants. Barre latérale traditionnelle contenant des cases à cocher pour le bureau, le clavier
et lecteurs d'écran, ainsi qu'un élément <select
multiple>
pour les utilisateurs tactiles.
La décision d'utiliser la fonctionnalité de sélection multiple intégrée pour le toucher, et non pour les ordinateurs de bureau, permet d'économiser du travail et crée du travail, mais je pense qu'elle offre des expériences appropriées qui nécessitent moins de code que la création de l'ensemble de l'expérience responsive en un seul composant.
Toucher
Le composant tactile permet de gagner de l'espace et d'améliorer la précision des interactions de l'utilisateur sur
mobile. Elle permet de gagner de la place en réduisant toute une barre latérale de cases à cocher dans un
Expérience tactile en superposition <select>
intégrée. Il contribue à la précision des entrées en montrant
une superposition tactile de grande taille
fournie par le système.
Clavier et manette de jeu
Vous trouverez ci-dessous une démonstration de l'utilisation d'un élément <select multiple>
à partir du clavier.
Cette sélection multiple intégrée ne peut pas être stylisée et n'est proposée que dans un format compact mise en page non adaptée à la présentation d'un grand nombre d'options. Découvrez comment vous ne pouvez pas voir l’étendue des options dans cette petite boîte ? Vous pouvez modifier sa taille, toujours pas aussi utilisables qu'une barre latérale de cases à cocher.
Majoration
Les deux composants seront contenus dans le même élément <form>
. Les résultats de
ce formulaire, qu'il s'agisse de cases à cocher ou de sélections multiples, sera observé et utilisé pour
filtrer la grille, mais pourrait également
être envoyé à un serveur.
<form>
</form>
Composant de cases à cocher
Les groupes de cases à cocher doivent être placés dans
<fieldset>
auquel on attribue une valeur
<legend>
Lorsque le code HTML est structuré de
cette manière, les lecteurs d'écran et
FormData va
comprendre automatiquement la relation entre les éléments.
<form>
<fieldset>
<legend>New</legend>
… checkboxes …
</fieldset>
</form>
Une fois le regroupement en place, ajoutez un <label>
et un <input type="checkbox">
pour
chacun des filtres. J'ai choisi d'encapsuler le mien dans un <div>
afin que la propriété CSS gap
vous pouvez les espacer uniformément et maintenir
l'alignement lorsque les libellés sont multilignes.
<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>
Composant <select multiple>
Une caractéristique rarement utilisée de l'élément <select>
est
multiple
Lorsque l'attribut est utilisé avec un élément <select>
, l'utilisateur est autorisé à
choisissez-en plusieurs
dans la liste. C'est comme changer l'interaction
d'une liste d'options
à une liste de cases à cocher.
<form>
<select multiple="true" title="Filter results by category">
…
</select>
</form>
Pour ajouter un libellé et créer des groupes dans un <select>
, utilisez la méthode
<optgroup>
et attribuez-lui un attribut et une valeur label
. Cet élément et cet attribut
sont semblables aux éléments <fieldset>
et <legend>
.
<form>
<select multiple="true" title="Filter results by category">
<optgroup label="New">
…
</optgroup>
</select>
</form>
À présent, ajoutez le
<option>
pour le filtre.
<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>
Suivi des entrées avec des compteurs pour informer les technologies d'assistance
L'état
rôle
est utilisée dans cette expérience utilisateur, pour suivre et maintenir le décompte
des filtres pour les lecteurs d'écran et
d'autres technologies d'assistance. Vidéo YouTube
présente la fonctionnalité. L'intégration commence par le code HTML et l'attribut
role="status"
<div role="status" class="sr-only" id="applied-filters"></div>
Cet élément lit à voix haute les modifications apportées au contenu. Nous pouvons mettre à jour contenu avec CSS compteurs lorsque les utilisateurs interagissent avec les cases à cocher. Pour ce faire, nous devons d'abord créer compteur avec un nom sur un élément parent des entrées et de l'élément d'état.
aside {
counter-reset: filters;
}
Par défaut, le nombre est de 0
, ce qui est très bien, car aucun résultat n'indique :checked
par défaut dans
cette conception.
Ensuite, pour incrémenter le compteur que vous venez de créer, nous allons cibler les enfants du
Élément <aside>
défini sur :checked
. Lorsque l'utilisateur modifie l'état des entrées,
le compteur filters
va être comptabilisé.
aside :checked {
counter-increment: filters;
}
Le CSS connaît désormais le décompte général de l'interface utilisateur de la case à cocher et le rôle d'état
est vide et attend des valeurs. Comme le CSS gère le décompte
mémoire, le
counter()
permet d'accéder à la valeur d'une valeur pseudo-
:
aside #applied-filters::before {
content: counter(filters) " filters ";
}
Le code HTML de l'élément de rôle d'état affichera désormais "2 filtres" à un écran en lecture seule. C'est un bon début, mais nous pouvons faire mieux, par exemple partager le décompte les résultats que les filtres ont mis à jour. Nous effectuerons cette tâche à partir de JavaScript, en dehors de ce que les compteurs peuvent faire.
Excitation liée à l'imbrication
L'algorithme des compteurs était optimal avec CSS nesting-1, car j'ai pu insérer toutes les dans un seul bloc. Se sent portable et centralisée pour la lecture et la mise à jour.
aside {
counter-reset: filters;
& :checked {
counter-increment: filters;
}
& #applied-filters::before {
content: counter(filters) " filters ";
}
}
Mises en page
Cette section décrit les mises en page entre les deux composants. La plupart des les styles de mise en page s'appliquent au composant de case à cocher pour ordinateur de bureau.
Le formulaire
Afin d'optimiser la lisibilité et la lisibilité du formulaire, le formulaire reçoit une valeur maximale
de 30 caractères, soit une épaisseur de ligne optique
libellé de filtre. Le formulaire utilise une mise en page sous forme de grille et la propriété gap
pour espacer les
des ensembles de champs.
form {
display: grid;
gap: 2ch;
max-inline-size: 30ch;
}
L'élément <select>
La liste des libellés et des cases à cocher occupe trop d'espace sur les appareils mobiles. Par conséquent, la mise en page vérifie que le principal dispositif de pointage de l'utilisateur à changer l'expérience tactile.
@media (pointer: coarse) {
select[multiple] {
display: block;
}
}
La valeur coarse
indique que l'utilisateur ne pourra pas interagir avec
l'écran avec une grande précision
avec son périphérique d'entrée principal. Sur un
appareil mobile, la valeur du pointeur est souvent coarse
, car il s'agit de l'interaction principale
c'est le toucher. Sur un ordinateur de bureau, la valeur du pointeur est souvent fine
, comme c'est souvent le cas.
d’avoir une souris ou un autre périphérique
d’entrée haute précision connecté.
Ensembles de champs
Le style et la mise en page par défaut d'un <fieldset>
avec un <legend>
sont uniques:
Normalement, pour espacer mes éléments enfants, j'utilise la propriété gap
, mais la valeur unique
le positionnement de <legend>
rend difficile la création d'un ensemble espacé uniformément.
des enfants. Au lieu de gap
, le sœur adjacent
sélecteur et
margin-block-start
sont utilisés.
fieldset {
padding: 2ch;
& > div + div {
margin-block-start: 2ch;
}
}
Cela évite que <legend>
n'ait un ajustement de son espace en ne ciblant que le
<div>
enfant.
Le libellé et la case à cocher du filtre
En tant qu'enfant direct d'un élément <fieldset>
, dans la largeur maximale de la
30ch
, le texte du libellé risque d'être renvoyé à la ligne s'il est trop long. Le retour à la ligne automatique
est une bonne chose, mais
un désalignement entre
le texte et la case à cocher ne l’est pas. Flexbox est la solution idéale pour cela.
fieldset > div {
display: flex;
gap: 2ch;
align-items: baseline;
}
La grille animée
L'animation de mise en page est réalisée par Isotope. A performant et performant pour le tri et le filtrage interactifs.
JavaScript
En plus de vous aider à orchestrer une grille interactive et animée, JavaScript sert à polir quelques arêtes.
Normaliser l'entrée utilisateur
Cette conception a une forme avec deux façons différentes de fournir des informations, et elles ne pas sérialiser même chose. Mais avec un peu de JavaScript, normaliser les données.
J'ai choisi d'aligner la structure de données de l'élément <select>
sur les cases à cocher groupées.
structure. Pour ce faire, un
input
l'écouteur d'événements est ajouté à l'élément <select>
. Il est alors
selectedOptions
sont mappées.
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
}, [])
})
Vous pouvez maintenant envoyer le formulaire en toute sécurité ou, dans le cas de cette démonstration, demander à Isotope sur les éléments à filtrer.
Finalisation de l'élément de rôle d'état
L'élément comptabilise et annonce uniquement le nombre de filtres en fonction d'une case à cocher
interaction, mais j'ai pensé que c'était une bonne idée de partager également le nombre de
et vous assurer que les choix d'éléments <select>
sont également comptés.
Le choix de l'élément <select>
est reflété dans counter()
Dans la section de normalisation des données, un écouteur a déjà été créé pour l'entrée. À la fin de cette fonction, le nombre de filtres choisis et le nombre de résultats pour ces filtres sont connues. Les valeurs peuvent être transmises à l'élément du rôle d'état comme ceci.
let statusRoleElement = document.querySelector('#applied-filters')
statusRoleElement.style.counterSet = selectData.length
Résultats reflétés dans l'élément role="status"
:checked
fournit un moyen intégré de transmettre le nombre de filtres choisis à
l'élément du rôle d'état, mais n'a pas accès au nombre de résultats filtrés.
JavaScript peut surveiller l'interaction avec les cases à cocher et après avoir filtré
grille, ajoutez textContent
comme l'élément <select>
.
document
.querySelector('aside form')
.addEventListener('input', e => {
// isotope demo code
let filterResults = IsotopeGrid.getFilteredItemElements().length
document.querySelector('#applied-filters').textContent = `giving ${filterResults} results`
})
Au total, ce travail achève l'annonce "2 filtres donnant 25 résultats".
Notre excellente expérience technologique d'assistance sera désormais assurée les utilisateurs, quelle que soit leur façon d'interagir avec elle.
Conclusion
Maintenant que vous savez comment j'ai fait, comment feriez-vous ? 😃
Diversifiez nos approches et découvrons toutes les manières de créer des applications sur le Web. Créer une démonstration, me envoyer des tweets et je l'ajouterai à la section des remix de la communauté ci-dessous.
Remix de la communauté
Rien à afficher pour le moment !