Esta publicación es la tercera de una serie sobre el poder de CSS.
Serie de artículos:
- Colorear fondos SVG
- Menús desplegables
- Estilo lógico basado en el número de elementos dados (esta publicación)
¿Sabías que CSS es Turing completo? ¿Sabías que puedes usarlo para hacer un estilo lógico bastante serio? ¡Bien tu puedes! No tiene que configurar todas sus reglas de estilo basadas en lógica en JavaScript, ni siquiera tiene que usar JavaScript para configurar las clases contra las que está diseñando. En muchos casos, CSS puede manejar eso por sí mismo. Todavía estoy descubriendo nuevos trucos de CSS todos los días, y me hace amarlo aún más.
Este año comencé a trabajar en Bustle Digital Group. En los medios, como ocurre con muchos productos, el equipo de ingeniería crea una plataforma que debe ser compatible con todos los casos de uso. Nuestro CMS proporciona capacidades para que los autores y editores creen artículos, además de seleccionar páginas y controlar la inyección de anuncios.
A diferencia de trabajar con un sitio estático, el equipo de ingeniería no tiene control total sobre qué datos provienen del usuario, por lo que se deben tomar decisiones de diseño y reglas de gobierno para una buena experiencia del usuario. Algunos de estos escenarios a los que nos hemos enfrentado en el espacio de los medios digitales realmente me inspiraron a buscar formas de usar CSS para resolver esos desafíos de la interfaz de usuario, y fue entonces cuando las soluciones que involucran esta idea realmente llegaron a mi periferia.
¡Así que echemos un vistazo a algunos ejemplos!
Ejemplo 1: Estados binarios
Un selector a menudo olvidado y muy útil es el :empty
pseudoselector. Le permite diseñar elementos en función de si contienen contenido o no. ¡Hola estados vacíos! Los estados vacíos son una excelente manera de llegar a sus usuarios y mostrar personalidad en su aplicación, y puede inyectar esa personalidad directamente desde su CSS.
En este ejemplo, tenemos cualquier lista de un usuario. Pueden ser publicaciones que el usuario ha publicado (como autor) o artículos marcados que un usuario ha guardado (como editor). Los casos de uso son realmente infinitos aquí. En lugar de inyectar JavaScript, podemos usar pseudo elementos para inyectar imágenes, estilos y texto:
Los dibujos ilustran estilos aplicados condicionalmente basados en ningún elemento (izquierda) versus elementos mostrados (derecha) en la lista.
Nuestra solución aquí son solo tres líneas de código:
div:empty:after {
content: 'oh no...';
}
También puede agregar un :before
pseudo elemento para inyectar imágenes o cualquier otro contenido que desee. Alternativamente, el :not
pseudoselector se puede utilizar en combinación con :empty
para crear un :not(:empty)
rige y aplica estilo a todos los elementos que no están vacíos y, por lo tanto, contienen elementos secundarios.
Vea Pen Empty States de Una Kravets (@una) en CodePen.
Nota: Esta demostración es solo para fines de visualización. No se recomienda poner contenido en pseudo elementos con fines de accesibilidad. Puede utilizar la misma técnica de segmentación :empty
o :not(:empty)
elementos para aplicar estilos a los elementos secundarios que son más accesibles para los lectores de pantalla.
Selección numérica avanzada
Ese fue un buen ejemplo de bola suave, pero podemos ser mucho más complejos que esta elección binaria de elementos secundarios en CSS, y para hacer esto, usaremos el :nth-child
pseudoselector! Programar Plustiene una gran herramienta para ayudarte a probar y jugar con el :nth-child
selección, y realmente puede ser útil como le mostrarán algunos de los ejemplos.
Pero antes de entrar en eso, ¿cómo funciona exactamente esto?
El meollo del código es este, con div
sustituyendo a cualquier elemento hermano dado, y x
reemplazando el número que estamos usando para determinar las rupturas de estilo:
div:first-child:nth-last-child(n + x),
div:first-child:nth-last-child(n + x) ~ div
Utilizando :nth-last-child
En lugar de usar :nth-child
porque la selección nos permite comenzar desde el final de una serie en lugar de desde el principio. cuando seleccionamos :nth-last-child(n + x)
, estamos seleccionando el x
valor a partir del final. Si x = 3
que se vería así:
ilustración de cómo :nth-last-child(3)
selecciona el tercer elemento del final de la lista.
Ahora, si queremos contar valores de n + 3
, estamos seleccionando todos los elementos que coinciden 3 o más de 3 desde el final. Empezando con n = 0
(lo que significaría 0 + 3
, y el cuarto elemento es el primero desde el final después de 3
). Se parece a esto:
ilustración de cómo :nth-last-child(n+3)
selecciona todos los elementos que coinciden con 3 o más de 3 desde el final.
Este es un gran comienzo, pero la idea aquí es diseñar condicionalmente todos los elementos en función de cuántos existen. Por lo tanto, debemos trabajar con estas condiciones pero seleccionar todos los elementos. Comencemos seleccionando el primer elemento. Necesitamos hacer una condición para ver si toda la selección califica para el estilo y luego comenzar con ese primer hermano:
UH oh. Solo tenemos el primer elemento seleccionado en este punto, y queremos seleccionar todos los elementos. Afortunadamente, podemos usar el súper práctico selector de hermanos adyacentes (~
) ¡para eso!
Ajustando nuestro último ejemplo a :first-child:last-child(n + 3) ~ *
selecciona todos los elementos excepto el primero como queremos.
Bueno, ahora puede ver que todos los elementos que siguen al primer elemento están seleccionados, pero nos falta el primero, por lo que necesitamos usar dos selectores y, por lo tanto, la respuesta final es:
La combinación de los dos ejemplos anteriores seleccionará todos los elementos de la lista.
Ejemplo 2: formato de lista
Digamos que desea enumerar algunos créditos al final de un artículo. Tiene espacio para llenar, y la mayoría de los artículos tienen una pequeña cantidad de créditos, pero existen excepciones que tienen un alto valor de producción y mucha gente involucrada en su elaboración. Queremos asegurarnos de que ambas sean buenas experiencias visuales y que podamos hacerlo solo con CSS.
Este es el plan: si hay cuatro créditos o menos, enumérelos en formato de viñetas. Deje que ocupen espacio vertical para llenar el bloque apropiadamente. Una vez que tengamos cinco o más créditos en la lista, cambiemos esa lista a un formato horizontal para que no sea demasiado abrumador para el lector. ¡Esta es una pequeña caja de créditos después de todo!
Ilustraciones de una lista desordenada vertical (izquierda) y una lista horizontal separada por punto y coma (derecha).
Podemos verificar la cantidad de elementos que tenemos disponibles y diseñarlos como block
elementos hasta que lleguemos a nuestro límite. En ese momento, cambiaremos a inline
estilo y agregue un pseudo elemento para dividir visualmente los datos.
/* 5 or more items display next to each other */
li:first-child:nth-last-child(n + 5),
li:first-child:nth-last-child(n + 5) ~ li {
display: inline;
}
/* Adds semicolon after each item except the last item */
li:first-child:nth-last-child(n + 5) ~ li::before {
content: ';';
margin: 0 0.5em 0 -0.75em;
}
:nth-first-child:nth-last-child(n + 5)
nos permite afirmar: “comience con el primer hijo y aplique el estilo a ese hijo y a todos los hermanos posteriores si el hijo original coincide con cinco o más hermanos”. ¿Es confuso? Bueno, funciona.
li:first-child:nth-last-child(n + 5)
selecciona el primer elemento de la lista y li:first-child:nth-last-child(n + 5) ~ li
selecciona cada elemento de la lista después del inicial.
Vea el Pen vrQBMv de Una Kravets (@una) en CodePen.
Ejemplo 3: carrusel condicional
Usando esta técnica, diseñemos un carrusel para que responda. En un tamaño grande, desea que esté centrado en el medio de la página cuando tiene tres elementos dentro. Pero cuando tenga suficientes elementos para llenar la pantalla horizontalmente, deja que se alinee a la izquierda para que el usuario pueda deslizarlo.
Ilustraciones de un carrusel con tres elementos (izquierda) y más de tres elementos (derecha).
Lo que podemos hacer aquí es estirar los elementos para que se ajusten a la pantalla a menos que tengamos demasiados elementos y requieran un desbordamiento. En ese momento, aprovechemos este desbordamiento y mostremos realmente las capacidades del carrusel señalando la capacidad de desplazamiento con flechas y aumentando el margen entre los elementos. Además de eso, agreguemos un botón de flecha adhesiva para mostrar que podemos desplazarnos por los elementos y vincular eventos de JavaScript para hacer que el carrusel se desplace.
Podemos hacer lo mismo que arriba en cuanto a la técnica, pero también usaremos solo el first-child
para detectar un arrow
div y mostrarlo en la interfaz de usuario. El HTML se vería así:
<ul>
<li>
<div class="box">1</div>
</li>
<li>
<div class="box">2</div>
</li>
...
<button class="arrow">——></button>
</ul>
No es ideal tener elementos vacíos en el DOM, pero trabaja conmigo. Sigue siendo un truco inteligente. Le daremos estilo a .arrow
botón para que sea invisible para el DOM y para los lectores de pantalla con visibility: hidden
a menos que se apliquen las condiciones (en este caso, si hay cuatro o más elementos presentes). En ese momento le daremos una pantalla visible (display: block
), estilo y colóquelo apropiadamente:
li:first-child:nth-last-child(n + 5) ~ .arrow {
display: block;
position: sticky;
...
}
Vea la alineación de Pen Box por Una Kravets (@una) en CodePen.
¡Más información!
En mi investigación para esta publicación, descubrí una excelente publicación de Heydon Pickering sobre esta técnica, llamada Consultas de cantidad, y otro ejemplo de lea verou! En el hilo de comentarios de la publicación de Heydon, pablo irlandés señala que esta es una forma más lenta de seleccionar elementos, por lo que tal vez la use con precaución.