Pseudo-elementos
Los pseudo-elementos crean partes de un elemento que no existen en el HTML. Con ellos puedes añadir iconos, decoraciones, overlays y estilos tipográficos sin ensuciar el markup ni añadir elementos vacíos.
::before y ::after — contenido generado
::before y ::after insertan un elemento virtual como primer o último hijo del elemento seleccionado. Necesitan obligatoriamente la propiedad content (puede ser vacía):
.nota::before {
content: '⚠️ ';
}
.precio::after {
content: ' €';
}
/* content vacío — solo para decoración */
.divider::after {
content: '';
display: block;
height: 2px;
background: var(--color-border);
margin: 1rem 0;
}
El pseudo-elemento generado es un hijo del elemento, no un hermano. Participa en el flujo normal y puede recibir cualquier propiedad CSS.
Posicionamiento absoluto dentro de un elemento
El patrón más habitual: posicionar ::before/::after con position: absolute dentro de un contenedor position: relative. El contenedor no necesita contenido extra en el HTML:
/* Badge de notificaciones */
.btn-notif {
position: relative;
display: inline-block;
}
.btn-notif::after {
content: attr(data-count); /* lee el atributo data-count del HTML */
position: absolute;
top: -6px;
right: -6px;
min-width: 18px;
height: 18px;
background: #e63946;
color: white;
font-size: 0.65rem;
font-weight: 700;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
<button class="btn-notif" data-count="3">Mensajes</button>
attr() es una función CSS que lee el valor de un atributo HTML. Solo funciona dentro de content.
Overlay sobre imágenes o secciones
.hero {
position: relative;
overflow: hidden;
}
/* Overlay oscuro semitransparente sobre la imagen */
.hero::before {
content: '';
position: absolute;
inset: 0; /* shorthand de top/right/bottom/left: 0 */
background: rgba(0, 0, 0, 0.4);
z-index: 1;
}
/* El contenido del hero tiene que estar por encima del overlay */
.hero > * {
position: relative;
z-index: 2;
}
Decoración tipográfica
/* Comillas tipográficas automáticas */
blockquote::before {
content: '\201C'; /* " — comilla de apertura unicode */
font-size: 4rem;
line-height: 0;
vertical-align: -0.4em;
color: var(--color-primary);
margin-right: 0.2em;
}
/* Línea decorativa antes de una sección */
h2::before {
content: '';
display: inline-block;
width: 0.4em;
height: 0.9em;
background: var(--color-primary);
margin-right: 0.5em;
vertical-align: middle;
}
Contadores CSS
Con counter-reset y counter-increment puedes numerar elementos automáticamente, incluso con formato personalizado:
ol.custom {
counter-reset: item;
list-style: none;
padding: 0;
}
ol.custom li {
counter-increment: item;
padding: 0.5rem 0 0.5rem 3rem;
position: relative;
}
ol.custom li::before {
content: counter(item, decimal-leading-zero); /* 01, 02, 03... */
position: absolute;
left: 0;
font-weight: 900;
color: var(--color-primary);
}
::placeholder — estilos del texto de ayuda
input::placeholder {
color: var(--color-text-muted);
font-style: italic;
opacity: 0.7;
}
/* Cambiar el placeholder al hacer foco */
input:focus::placeholder {
opacity: 0.3;
transform: translateX(4px);
transition: all 0.2s ease;
}
::selection — texto seleccionado
Personaliza el aspecto del texto cuando el usuario lo selecciona con el ratón:
::selection {
background: var(--color-primary);
color: var(--blackMirror);
}
/* Por sección específica */
.code-block::selection {
background: var(--color-accent);
color: white;
}
::first-line y ::first-letter
/* Estilo solo para la primera línea de un párrafo */
.intro p::first-line {
font-weight: 700;
font-variant: small-caps;
letter-spacing: 0.05em;
}
/* Capital decorativa al inicio de un artículo */
article > p:first-child::first-letter {
font-size: 3.5rem;
font-weight: 900;
float: left;
line-height: 0.8;
margin: 0.1em 0.1em 0 0;
color: var(--color-primary);
}
::marker — estilos del marcador de listas
Antes de ::marker tenías que hacer malabares con list-style: none y pseudo-elementos para personalizar los bullets. Ahora puedes estilar el marcador directamente:
ul li::marker {
color: var(--color-primary);
font-size: 1.2em;
}
ol li::marker {
font-weight: 900;
color: var(--color-accent);
}
En la siguiente lección pasamos al CSS que se mueve: transiciones y animaciones con transition, @keyframes y la propiedad animation.