soy Kseso y esto EsCSS

Contadores Css y autonumeración automática. La propiedad Content

Artículo a fondo para dominar los contadores css y que no tengan secretos para ti. Incluye caso práctico aplicado a la numeración de los comentarios anidados de blogger.

Contadores Css y autonumeración automática. La propiedad Content

·Por Kseso ✎ 3
Contadores Css: autonumeración. La propiedad Content

Con Css SÍ se puede generar contenido

Html y Css no son lenguajes de programación, sólo de marcado" ¿Te suena lo anterior?. Seguro que sí. No son pocas las veces que eso se ha repetido a lo largo y ancho de la blogocosa, forumcaos y todo el universo de internet. Dí conmigo que nanay y vamos a demostrarselo. Css sí puede generar contenido. Lógicamente con sus limitaciones y en unos casos muy concretos. No pienses que estoy diciendo que olvides php, asp... o cualquier otro lenguaje específico de programación.

Tradicionalmente en Css el contenido puede ser generado de diversas formas:

  1. En los elementos con el valor list-item en la propiedad display
  2. Con la propiedad content en los pseudoelementos ::before | ::after | ::market
  3. En las hojas de estilo auditivas con propiedades sonoras cue-before y cue-after

En este post vamos a centrarnos en las 2 primeras y especialmente en la segunda, la propiedad content, por prestarse a más juego.

Si quieres conocer las propuestas más nuevas sobre los contadores, lee el artículo:

La regla Css @counter-style Contadores de tercer nivel

Listas numeradas

Cualquier elemento de una lista, o con la declaración display: list-item generan un "marcador" en cada item. Estas marcas se pueden controlar con las propiedades definidas a tal fin:

List-style-type
Define el tipo de marcador, un número o signo, de cada elemento. Si quieres numerar el valor a declarar es decimal (números decimales comenzando por 1, 2...) o decimal-leading-zero (igual pero anteponiendo el 0 -cero-: 01,02...10,11...). Y lower-roman o upper-roman para números romanos en minúsculas o mayúsculas. Como esta lista de definición.
List-style-image
Si quieres que el marcador sea una imagen
List-style-position
Determina dónde se coloca el elemento: outside, que es el valor por defecto, fuera de la caja generada por el item e inside dentro de ella.

Quiero que te fijes bien en la numeración obtenida en esta lista de definición (dl/dt/dd). Como ves el conteo es sucesivo. Incrementan la misma numeración tanto los elementos "dt" como los "dd".
Este es el Css del ejemplo:

dt { display: list-item; list-style-type: upper-roman; } dd { display: list-item; list-style-type: decimal; }

A lo anterior, los elementos de lista (list-item) tienen la particularidad que en cada lista comienzan otra vez por el número 1. Esto es, si ahora incluyese otra lista de definición, la numeración volvería a ser la misma que la anterior: I-2-III-4-V...

Utilizando list-items además no se pueden controlar de forma separada del propio contenido casi ninguna otra propiedad, además de ser imposible añadir nada más, como una palabra que identifique qué estamos numerando.

Para soslayar estas limitaciones tenemos que hacer uso de los contadores Css.

Contadores Css y autonumeración

Contadores css: Generar contenido y autonumeración. La propiedad ContentEl control de los contadores o numeración automática en css se realiza con:

  • La propiedad content (recuerda que sólo la admiten los pseudoelementos ::before | ::after | ::market ) las funciones o valores:
    counter() y counters() para definir y diferenciar unos contadores de otros y actuar sobre ellos selectivamente. Más llánamente: dentro del paréntesis ponemos el nombre que queramos dar a nuestro contador.
  • La propiedad counter-increment:
    define qué elemento incrementar un contador dado. Amite más de un identificador de contadores (el nombre dado a cada uno). Este identificador puede ir seguido de un número entero. Es la cantidad en que aumentará. Los valores 0 (cero) y negativos son válidos.
  • La propiedad counter-reset:
    qué elemento pone a cero un contador concreto. También como antes puedes definir más de un nombre. Y el número declarado es es el valor inicial del reseteo. Admite cualquier valor entero: positivo, negativo y cero. Por defecto su valor es 0

Vamos con un ejemplo y sobre él las explicaciones.
Tengamos el típico contenido distribuido en secciones, y dentro de ellas encabezados de primer y segundo nivel tal que así:

<section> <h1>Display<h1> bla, bla, bla... <h2>Block<h2> bla, bla, bla... <h2>Inline<h2> bla, bla, bla... </section> <section> <h1>Text-decoration</h1> bla, bla, bla... <h2>None<h2>

Y ahora en nuestro css declaramos:

h1:before { content: "Propiedad " counter(property) ": "; counter-increment: property; counter-reset: val; } h2:before { content: counter(property) "." counter(val) " Valor: "; counter-increment: val; }

Contadores css: Generar contenido y autonumeración. La propiedad ContentVamos a ver con detenimiento este código Css. Fíjate en primer lugar que he obtado por declarar todo en los pseudoelementos para simplificar. Las propiedades C-increment y C-reset también podría haberlas puesto en el hn diréctamente.
En la regla del selector h1:before

  • content: "Propiedad " counter(property) ": "; Con esta declaración ponemos la palabra Propiedado y un espacio en blanco antes de cada h1, imprimimos el valor del contador llamado property y añadimos el signo ortográfico de los 2 puntos y otro espacio en blanco (para separarlo de lo que haya en la etiqueta h1).
  • counter-increment: property; Cada vez que aparece un h1 el contador llamado property lo incrementamos en uno más.
  • counter-reset: val; Esto hará que el contador llamado val se ponga a cero (se reinicie) cada vez que aparezca un h1. val es el contador que utilizo para numerar los h2

La segunda declaración del h2:before

  • content: counter(property) "." counter(val) " Valor: "; Al igual que antes, al aparecer un h2 imprimiremos el valor del contador property (que ya lo habíamos creado antes) más un punto más el valor del contador val (este se crea ahora) seguido por la cadena de texto " Valor: " sin comillas
  • counter-increment: val; COn esta declaración cada h2 incrementa en una unidad el contador val
  • En un caso real, aquí añadiríamos otra declaración para resetear los contadores de los h3: (counter-reset: h3)

Todo esto, que es más difícil y largo de explicar que de hacer y comprender, nos daría como resultado del código html anterior del ejemplo lo siguiente:

Contadores css: Generar contenido y autonumeración. La propiedad Content Propiedad 1: Display bla, bla, bla... 1.1 Valor: Block bla, bla, bla... 1.2 Valor: Inline Propiedad 2: Text-decoration bla, bla, bla... 2.1 Valor: None

Caso práctico: numeración de comentarios anidados en blogger

Una aplicación práctica de los contadores css puede ser la numeración de los comentarios en esta plataforma, blogger, que no lo incorpora.

Para ello sólo tenemos que identificar la clase que tienen los comentarios raíz y la del comentario de respuesta:

/*Identificamos un ancestro común a todos los comentarios para que inicialice la cuenta:*/ .comment-thread ol { counter-reset: CuentaComentarios; } /*Buscamos un identificador de cada comentario raíz*/ .comment-thread .comment-header:after { content: counter(CuentaComentarios); counter-increment: CuentaComentarios; } /*Identificamos un ancestro de las réplicas para reiniciar su cuenta*/ .comment-thread ol ol { counter-reset: replica; } /*Identificamos las réplicas y cómo imprimimo la cuenta*/ .comment-thread li li .comment-header:after { content: counter(CuentaComentarios) "-" counter(replica); counter-increment: replica; }

Dos notas al código anterior:

  1. No declaro el tipo de contador (decimal) en counter porque es el valor por defecto. Sería redundante.
  2. Ten presente que los selectores pueden cambiar de una plantilla a otra.

CounterS control de contadores anidados

La función Counters() no es para declarar múltiples contadores. Como estamos viendo la propiedad content admite más de uno.

Counters es para apuntar y controlar de una sola vez a todos los contadores del mismo nombre.
Los contadores son por naturaleza autoanidados. Esto es, cada elemento hijo crea una nueva instancia del contador.
Esto es muy relevante en casos como las listas anidadas, que pueden tener tanta profundidad como se necesite (listas dentro de lista).

En este caso de elementos anidados de profundidad desconocida si aplicamos un contador del tipo counter como el siguiente:

ol {counter-reset: item} li:before { content: counter(item) "."; counter-increment: item; }

Cada ol crea un contador del mismo nombre (item) y la numeración obtenida es un tanto caótica y confusa como el ejemplo siguiente. El código html me lo ahorro. Échale un vistazo al código fuente.

  1. El día que me convertí en...
    1. Un Papel
      1. Reciclado
      2. Ligero
        1. Transparente
          1. Nítido
          2. Velado
            1. Distorsionado:
              1. Al 20%
              2. Al 40%
              3. Al 60%
            2. Sin distorsión
        2. Traslúcido
        3. Opaco
      3. Impreso
    2. Una Piedra
    3. Una Tijera
  2. Trabajando de...
  3. Otro item precedido de su número
  4. Más items numerados

Normalmente en estas situaciones lo que se busca es una numeración del tipo 1 / 1.1 / 1.1.1 / etc y no el que nos muestra de contadores intercalados.
Si esto se quisiera lograr definiendo un nuevo contador para cada una de las listas anidadas además de ser tedioso y propenso a errores tendría la dificultad de desconocer a priori el número de ellas.

Pues en esta situación viene al rescate la propiedad counters(). Para facilitar la vida y la codificación basta cambiar el código Css anterior por éste otro:

li:before { content: counters(item, "."); counter-increment: item; }

Fíjate que el cambio es mu pequeño: counters por counter y metemos dentro del paréntesis el "." o cadena de texto para separar cada número. El resto es lo mismo.
Con eso y una pizca de estilos para presentar los datos el resultado ahora sí que sí numera los items sin ambigüedades. Mira:

  1. El día que me convertí en...
    1. Un Papel
      1. Reciclado
      2. Ligero
        1. Transparente
          1. Nítido
          2. Velado
            1. Distorsionado:
              1. Al 20%
              2. Al 40%
              3. Al 60%
            2. Sin distorsión
        2. Traslúcido
        3. Opaco
      3. Impreso
    2. Una Piedra
    3. Una Tijera
  2. Trabajando de...
  3. Otro item precedido de su número
  4. Más items numerados

Contadores Css: Apuntes finales

Y para terminar, que vaya un tocho que me ha salido hoy, unas consideraciones o pinceladas a tener en cuenta en el uso de los contadores Css:

  1. El valor por defecto para el tipo de contador es decimal, como ya apunté, pero se puede utilizar cualquiera de los válidos para list-style-type.
  2. Los elementos con display: none ni incrementan ni restablecen (reset) los contadores.
  3. Sin embargo si se oculta con visibility: hidden sí suman y resetean.
  4. La función counters() forma una cadena con todos los valores de todos los contadores con el mismo nombre que le precede, separados por el símbolo o cadena de texto que indiquemos.
  5. Los contadores Css también son obedientes con la regla de la cascada. Por eso cuando el mismo elemento necesita manejar dos contadores distintos se escriben juntos en la misma declaración y no por separado. Ejemplo: /*la segunda regla anula a la primera y section no se resetearía*/ section { counter-reset: section -10;} section { counter-reset: articulo 10;} /*Esta otra sí reinicia los dos*/ section { counter-reset: section -10 articulo 10;}
  6. Si un elemento suma o reinicia un contador y también lo usa (su pseudoelemento lo incluye en content) primero se hace la suma o reinicio y después el uso (se muestra el valor).
  7. Si un elemento reinicia y suma un contador, primero lo reinicia y después lo incrementa.
  8. En caso de no declarar counter-increment el contador funciona. Es el elemento raíz el que lo inicializa.
  9. Si necesitas forzar un salto de línea <br /> en el contenido generado por 'content' sólo tienes que incluir \A tal que así:
    content: "Capítulo " counter(capitulo) "\A" counter(titulo); y sin comillas si es dentro de una cadena de texto:
    content: "Capítulo \A Título \A Subtítulo"

Y final

Como con esto es más que suficiente por hoy :-D dejamos para otro día cómo controlar el posicionamiento de los contadores y de las marcas de las listas.

Artículo publicado originalmente el 22/10/2012

avatar del Editor del blog

the obCSServer ᛯ Ramajero Argonauta, Enredique Amanuense de CSS.
#impoCSSible inside
Dicen que, en español, EsCss es el mejor blog de CSS. Posíblemente exageren.
@Kseso EsCss Kseso