En el artículo "How To Benefit From CSS Generated Content And Counters" de Smashing Magazine nos ofrecen un interesante tutorial acerca de como agregar contenido con CSS. El tutorial abarca desde la adición de cadenas de texto o imágenes hasta la adición de contadores. En este post se realiza una traducción libre de esta parte de dicho tutorial.
Se puede insertar contenido generado desde una hoja de estilo, antes y después el contenido de un elemento, utilizando los pseudo-elementos :before y :after, respectivamente. Para representar los pseudo-elementos podemos utilizar el siguiente ejemplo:
<p>
<before>Inicio</before>
Contenido
<after>Final</after>
</p>
Y el CSS sería
p:before {
content: "Inicio";
}
p:after {
content: "Final";
}
Ten en cuenta que si estás validando el archivo CSS contra las especificaciones CSS3, los pseudo-elementos :before y :after deberían escribirse como ::before y ::after. De lo contrario, el validador CSS dará un error.
Insertar contadores
La numeración automática de CSS es controlada por dos propiedades, counter-reset y counter-increment. Los contadores definidos por estas propiedades se utilizan con las funciones counter() y counters() de la propiedad content. La propiedad counter-reset puede contener uno o más nombres de contadores, opcionalmente seguidos por un número entero. El entero establece el valor que se incrementa por la propiedad counter-increment para cualquier coincidencia con el elemento dado. El valor predeterminado es 0. Se admiten valores negativos. La propiedad counter-increment es similar. La diferencia fundamental es que ésta incrementa un contador. El incremento de su valor por defecto es 1. También se admiten valores negativos.
Vamos a ver ahora un ejemplo:
<dl>
<dt>elemento</dt>
<dd>descripción</dd>
<dt>elemento</dt>
<dd>descripción</dd>
<dt>elemento</dt>
<dd>descripción</dd>
</dl>
Queremos agregar numeración progresiva (1, 2, 3, etc.) para cada definición (dt) de la lista. El CSS:
dl {
counter-reset: item;
}
dt:before {
counter-increment: item;
content: counter(item);
}
Ver ejemplo en funcionamiento » »
La primera regla establece un contador para la lista de definiciones. A esto se le denomina "scope" o "alcance". El nombre (o identificador) del contador es item. Cualquier nombre que elijamos para nuestro contador debe ser idéntico al de la propiedad counter-increment.
En la segunda regla, asociamos el pseudo-elemento :before al elemento dt, ya que queremos insertar el contador precisamente antes del contenido del elemento. La función counter() acepta nuestro identificador item como argumento, y la propiedad content genera el contador.
No hay ningún espacio entre el número y el contenido del elemento. Si queremos añadir, por ejemplo, un punto y un espacio después del número, podríamos insertar la siguiente cadena en la propiedad content:
dt:before {
content: counter(item) ". ";
}
Ver ejemplo en funcionamiento » »
Podemos agregar más estilos a los contadores aplicando otras propiedades al pseudo-elemento. Por ejemplo:
dt:before {
padding: 1px 2px;
margin-right: 0.2em;
background: #ffc;
color: #000;
border: 1px solid #999;
font-weight: bold;
content: counter(item);
counter-increment: item;
}
Ver ejemplo en funcionamiento » »
Además, los contadores pueden ser negativos. Por ejemplo, si necesitamos numeración progresiva a partir de 0, podríamos escribir lo siguiente:
dl {
counter-reset: item -1;
}
dt:before {
counter-increment: item;
content: counter(item) ". ";
}
Ver ejemplo en funcionamiento » »
Al establecer la propiedad counter-reset en -1 e incrementándola en 1, el valor resultante es 0, y la numeración comenzará a partir de ese valor. Los contadores negativos pueden combinarse con contadores positivos para lograr efectos interesantes. Por ejemplo:
dl {
counter-reset: item -1;
}
dt:before {
counter-increment: item 3;
content: counter(item) ". ";
}
Ver ejemplo en funcionamiento » »
Como veis, sumar y restar números positivos y negativos produce una amplia gama de combinaciones entre contadores. Con sólo unos simples cálculos, obtenemos un completo control sobre la numeración automática.
Otra característica interesante de los contadores CSS radica en su capacidad para anidar. De hecho, la numeración también se puede ordenar por subniveles progresivos, como 1.1, 1.1.1, 2.1 y así sucesivamente. Para agregar un subnivel a los elementos en la lista, deberías escribir lo siguiente:
HTML:
<ol>
<li>elemento</li>
<li>elemento
<ol>
<li>elemento</li>
<li>elemento</li>
<li>elemento
<ol>
<li>elemento</li>
<li>elemento</li>
</ol>
</li>
</ol>
</li>
</ol>
CSS:
ol {
counter-reset: item;
list-style: none;
}
li {
display: block;
}
li:before {
counter-increment: item;
content: counters(item, ".") " ";
}
Ver ejemplo en funcionamiento » »
En este ejemplo, tenemos sólo el contador item para cada nivel de anidamiento. En lugar de escribir tres contadores diferentes (como item1, item2, item3) y creando tres alcances o "scopes" diferentes para cada elemento ol anidado, contamos con la función counters() para lograr este objetivo. La segunda regla es importante y merece una explicación. Las listas ordenadas tienen marcadores por defecto (es decir, números), por lo que nos deshacemos de estos marcadores convirtiendo los elementos de lista en bloques. Recuerda que sólo elementos con display: list-items tienen marcadores.
La tercera regla es la que hace el trabajo. La primera declaración incrementa el contador establecido previamente en la lista. Luego, en la segunda declaración, la función counters() crea todas las instancias del contador para las listas internas. La estructura de esta función es el siguiente:
-
Su primer argumento es el nombre del contador dado, seguido inmediatamente por una coma.
-
Su segundo argumento es un período entre comillas dobles.
Fíjate que hemos introducido un espacio después de la función counters() para separar los números del contenido real de los elementos de lista.
Los contadores están formateados, por defecto, como números decimales. Sin embargo, los estilos de la propiedad list-style-type también están disponibles para los contadores. La notación por defecto es counter(nombre) (es decir, sin estilo) o counter(nombre, 'list-style-type') para cambiar el formato por defecto. En la práctica, los estilos recomendados son los siguientes:
-
decimal
-
decimal-leading-zero
-
lower-roman
-
upper-roman
-
lower-greek
-
lower-latin
-
upper-latin
-
lower-alpha
-
upper-alpha
Veamos un ejemplo:
HTML:
<dl>
<dt>elemento</dt>
<dd>descripción</dd>
<dt>elemento</dt>
<dd>descripción</dd>
<dt>elemento</dt>
<dd>descripción</dd>
</dl>
CSS:
dl {
counter-reset: item desc;
}
dt:before {
counter-increment: item;
content: counter(item, upper-latin) ". ";
}
dd:before {
counter-increment: desc;
content: counter(desc, lower-latin) ". ";
}
Ver ejemplo en funcionamiento » »
No te olvides que estamos trabajando con sistemas numéricos. Recuerda también que la especificación no define cómo producir un sistema alfabético más allá del final de un alfabeto. Por lo que los números se recomiendan para largas listas.
También podemos añadir estilos a la función counters()
HTML:
<ol>
<li>elemento</li>
<li>elemento
<ol>
<li>elemento</li>
<li>elemento</li>
<li>elemento
<ol>
<li>elemento</li>
<li>elemento</li>
</ol>
</li>
</ol>
</li>
</ol>
CSS:
ol {
counter-reset: item;
list-style: none;
}
li:before {
counter-increment: item;
content: counters(item, ".", lower-roman) " ";
}
li:before { counter-increment: item; content: counters(item, ".", lower-roman) " "; }
Ver ejemplo en funcionamiento » »
Fíjate que la función counters() acepta también un tercer argumento (lower-roman) como el último elemento en la lista de argumentos, separado de los anteriores por una segunda coma. Sin embargo, la función counters() no nos permite especificar diferentes estilos para cada nivel de anidamiento.