Una descripción general fundamental de cómo compilar un componente de selección múltiple responsivo, adaptable y accesible para ordenar y filtrar las experiencias del usuario.
En esta publicación, quiero compartir ideas sobre cómo crear un componente de selección múltiple. Prueba la demostración.
Si prefieres ver un video, aquí tienes una versión de YouTube de esta publicación:
Descripción general
A menudo, los usuarios reciben elementos, a veces, muchos elementos, y en estos en muchos casos, puede ser una buena idea ofrecer una forma de reducir la lista para evitar sobrecarga de opciones. Esta en la entrada de blog explora la IU de filtrado como una forma de reducir las opciones. Para ello, presentar atributos de elementos que los usuarios pueden seleccionar o anular, lo que reduce los resultados lo que reduce la sobrecarga de opciones.
Interacciones
El objetivo es permitir un recorrido rápido de opciones de filtro para todos los usuarios y sus
diferentes tipos de entradas. A esto se le brindará una plataforma adaptable y
par de componentes. Barra lateral tradicional de casillas de verificación para computadoras, teclados
y lectores de pantalla, y un <select
multiple>
para usuarios táctiles.
Esta decisión de usar la selección múltiple integrada para el tacto y no para computadoras de escritorio ahorra trabajo y genera trabajo, pero creo que ofrece experiencias adecuadas con menos deuda de código que crear toda la experiencia responsiva en un solo componente.
Pantalla táctil
El componente táctil ahorra espacio y ayuda con la precisión de la interacción del usuario en
móvil. Ahorra espacio al contraer toda la barra lateral de casillas de verificación en una
<select>
Experiencia táctil integrada. Ayuda a la exactitud de las entradas al mostrar
una experiencia de superposición táctil de gran tamaño proporcionada por el sistema.
Teclado y control de juegos
A continuación, se muestra una demostración de cómo usar un <select multiple>
desde el teclado.
No se puede aplicar estilo a esta selección múltiple integrada, y solo se ofrece en formato compacto no es adecuado para presentar muchas opciones. Ve cómo realmente no puedes ver la amplitud de opciones en esa pequeña caja? Si bien puedes cambiar el tamaño, aún no se puede usar tanto como una barra lateral de casillas de verificación.
Marca
Ambos componentes estarán incluidos en el mismo elemento <form>
. Los resultados de
este formulario, ya sean casillas de verificación o una selección múltiple, se observarán y usarán para
filtrar la cuadrícula, pero también podrían enviarse a un servidor.
<form>
</form>
Componente de casillas de verificación
Los grupos de casillas de verificación deben estar dentro de
<fieldset>
elemento y se le dio un
<legend>
Cuando HTML se estructura de esta manera, los lectores de pantalla y
FormData hará lo siguiente:
automáticamente la relación de los elementos.
<form>
<fieldset>
<legend>New</legend>
… checkboxes …
</fieldset>
</form>
Con la agrupación en su lugar, agrega un <label>
y una <input type="checkbox">
de
cada uno de los filtros. Elegí unir el mío en un <div>
para que la propiedad gap
de CSS
puede espaciarlas de manera uniforme y mantener la alineación cuando las etiquetas tengan varias líneas.
<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>
Componente <select multiple>
Una de las funciones que casi no se usa del elemento <select>
es la siguiente:
multiple
Cuando el atributo se usa con un elemento <select>
, el usuario puede hacer lo siguiente:
elige muchos de la lista. Es como cambiar la interacción de una lista de radio
a una lista de casillas de verificación.
<form>
<select multiple="true" title="Filter results by category">
…
</select>
</form>
Para etiquetar y crear grupos dentro de un <select>
, usa el elemento
<optgroup>
y asignarle un atributo y un valor label
. Este elemento y este atributo
son similares a los elementos <fieldset>
y <legend>
.
<form>
<select multiple="true" title="Filter results by category">
<optgroup label="New">
…
</optgroup>
</select>
</form>
Ahora, agrega
<option>
elementos para el filtro.
<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>
Seguimiento de entradas con contadores para informar a la tecnología de accesibilidad
El estado
puesto
se utiliza en esta experiencia del usuario para hacer un seguimiento y mantener el recuento de
filtros para lectores de pantalla y otras tecnologías de asistencia. El video de YouTube
demuestra la función. La integración comienza con HTML y el atributo
role="status"
<div role="status" class="sr-only" id="applied-filters"></div>
Este elemento leerá en voz alta los cambios realizados en el contenido. Podemos actualizar el contenidos con CSS contadores a medida que los usuarios interactúan con las casillas de verificación. Para ello, primero necesitamos crear un contador con un nombre en un elemento superior de las entradas y el elemento de estado.
aside {
counter-reset: filters;
}
De forma predeterminada, el recuento será 0
, lo que es genial, nada es :checked
.
de forma predeterminada en este diseño.
Luego, para incrementar el contador recién creado, nos orientaremos a los elementos secundarios del
elemento <aside>
que son :checked
. A medida que el usuario cambia el estado de las entradas,
se contabilizará el contador de filters
.
aside :checked {
counter-increment: filters;
}
CSS ahora conoce el recuento general de la IU de la casilla de verificación y el rol de estado
elemento está vacío y en espera de valores. Dado que CSS mantiene el recuento en
la memoria,
counter()
la función permite acceder al valor desde pseudo
del elemento:
aside #applied-filters::before {
content: counter(filters) " filters ";
}
El código HTML del elemento de función de estado ahora anunciará "2 filtros" a una pantalla de lectura. Este es un buen comienzo, pero podemos hacerlo mejor, por ejemplo, compartir el recuento de resultados que actualizaron los filtros. Lo haremos desde JavaScript, ya que es fuera de lo que pueden hacer los contadores.
Emoción durante el período de prueba
El algoritmo de contadores funcionaba bien con CSS nesting-1, ya que pude colocar todos los lógica en un bloque. Se siente portátil y centralizada para leer y actualizar.
aside {
counter-reset: filters;
& :checked {
counter-increment: filters;
}
& #applied-filters::before {
content: counter(filters) " filters ";
}
}
Diseños
En esta sección, se describen los diseños entre los dos componentes. La mayoría de las los estilos de diseño son para el componente de la casilla de verificación de escritorio.
El formulario
Para optimizar la legibilidad y capacidad de lectura rápida para los usuarios, se le otorga al formulario
de 30 caracteres, lo que establece un ancho de línea óptico para cada
etiqueta de filtro. El formulario usa un diseño de cuadrícula y la propiedad gap
para espaciar los
conjuntos de campos específicos.
form {
display: grid;
gap: 2ch;
max-inline-size: 30ch;
}
El elemento <select>
La lista de etiquetas y casillas de verificación ocupa demasiado espacio en los dispositivos móviles. Por lo tanto, el diseño verifica el dispositivo apuntador principal del usuario para cambiarlo. la experiencia táctil.
@media (pointer: coarse) {
select[multiple] {
display: block;
}
}
Un valor de coarse
indica que el usuario no podrá interactuar con
con gran precisión a través
del dispositivo de entrada principal. En una
dispositivo móvil, el valor del puntero suele ser coarse
, como interacción principal
es táctil. En un dispositivo de escritorio, el valor del puntero suele ser fine
, ya que es común.
tener conectado un mouse u otro dispositivo de entrada de alta precisión.
Los conjuntos de campos
El estilo y el diseño predeterminados de una <fieldset>
con un <legend>
son únicos:
Por lo general, para espaciar los elementos secundarios, usaría la propiedad gap
, pero la propiedad
El posicionamiento de <legend>
dificulta la creación de un conjunto espaciado uniformemente.
de niños. En lugar de gap
, el hermano adyacente
selector y
margin-block-start
.
fieldset {
padding: 2ch;
& > div + div {
margin-block-start: 2ch;
}
}
De esta forma, se evita que <legend>
tenga su espacio ajustado solo al
<div>
niños.
La etiqueta de filtro y la casilla de verificación
Como elemento secundario directo de un <fieldset>
y dentro del ancho máximo del formulario
30ch
, el texto de la etiqueta puede ajustarse si es demasiado largo. Ajustar el texto es genial, pero
la desalineación entre el texto y la casilla de verificación no lo es. Flexbox es ideal para esto.
fieldset > div {
display: flex;
gap: 2ch;
align-items: baseline;
}
![Captura de pantalla que muestra cómo se alinea la marca de verificación con
la primera línea de texto en un escenario de ajuste de varias líneas.](https://web.dev/static/articles/building/a-multi-select-component/image/screenshot-showing-the-c-b135285ef7d8a.png?authuser=1&hl=es)
La cuadrícula animada
La animación de diseño se realiza con Isotope. R de alto rendimiento y potente para ordenar y filtrar de forma interactiva.
JavaScript
Además de ayudar a organizar una cuadrícula animada e interactiva, JavaScript se usa para pulir algunas asperezas.
Normalización de las entradas del usuario
Este diseño tiene una forma con dos formas diferentes de proporcionar información, y no debes serializa el igual. Sin embargo, con algo de JavaScript podemos normalizar los datos.
Elegí alinear la estructura de datos del elemento <select>
con las casillas de verificación agrupadas
en la nube. Para ello, una
input
el objeto de escucha de eventos se agrega al elemento <select>
, y en ese momento se
selectedOptions
de que estén asignados.
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
}, [])
})
Ahora, es seguro enviar el formulario o, en el caso de esta demostración, indicar a Isotope. sobre qué filtrar.
Cómo finalizar el elemento de rol de estado
El elemento solo cuenta y anuncia el recuento de filtros según la casilla de verificación.
interacción, pero sentí que era una buena idea compartir además la cantidad de
resultados y garantizar que también se cuenten las opciones del elemento <select>
.
Elección del elemento <select>
reflejada en counter()
En la sección de normalización de datos, ya se creó un objeto de escucha en la entrada. En al final de esta función la cantidad de filtros elegidos y la cantidad de resultados de esos filtros. Los valores se pueden pasar al elemento de rol de estado de esta forma.
let statusRoleElement = document.querySelector('#applied-filters')
statusRoleElement.style.counterSet = selectData.length
Resultados reflejados en el elemento role="status"
:checked
proporciona una forma integrada de pasar la cantidad de filtros elegidos a
el elemento de rol de estado, pero carece de visibilidad del número filtrado de resultados.
JavaScript puede observar la interacción con las casillas de verificación y, después de filtrar el
cuadrícula, agrega textContent
como lo hizo el elemento <select>
.
document
.querySelector('aside form')
.addEventListener('input', e => {
// isotope demo code
let filterResults = IsotopeGrid.getFilteredItemElements().length
document.querySelector('#applied-filters').textContent = `giving ${filterResults} results`
})
En conjunto, este trabajo completa el anuncio de “2 filtros que dan 25 resultados”.
Ahora, nuestra excelente experiencia con la tecnología de asistencia se entregará a todos los a los usuarios, cómo interactúan con él.
Conclusión
Ahora que sabes cómo lo hice, ¿cómo lo harías?‽ 🙂
Diversifiquemos nuestros enfoques y aprendamos todas las formas de desarrollar en la Web. Crear una demostración, twittearme vínculos y la agregaré. a la sección de remixes de la comunidad.
Remixes de la comunidad
Aún no hay nada para ver aquí.