Descripción general de los conceptos básicos para crear un componente de configuración con controles deslizantes y casillas de verificación
En esta publicación, compartiré ideas sobre cómo crear un componente de configuración para el web que sea responsiva, admita múltiples entradas de dispositivos y funcione en navegadores. Prueba la demostración.
Si prefieres ver videos o quieres obtener una vista previa de la IU/UX de lo que estamos creando, aquí tienes explicación más breve en YouTube:
Descripción general
He desglosado los aspectos de este componente en las siguientes secciones:
- Diseños
- Color
- Entrada de rango personalizado
- Entrada de casilla de verificación personalizada
- Consideraciones de accesibilidad
- JavaScript
Diseños
Esta es la primera demostración del desafío de la GUI de Cuadrícula de CSS. Esta es cada cuadrícula destacado con Herramientas para desarrolladores de Chrome para cuadrícula:
Solo para espacios
El diseño más común:
foo {
display: grid;
gap: var(--something);
}
A este diseño lo llamo "solo para espacios". porque solo usa una cuadrícula para agregar espacios entre los bloques.
Cinco diseños usan esta estrategia. A continuación, se muestran todos:
El elemento fieldset
, que contiene cada grupo de entrada (.fieldset-item
), usa gap: 1px
para
crear los bordes finos entre los elementos. No hay una solución de frontera complicada.
.grid { display: grid; gap: 1px; background: var(--bg-surface-1); & > .fieldset-item { background: var(--bg-surface-2); } }
.grid { display: grid; & > .fieldset-item { background: var(--bg-surface-2); &:not(:last-child) { border-bottom: 1px solid var(--bg-surface-1); } } }
Envoltura de cuadrícula natural
El diseño más complejo terminó siendo el diseño macro, el diseño lógico
sistema entre <main>
y <form>
.
Centrar contenido de unión
El Flexbox y la cuadrícula proporcionan capacidades a align-items
o
align-content
y, cuando se trata de unir elementos, el diseño de content
los alineamientos distribuirán el espacio
entre los elementos secundarios como grupo.
main {
display: grid;
gap: var(--space-xl);
place-content: center;
}
El elemento principal usa la alineación place-content: center
.
abreviatura para
que los elementos secundarios estén centrados vertical y horizontalmente en los diseños de una y dos columnas.
Mira en el video anterior cómo el "contenido" se mantenga centrado, aunque encaje el problema.
Repetir máx. mínimo de ajuste automático
<form>
usa un diseño de cuadrícula adaptable para cada sección.
Este diseño cambia de una a dos columnas en función del espacio disponible.
form {
display: grid;
gap: var(--space-xl) var(--space-xxl);
grid-template-columns: repeat(auto-fit, minmax(min(10ch, 100%), 35ch));
align-items: flex-start;
max-width: 89vw;
}
Esta cuadrícula tiene un valor diferente para row-gap
(--space-xl) que para column-gap
(--space-xxl)
para darle un toque personalizado al diseño adaptable. Cuando se apilan las columnas,
un espacio grande, pero no tan grande como si estuviéramos en una pantalla panorámica.
La propiedad grid-template-columns
usa 3 funciones de CSS: repeat()
, minmax()
y
min()
Una Kravets posee un excelente blog de diseño.
publicación sobre esto, llamándolo
RAM
Hay 3 adiciones especiales en nuestro diseño, si lo comparas con el de Una:
- Pasamos una función
min()
adicional. - Especificamos
align-items: flex-start
. - Hay un estilo
max-width: 89vw
.
La función adicional min()
está bien descrita por Evan Minto en su blog en el
post Cuadrícula de CSS intrínsecamente responsiva con minmax() y
min().
Te recomiendo que lo leas. La corrección de la alineación flex-start
consiste en
eliminar el efecto de estiramiento predeterminado, de modo que los elementos secundarios de este diseño no
deben tener alturas iguales, pueden tener alturas intrínsecas y naturales. El
En el video de YouTube, se incluye un desglose rápido de esta incorporación de alineación.
Vale la pena hacer un pequeño desglose de max-width: 89vw
en esta publicación.
Permíteme mostrarte el diseño con y sin el estilo aplicado:
¿Qué sucede? Cuando se especifica max-width
, proporciona contexto.
tamaño explícito o definitivo
tamaño de auto-fit
de diseño para saber cómo
muchas repeticiones puede caber en el espacio. Si bien parece obvio que el
sea de “ancho completo”, según las especificaciones de la cuadrícula de CSS, se debe especificar un tamaño definido o un tamaño máximo.
que se proporcione. Proporcioné un tamaño máximo.
Entonces, ¿por qué elegir 89vw
? Porque "funcionó" para mi diseño.
Yo y otros usuarios de Chrome investigan por qué un valor más razonable,
como 100vw
no es suficiente y si en realidad se trata de un error.
Espaciado
La mayor parte de la armonía de este diseño proviene de una paleta limitada de espaciado, 7 para ser exactos.
:root {
--space-xxs: .25rem;
--space-xs: .5rem;
--space-sm: 1rem;
--space-md: 1.5rem;
--space-lg: 2rem;
--space-xl: 3rem;
--space-xxl: 6rem;
}
El uso de estos flujos funciona muy bien con cuadrícula, CSS @nest y sintaxis de nivel 5
de @media. Este es un ejemplo del conjunto de estilos de diseño completamente <main>
.
main {
display: grid;
gap: var(--space-xl);
place-content: center;
padding: var(--space-sm);
@media (width >= 540px) {
& {
padding: var(--space-lg);
}
}
@media (width >= 800px) {
& {
padding: var(--space-xl);
}
}
}
Una cuadrícula con contenido centrado, con relleno moderado de forma predeterminada (como en los dispositivos móviles) Sin embargo, a medida que hay más espacio de viewport disponible, se extiende aumentando el relleno. ¡El CSS de 2021 se ve bastante bien!
¿Recuerdas el diseño anterior, "solo para la brecha"? Aquí hay una versión más completa de cómo se ven en este componente:
header {
display: grid;
gap: var(--space-xxs);
}
section {
display: grid;
gap: var(--space-md);
}
Color
Un uso controlado del color ayudó a que este diseño se destacara como expresivo pero, a la vez, mínimo. Lo hago de la siguiente manera:
:root {
--surface1: lch(10 0 0);
--surface2: lch(15 0 0);
--surface3: lch(20 0 0);
--surface4: lch(25 0 0);
--text1: lch(95 0 0);
--text2: lch(75 0 0);
}
Nombraré los colores de la superficie y del texto con números en lugar de nombres como
surface-dark
y surface-darker
porque, en una consulta de medios, invertiré la información
por lo que la luz y la oscuridad no serán significativas.
Los hago girar en una consulta de medios de preferencia de la siguiente manera:
:root {
...
@media (prefers-color-scheme: light) {
& {
--surface1: lch(90 0 0);
--surface2: lch(100 0 0);
--surface3: lch(98 0 0);
--surface4: lch(85 0 0);
--text1: lch(20 0 0);
--text2: lch(40 0 0);
}
}
}
Es importante echar un vistazo rápido al panorama y la estrategia generales antes profundizaremos en los detalles de la sintaxis de colores. Pero, como me adelantaba un poco, déjame retroceder un poco.
¿LCH?
Sin profundizar demasiado en la teoría del color, la LCH tiene una sintaxis orientada al ser humano, se adapta a cómo percibimos el color, no a cómo lo medimos con matemáticas (como 255). Esto le da una ventaja distintiva, ya que las personas pueden escribirlo más fácilmente y otras humanos estarán en sintonía con estos ajustes.
![Una captura de pantalla de la página web pod.link/csspodcast, en la que se muestra Color 2: Episodio de percepción](https://web.dev/static/articles/building/a-settings-component/image/a-screenshot-podlinkcs-a40f130bf81b8.png?authuser=9&hl=es)
Hoy, en esta demostración, enfoquémonos en la sintaxis y en los valores para aclarar y oscurecer. Veamos 1 superficie y 1 color del texto:
:root {
--surface1: lch(10 0 0);
--text1: lch(95 0 0);
@media (prefers-color-scheme: light) {
& {
--surface1: lch(90 0 0);
--text1: lch(40 0 0);
}
}
}
--surface1: lch(10 0 0)
se traduce en 10%
de luminosidad, 0 croma y 0 matiz: un
gris muy oscuro sin color. En la consulta de medios del modo claro,
se cambió a 90%
con --surface1: lch(90 0 0);
. Y esa es la esencia de la
de administración de amenazas. Comienza cambiando la luminosidad entre los 2 temas, manteniendo el
las relaciones de contraste que requiere el diseño o lo que puede mantener la accesibilidad.
La ventaja con lch()
es que la ligereza está orientada al ser humano, y podemos sentir
bueno acerca de un cambio de %
, que será perceptual y coherente
que %
es diferente. hsl()
, por ejemplo, no es tan
confiables.
Hay más que
más información sobre
espacios de color y lch()
si te interesa. ¡Próximamente!
En este momento, el CSS no puede acceder a estos colores. Permítanme repetir: No tenemos acceso a un tercio de los colores en los modelos más modernos. monitores. Y no son todos los colores, sino los colores más vívidos que puede mostrar la pantalla. Nuestros sitios web están desgastados porque el hardware de los monitores evolucionó más rápido que las especificaciones de CSS y las implementaciones del navegador.
Lea Verou
Controles de forma adaptables con esquema de colores
Muchos navegadores incluyen controles de tema oscuro, actualmente Safari y Chromium, debes especificar en CSS o HTML que tu diseño los usa.
Lo anterior demuestra el efecto de la propiedad desde el panel Estilos de Herramientas para desarrolladores. La demostración usa la etiqueta HTML, que en mi opinión es, por lo general, una mejor ubicación:
<meta name="color-scheme" content="dark light">
Obtén toda la información al respecto en este color-scheme
artículo de Thomas
Steiner Hay mucho más por ganar
que las entradas
de casillas de verificación oscuras.
CSS accent-color
Hubo recientes
actividad alrededor de
accent-color
para los elementos de formulario, por lo que es un estilo de CSS único que puede cambiar la
el color de tono que se usa en el elemento de entrada del navegador. Obtenga más información aquí en
GitHub. Lo incluí en mi
estilos de este componente. Como los navegadores lo admiten, mis casillas de verificación aparecerán
más el tema con los que se destacan
rosa y púrpura.
input[type="checkbox"] {
accent-color: var(--brand);
}
Resalta los colores con degradados fijos y enfoque dentro
El color se destaca más cuando se usa con moderación, y es una de las formas es mediante interacciones coloridas de la IU.
Hay muchas capas de comentarios e interacción sobre la IU en el video anterior, que ayudan a darle personalidad a la interacción al:
- Resaltar el contexto
- Cómo proporcionar comentarios en la IU sobre "qué tan lleno" el valor está en el rango.
- Proporcionar comentarios a la IU en los que se indique que un campo acepta entradas
Para proporcionar comentarios cuando se interactúa con un elemento, CSS utiliza el
:focus-within
seudoclase para cambiar el aspecto de varios elementos,
.fieldset-item
, es muy interesante:
.fieldset-item {
...
&:focus-within {
background: var(--surface2);
& svg {
fill: white;
}
& picture {
clip-path: circle(50%);
background: var(--brand-bg-gradient) fixed;
}
}
}
Cuando uno de los elementos secundarios de este elemento tiene foco adentro:
- Al fondo
.fieldset-item
se le asigna un color de superficie de mayor contraste. - El elemento
svg
anidado se rellena de color blanco para ofrecer un mayor contraste. - El
<picture>
clip-path
anidado se expande a un círculo completo y el el fondo se rellena con el gradiente fijo brillante.
Período personalizado
Con el siguiente elemento de entrada HTML, te mostraré cómo personalicé su apariencia:
<input type="range">
Este elemento tiene 3 partes que debemos personalizar:
Estilos de elementos de rango
input[type="range"] {
/* style setting variables */
--track-height: .5ex;
--track-fill: 0%;
--thumb-size: 3ex;
--thumb-offset: -1.25ex;
--thumb-highlight-size: 0px;
appearance: none; /* clear styles, make way for mine */
display: block;
inline-size: 100%; /* fill container */
margin: 1ex 0; /* ensure thumb isn't colliding with sibling content */
background: transparent; /* bg is in the track */
outline-offset: 5px; /* focus styles have space */
}
Las primeras líneas de CSS son las partes personalizadas de los estilos etiquetarlos claramente ayuda. El resto de los estilos son principalmente estilos restablecidos, para proporcionarán una base consistente para crear las partes complicadas del componente.
Estilos de pista
input[type="range"]::-webkit-slider-runnable-track {
appearance: none; /* clear styles, make way for mine */
block-size: var(--track-height);
border-radius: 5ex;
background:
/* hard stop gradient:
- half transparent (where colorful fill we be)
- half dark track fill
- 1st background image is on top
*/
linear-gradient(
to right,
transparent var(--track-fill),
var(--surface1) 0%
),
/* colorful fill effect, behind track surface fill */
var(--brand-bg-gradient) fixed;
}
El truco para esto es "revelar" el color de relleno vibrante. Esto se hace con el con gradiente de parada fija en la parte superior. El gradiente es transparente hasta el porcentaje de relleno y, luego, que usa el color de superficie del recorrido sin rellenar. Detrás de esa superficie vacía, hay una a todo color, esperando que lo revele la transparencia.
Estilo de relleno del segmento
Mi diseño requiere JavaScript para mantener el estilo de relleno. Hay son estrategias exclusivas de CSS, pero requieren que el elemento miniatura tenga la misma altura. la canción, y no pude encontrar la armonía dentro de esos límites.
/* grab sliders on page */
const sliders = document.querySelectorAll('input[type="range"]')
/* take a slider element, return a percentage string for use in CSS */
const rangeToPercent = slider => {
const max = slider.getAttribute('max') || 10;
const percent = slider.value / max * 100;
return `${parseInt(percent)}%`;
};
/* on page load, set the fill amount */
sliders.forEach(slider => {
slider.style.setProperty('--track-fill', rangeToPercent(slider));
/* when a slider changes, update the fill prop */
slider.addEventListener('input', e => {
e.target.style.setProperty('--track-fill', rangeToPercent(e.target));
})
})
Creo que esto representa una buena mejora visual. El control deslizante funciona muy bien sin
En JavaScript, no se requiere el prop --track-fill
; simplemente no tendrá un
relleno si no está presente. Si JavaScript está disponible, propaga el archivo
del usuario y, al mismo tiempo, se observan los cambios del usuario, y se sincroniza la propiedad personalizada con
el valor.
Este es un gran
publicación en
Trucos de CSS de Ana
Tudor, que muestra una solución de CSS únicamente para
relleno de pista. También encontré esto
El elemento range
es muy inspirador.
Estilos de miniatura
input[type="range"]::-webkit-slider-thumb {
appearance: none; /* clear styles, make way for mine */
cursor: ew-resize; /* cursor style to support drag direction */
border: 3px solid var(--surface3);
block-size: var(--thumb-size);
inline-size: var(--thumb-size);
margin-top: var(--thumb-offset);
border-radius: 50%;
background: var(--brand-bg-gradient) fixed;
}
La mayoría de estos estilos están diseñados para crear un bonito círculo.
De nuevo, se ve el gradiente de fondo fijo que unifica
colores dinámicos de las miniaturas, los seguimientos y los elementos SVG asociados.
Separé los estilos de la interacción para aislar el box-shadow
.
técnica que se utiliza para destacar al colocar el cursor sobre un elemento:
@custom-media --motionOK (prefers-reduced-motion: no-preference);
::-webkit-slider-thumb {
…
/* shadow spread is initally 0 */
box-shadow: 0 0 0 var(--thumb-highlight-size) var(--thumb-highlight-color);
/* if motion is OK, transition the box-shadow change */
@media (--motionOK) {
& {
transition: box-shadow .1s ease;
}
}
/* on hover/active state of parent, increase size prop */
@nest input[type="range"]:is(:hover,:active) & {
--thumb-highlight-size: 10px;
}
}
El objetivo era mostrar una representación visual animada y fácil de administrar para los comentarios de los usuarios. Al usar una sombra de cuadro, puedo evitar activar diseño con el efecto. Hago esto creando una sombra que no esté desenfocada y coincida con la forma circular de la pulgar. Luego, cambio y cambio el tamaño de dispersión al colocar el cursor sobre ellos.
Si solo el efecto de destacar fuera tan fácil en las casillas de verificación...
Selectores entre navegadores
Descubrí que necesitaba estos selectores -webkit-
y -moz-
para lograr varios navegadores
coherencia:
input[type="range"] {
&::-webkit-slider-runnable-track {}
&::-moz-range-track {}
&::-webkit-slider-thumb {}
&::-moz-range-thumb {}
}
Casilla de verificación personalizada
Con el siguiente elemento de entrada HTML, te mostraré cómo personalicé su apariencia:
<input type="checkbox">
Este elemento tiene 3 partes que debemos personalizar:
Elemento de casilla de verificación
input[type="checkbox"] {
inline-size: var(--space-sm); /* increase width */
block-size: var(--space-sm); /* increase height */
outline-offset: 5px; /* focus style enhancement */
accent-color: var(--brand); /* tint the input */
position: relative; /* prepare for an absolute pseudo element */
transform-style: preserve-3d; /* create a 3d z-space stacking context */
margin: 0;
cursor: pointer;
}
Los estilos transform-style
y position
se preparan para el seudoelemento que presentaremos más adelante.
para darle estilo al resaltado. De lo contrario, es principalmente
y cosas insignificantes. Me gusta que el cursor sea puntero, me gusta
de contorno, las casillas de verificación predeterminadas son demasiado pequeñas y, si accent-color
es
compatible, agrega
en el esquema de colores de la marca.
Etiquetas de casillas de verificación
Es importante proporcionar etiquetas para las casillas de verificación por 2 motivos. La primera es representan para qué se usa el valor de la casilla de verificación, para responder "¿para qué?" En segundo lugar, para la UX, los usuarios web están acostumbrados a interactuar con casillas de verificación a través de sus etiquetas asociadas.
<input type="checkbox" id="text-notifications" name="text-notifications" >
<label for="text-notifications"> <h3>Text Messages</h3> <small>Get notified about all text messages sent to your device</small> </label>
En la etiqueta, coloca un atributo for
que dirija a una casilla de verificación por ID: <label for="text-notifications">
. En la casilla de verificación, duplica el nombre y el ID para
asegúrate de que se encuentre con varias herramientas y tecnología, como un mouse o un lector de pantalla:
<input type="checkbox" id="text-notifications" name="text-notifications">
:hover
, :active
y otros servicios vienen gratis con la conexión, lo que aumenta el
formas en que se puede interactuar con tu formulario.
Casilla de verificación destacada
quiero mantener la coherencia de mis interfaces, y el elemento deslizante tiene un buen
miniatura destacada que me gustaría usar con la casilla de verificación. La miniatura era
usar box-shadow
y su propiedad spread
para escalar una sombra y
fuera de servicio. Sin embargo, ese efecto no funciona aquí porque las casillas de verificación son, y deben,
ser, cuadrado.
pude lograr el mismo efecto visual con un seudoelemento, y una lamentable cantidad de CSS complejo:
@custom-media --motionOK (prefers-reduced-motion: no-preference);
input[type="checkbox"]::before {
--thumb-scale: .01; /* initial scale of highlight */
--thumb-highlight-size: var(--space-xl);
content: "";
inline-size: var(--thumb-highlight-size);
block-size: var(--thumb-highlight-size);
clip-path: circle(50%); /* circle shape */
position: absolute; /* this is why position relative on parent */
top: 50%; /* pop and plop technique (https://web.dev/centering-in-css#5-pop-and-plop) */
left: 50%;
background: var(--thumb-highlight-color);
transform-origin: center center; /* goal is a centered scaling circle */
transform: /* order here matters!! */
translateX(-50%) /* counter balances left: 50% */
translateY(-50%) /* counter balances top: 50% */
translateZ(-1px) /* PUTS IT BEHIND THE CHECKBOX */
scale(var(--thumb-scale)) /* value we toggle for animation */
;
will-change: transform;
@media (--motionOK) { /* transition only if motion is OK */
& {
transition: transform .2s ease;
}
}
}
/* on hover, set scale custom property to "in" state */
input[type="checkbox"]:hover::before {
--thumb-scale: 1;
}
Crear un seudoelemento circular es una tarea sencilla, pero colocarlo detrás del elemento al que se adjuntó fue más difícil. Esto es antes y después de solucionarlo:
Definitivamente es una microinteracción, pero para mí es importante
y mantener la coherencia. La técnica de escalamiento de animación es la misma que usamos en
en otros lugares. Configuramos una propiedad personalizada con un valor nuevo y permitimos que CSS realice la transición
según las preferencias de movimiento. La función clave aquí es translateZ(-1px)
. El
el elemento superior creó un espacio 3D y este seudoelemento secundario lo aprovechó
y se vuelve ligeramente atrás en el espacio z.
Accesibilidad
El video de YouTube ofrece una gran demostración del uso del mouse, el teclado y interacciones de los lectores de pantalla para este componente de configuración. Mencionaré algunos de los haz clic aquí para conocer los detalles.
Opciones del elemento HTML
<form>
<header>
<fieldset>
<picture>
<label>
<input>
Cada uno de ellos contiene sugerencias para la herramienta de navegación del usuario. Algunos elementos ofrecen sugerencias de interacción, algo de interactividad de conexión y otras ayudan a dar forma árbol de accesibilidad por el que navega un lector de pantalla.
Atributos HTML
Podemos ocultar los elementos que los lectores de pantalla no necesitan en este caso, el icono al lado del deslizador:
<picture aria-hidden="true">
El video anterior demuestra el flujo del lector de pantalla en Mac OS. ¿Observas cómo la entrada el enfoque se mueve directamente de un control deslizante al siguiente. Esto se debe a que hemos ocultado el icono que puede haber sido una parada en el camino hacia el siguiente control deslizante. Sin este , un usuario tendría que detenerse, escuchar y avanzar más allá de la imagen que que tal vez no puedan ver.
El SVG es un montón de matemáticas, por ejemplo, agreguemos un elemento <title>
para colocar el cursor sobre el elemento.
título y un comentario legible sobre la creación de los cálculos:
<svg viewBox="0 0 24 24">
<title>A note icon</title>
<path d="M12 3v10.55c-.59-.34-1.27-.55-2-.55-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4V7h4V3h-6z"/>
</svg>
Aparte de eso, usamos HTML claramente marcado para que el formulario no tenga errores muy bien en mouse, teclado, controles de videojuegos y lectores de pantalla.
JavaScript
Ya expliqué cómo se administraba el color de relleno de los segmentos desde JavaScript.
Ahora, veamos el JavaScript relacionado con <form>
:
const form = document.querySelector('form');
form.addEventListener('input', event => {
const formData = Object.fromEntries(new FormData(form));
console.table(formData);
})
Cada vez que se interactúa con el formulario y se lo cambia, la consola lo registra como un objeto en una tabla para facilitar su revisión antes de enviarlo a un servidor.
Conclusión
Ahora que sabes cómo lo hice, ¿cómo lo harías? Esto hace que sea divertido de la arquitectura de componentes de componentes en la nube. ¿Quién hará la 1a versión con ranuras en su framework favorito? 🙂
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 Remixes de la comunidad que está más abajo.