Listas CSS, marcadores y contadores
Publicado: 2022-03-10 Las listas en CSS tienen propiedades particulares que nos dan el estilo de lista estándar que esperamos. Una lista desordenada gana una viñeta de lista, del tipo disc
, y las listas ordenadas se numeran. Mi interés en explorar listas con más detalle provino de un trabajo que hice para documentar el pseudo-elemento ::marker
para MDN. Este pseudoelemento se incluye en Firefox 68 y se lanzará hoy . Con el pseudo elemento ::marker
disponible para nosotros, podemos comenzar a hacer algunas cosas interesantes con las listas, y en este artículo explicaré más.
Deconstruir una lista
Es posible que no haya pensado mucho en las listas, aunque las usamos con frecuencia en nuestro marcado. Muchas cosas se pueden marcar lógicamente como una lista. Si bien las instrucciones paso a paso o los elementos clasificados pueden describirse naturalmente mediante una lista ordenada <ol>
, muchas cosas en un diseño pueden describirse mediante una lista desordenada <ul>
. Un uso muy común del elemento, por ejemplo, es marcar la navegación, ya que es una lista de destinos en el sitio. Para nuestra exploración, comencemos por averiguar exactamente qué es una lista en CSS.
Al igual que con muchas cosas en CSS, las listas tienen algunos valores iniciales que se les aplican. Estos valores los hacen parecer una lista. Estos valores especiales comienzan con la información de que un elemento de lista tiene la propiedad de display
con un valor de list-item
. Esto crea un cuadro a nivel de bloque, con un cuadro de marcador adicional. El cuadro de marcador es donde se agrega la viñeta o el número de la lista.
Las listas se definieron desde el principio en CSS, y gran parte de la definición de listas, tal como las usamos hoy en día, proviene de CSS2. La especificación CSS2 describe un elemento de lista de la siguiente manera:
“Un elemento condisplay: list-item
genera un cuadro de bloque principal para el contenido del elemento y, dependiendo de los valores delist-style-type
ylist-style-image
, posiblemente también un cuadro de marcador como indicación visual de que el elemento es un elemento de la lista.”
El cuadro de bloque principal es el cuadro principal del elemento y contiene todos los elementos secundarios, ya que un elemento de lista puede contener otras marcas. El cuadro marcador se coloca entonces con respecto a este cuadro principal. La especificación continúa detallando el hecho de que cualquier color de fondo estará solo detrás de este cuadro principal, y no del marcador. También que el marcador se puede establecer en uno de un rango de valores predefinidos:
-
disc
-
circle
-
square
-
decimal
-
decimal-leading-zero
-
lower-roman
-
upper-roman
-
lower-greek
-
lower-latin
-
upper-latin
-
armenian
-
georgian
-
lower-alpha
-
upper-alpha
-
none
-
inherit
La especificación de visualización de nivel 3 define display: list-item
junto con los otros valores posibles para la propiedad de display
. Hace referencia a CSS 2.1, al igual que muchas propiedades y valores de CSS que provienen de CSS2, pero describe la palabra clave list-item
como "haciendo que el elemento genere un pseudo-elemento de ::marker
".
La especificación de nivel 3 también presenta la capacidad de crear un elemento de lista en línea con la sintaxis de dos valores que se usa display: inline list-item
. Esto aún no está implementado por los navegadores.
Creación de cuadros de marcadores en elementos que no están en la lista
Al igual que con otros valores de display
, es perfectamente válido dar a cualquier elemento HTML un tipo de visualización de elemento de list-item
(si desea generar un pseudoelemento ::marker
en el elemento). Esto no hará que el elemento se convierta semánticamente en un elemento de la lista, sino que solo se mostrará visualmente como un elemento de la lista y, por lo tanto, podrá tener un ::marker
. Cuando discutamos el pseudo-elemento ::marker
a continuación, descubrirá algunos casos en los que display: list-item
puede ser útil.
El CSS enumera la especificación de nivel 3: ::marker
y contadores
La especificación display
amplía y aclara la definición de listas que encontramos en CSS2, sin embargo, también hay una especificación que define el comportamiento de la lista en detalle: la Especificación de listas CSS Nivel 3. Como el comportamiento básico de los elementos de la lista se define en display
, este la especificación detalla el cuadro de marcador generado cuando algo tiene display: list-item
junto con los contadores que se usan de forma predeterminada cada vez que crea una lista ordenada. Hay algunas funciones potencialmente útiles a las que se accede a través de estas funciones.
El ::marker
Pseudo-Elemento
El pseudoelemento ::marker
le permite apuntar al marcador de la lista, independientemente del contenido del elemento de la lista. Esto no era posible en versiones anteriores de CSS, por lo tanto, si cambiaba el color o el tamaño de fuente de ul
o li
, también cambiaría el color y el tamaño de fuente de los marcadores. Para hacer algo tan aparentemente simple como tener viñetas de lista de diferentes colores que el texto, implicaría envolver el contenido del elemento de la lista en un lapso (o usar una imagen para el marcador).
ul { color: #00b7a8; } ul span { color #333; }
Con el pseudo elemento ::marker
, lo más simple que puede intentar es tener una viñeta diferente al color del texto, lo que significa que en lugar del código en el ejemplo anterior, puede usar:
ul { color: #333; } ul ::marker { color: #00b7a8; }
También es posible que desee utilizar un tamaño y font-family
diferentes para la numeración en una lista ordenada.
ol ::marker { font-size: 200%; color: #00b7a8; font-family: "Comic Sans MS", cursive, sans-serif; }
Puede ver todo esto en un navegador compatible usando mi ejemplo de CodePen:
Puede usar el pseudoelemento ::marker
en elementos que no son de lista. En el siguiente código, he establecido un encabezado para display: list-item
. Esto le da una viñeta y, por lo tanto, un cuadro de ::marker
para apuntar.
He cambiado la viñeta para usar un emoji:
h1 { display: list-item; } h1::marker { content: ""; }
En el ejemplo anterior, he usado contenido generado en las reglas para el marcador. Solo un pequeño subconjunto de propiedades CSS está disponible para usar en ::marker
. Estos incluyen propiedades de fuente y color, sin embargo, también incluyen la propiedad de content
, para incluir contenido generado.
La adición de content
como propiedad permitida para ::marker
es reciente, sin embargo, está incluida en la implementación de Firefox. La inclusión significa que puede hacer cosas como incluir una cadena de texto en un ::marker
. También plantea posibilidades adicionales para el formato de marcadores cuando combina el uso de contadores con ::marker
.
Compatibilidad con navegadores y respaldos
Para los navegadores que no admiten el pseudoelemento ::marker
, el respaldo es el marcador normal que se habría mostrado de todos modos. Desafortunadamente, actualmente no podemos usar Consultas de funciones para detectar la compatibilidad con selectores como este pseudoelemento en este momento, aunque ha surgido un problema sobre agregar esto a la especificación. Esto significa que no puede bifurcar su código para hacer una cosa cuando tiene soporte y otra cosa si no lo tiene. En la mayoría de los casos, volver al marcador regular será una solución razonable.
Contadores
Las listas ordenadas tienen numeración de lista, algo que se logra mediante un contador CSS. Por lo tanto, la especificación de listas CSS también describe estos contadores. Podemos acceder y crear contadores nosotros mismos que, combinados con el pseudo-elemento ::marker
, pueden brindarnos algunas funciones útiles. Estos contadores también se pueden usar en contenido generado normal (sin ::marker
).
Si tengo una lista numerada de pasos (y me gustaría escribir "Paso 1", "Paso 2", etc.), puedo hacerlo usando el contenido generado en mi marcador y agregando el contador list-item
, esto representa el contador integrado:
::marker { content: "Step " counter(list-item) ": "; }
Contadores anidados
Si tiene listas anidadas, una forma común de numerarlas es tener el elemento de nivel superior como un número entero, (1), luego los elementos secundarios como (1.1, 1.2) y sus elementos secundarios (1.1.1, 1.1.2), y así. Puede lograr esto utilizando más funciones de contadores.
Cuando anida listas HTML, terminará con varios contadores del mismo nombre, anidados unos dentro de otros. Se puede acceder al nido de contadores usando la función counters()
.
En el código a continuación, estoy usando counters()
para formatear mis marcadores de lista como se describe arriba. El primer argumento para counters()
es el nombre del contador a usar. Estoy usando el contador list-item
incorporado. El segundo argumento es una cadena; esto es lo que se concatenará entre los contadores de salida (estoy usando un .
). Finalmente, agrego un :
fuera de la función de contador pero dentro del valor del content
para que la salida de mi contador esté separada del contenido por dos puntos.
::marker { content: counters(list-item,'.') ':'; color: #00b7a8; font-weight: bold; }
Esto me da la salida como en la imagen. Si está utilizando un navegador que admite ::marker
y contadores, puede verlo funcionando en el ejemplo de CodePen: intente cambiar la cadena de un archivo .
a otra cosa para ver cómo eso cambia la salida.
¿Cuál es la diferencia entre counter()
y counters()
?
La función counter()
que usamos en el primer ejemplo para escribir nuestros pasos usa solo el contador más interno. Por lo tanto, en la situación en la que tiene un conjunto de listas anidadas, escribirá el contador relacionado con el nivel en el que se encuentra actualmente.
La función counters()
esencialmente escribe toda la rama y le brinda la oportunidad de concatenar una cadena entre contadores en la rama. Entonces, si tiene un elemento de lista con un contador de 2
(que es parte de una lista anidada dentro de un elemento de lista con un contador de 4
), entonces la rama contiene:
-
4
-
2
Puede generar esto como 4.2
en el marcador usando:
::marker { content: counters(list-item,'.'); }
Contadores en otros elementos
Los contadores se pueden usar en cosas que no son listas, ya sea para generar un marcador, en cuyo caso el elemento deberá tener display: list-item
, o para generar contenido generado regularmente. Los contadores se utilizan ampliamente en la producción de libros, para permitir que la numeración de capítulos y figuras sume otras cosas. No hay razón para no adoptar un enfoque similar en la web, en particular para artículos más largos.
Las propiedades CSS definidas en la especificación de Listas CSS que tratan con estos contadores son:
-
counter-set
-
counter-reset
-
counter-increment
Para ver cómo funcionan fuera de las listas, podemos ver un ejemplo del uso de contadores para numerar los encabezados de un documento.
Lo primero que debo hacer es crear un contador para los encabezados en el elemento del cuerpo, listo para usar. Estoy usando la propiedad counter-reset
para hacer esto. Las propiedades counter-reset
y counter-set
son muy similares. La propiedad counter-reset
creará un nuevo contador si aún no existe un contador con el nombre especificado, pero también creará contadores anidados como se describe anteriormente si existe un contador con ese nombre. La propiedad counter-set
solo creará un nuevo contador si no hay ningún contador con ese nombre. Para esto, usar cualquier propiedad funcionaría bien, sin embargo, counter-set
no tiene un soporte de navegador tan bueno como counter-reset
, así que estoy tomando la ruta práctica:
body { counter-reset: heading-counter; }
Ahora que tengo un contador, puedo usar la propiedad counter-increment
en el selector para los encabezados; esto debería incrementar el contador cada vez que el selector coincida.
h2 { counter-increment: heading-counter; }
Para ver el valor, necesito enviarlo al documento. Puedo hacer esto usando Contenido generado y agregándolo before
del encabezado como se muestra en el siguiente ejemplo de CodePen:
h2::before { content: counter(heading-counter) ": "; color: #00b7a8; font-weight: bold; }
Alternativamente, podría convertir el elemento h2
en un elemento list-item
y luego usar ::marker
, como se muestra a continuación. Como ya se detalló, el uso del elemento ::marker
tiene un soporte de navegador limitado. En Firefox, debería ver el contador utilizado como marcador para el encabezado, mientras que otros navegadores mostrarán la viñeta predeterminada.
h2 { display: list-item; } h2::marker { content: counter(heading-counter) ": "; color: #00b7a8; font-weight: bold; }
Contadores en elementos de formulario
También hay un poco de interactividad que puede lograr usando CSS Counters, algo que podría pensar que necesita JavaScript para hacer.
Tengo un formulario que tiene varios campos obligatorios. El estado obligatorio se puede seleccionar en CSS con una :required
, y el hecho de que un campo no se ha completado se puede detectar mediante la :invalid
. Esto significa que podemos verificar los campos que son obligatorios y no válidos, e incrementar un contador. Luego, envíelo como contenido generado.
Cuán útil es esto en realidad es discutible, dado que realmente no podemos hacer nada con ese valor más que incluirlo en el contenido generado. También existen preocupaciones con respecto a que el contenido generado sea inaccesible para ciertos lectores de pantalla, por lo tanto, cualquier uso que sea más que decorativo debería garantizar otras formas de acceder a esa información. Lea, "Soporte de accesibilidad para contenido generado CSS" y la información más reciente, "Compatibilidad del lector de pantalla de propiedades de contenido CSS" para obtener más detalles sobre la accesibilidad y el contenido generado.
Sin embargo, demuestra que los contadores pueden lograr cosas más útiles que simplemente enumerar listas. Puede ser que algún día ese conocimiento sí te sirva para solucionar algún problema en el que estés trabajando.
Saber más
Este artículo terminó bastante lejos de diseñar listas, a pesar de que todo lo que he descrito se encuentra en la especificación de Listas CSS. Puede encontrar más información sobre las cosas descritas en los enlaces a continuación. Si ha encontrado un uso interesante para los contadores CSS, o puede pensar en cosas para las que podría usar ::marker
, agregue una nota en los comentarios.
-
::marker
-
counter-set
-
counter-reset
-
counter-increment
- "Uso de contadores CSS", documentos web de MDN
- "Contar con contadores CSS y cuadrícula CSS", CSS-Tricks