Maquetación Web Dinámica / Pseudo-clases y pseudo-elementos: el arsenal secreto
:has() — el selector de padre que lo cambió todo
Durante 25 años, CSS solo miró hacia ABAJO: el padre estiliza al hijo, jamás al revés. "Estiliza la tarjeta SI contiene una imagen" era imposible — territorio de JavaScript. :has() rompió esa frontera en 2023 y es, sin exagerar, la adición más importante al CSS en una década. Hoy piensas en ambas direcciones.
La pregunta invertida
Se lee al revés que todo lo demás: A:has(B) selecciona A (el padre),
no B. Y el argumento acepta combinadores: :has(> img) (hijo directo),
:has(+ p) (¡hermano siguiente! — "el h2 seguido de un párrafo").
El caso estrella: validación visual sin JS
<form>
<div class="campo">
<label for="correo">Tu correo</label>
<input type="email" id="correo" required placeholder="nombre@dominio.com">
<p class="error">Ese correo no se ve completo</p>
</div>
<p class="nota">Escribe algo inválido ("hola") y luego un correo real: el campo reacciona solo, sin una línea de JS.</p>
</form>body { font-family: system-ui; padding: 24px; }
.campo { display: grid; gap: 6px; max-width: 320px; padding: 14px; border: 2px solid #e2e8f0; border-radius: 10px; }
label { font-size: 14px; font-weight: 600; color: #1e293b; }
input { padding: 8px 12px; border: 1px solid #cbd5e1; border-radius: 8px; font-size: 15px; }
.error { display: none; margin: 0; font-size: 12px; color: #b91c1c; font-weight: 600; }
.campo:has(input:invalid:not(:placeholder-shown)) { border-color: #dc2626; background: #fef2f2; }
.campo:has(input:invalid:not(:placeholder-shown)) .error { display: block; }
.campo:has(input:valid:not(:placeholder-shown)) { border-color: #16a34a; }
.nota { font-size: 12px; color: #64748b; max-width: 320px; }Disecciona el selector clave —
.campo:has(input:invalid:not(:placeholder-shown)) — porque es una clase
magistral de este módulo entero: el CAMPO (padre) reacciona si su input es
inválido (:invalid, validación nativa del módulo 2) PERO solo si el
usuario ya escribió algo (:not(:placeholder-shown) — el truco para no
gritarle en rojo a un formulario recién abierto).
Patrones :has() del mundo real
¿Qué selecciona .campo:has(input:invalid:not(:placeholder-shown))?
Mini-reto
Agrégale al formulario de tu periódico la validación visual completa del ejemplo (borde rojo + mensaje al escribir mal, borde verde al corregir). Y el patrón galería: al hacer hover sobre una noticia, las demás se atenúan. Dos efectos "de JavaScript", cero JavaScript.
Qué sigue
Cierras las pseudo-CLASES. Entran los pseudo-ELEMENTOS: ::before y ::after — los dos hijos fantasma que todo elemento regala, y con los que se decora, se enumera... y se dibuja.