Cómo seleccionar el elemento padre con CSS usando :has()

Aprende cómo seleccionar un elemento padre con CSS usando :has(), con ejemplos prácticos, sintaxis, combinaciones y casos de uso reales.

Durante muchos años, una de las limitaciones más conocidas de CSS era la imposibilidad de seleccionar un elemento padre dependiendo de sus hijos.

Si trabajas habitualmente con CSS, seguramente alguna vez has querido modificar un contenedor porque dentro tenía un botón, una imagen, una clase concreta o cualquier otro elemento.

La llegada de la pseudoclase :has() cambia por completo esta situación y permite crear selectores mucho más inteligentes sin necesidad de recurrir a JavaScript.

En este tutorial vas a aprender cómo seleccionar el elemento padre con CSS usando :has(), cómo funciona su sintaxis y qué aplicaciones prácticas puedes darle en una página web.

🔎 ¿Qué es :has() en CSS?

La pseudoclase :has() permite seleccionar un elemento en función de los elementos que contiene o de determinadas relaciones existentes dentro del documento HTML.

Por este motivo, aunque técnicamente tiene más posibilidades, suele conocerse popularmente como el selector de padre de CSS.

Puedes consultar también la documentación oficial de :has() en MDN Web Docs para profundizar en todas sus posibilidades.

La estructura más sencilla sería la siguiente:

.padre:has(.hijo) {
    propiedad: valor;
}

Con este selector estás indicando que CSS debe aplicar los estilos a .padre solamente cuando dicho elemento contenga un elemento con la clase .hijo.

Por ejemplo:

<div class="caja">
    <p class="destacado">Texto importante</p>
</div>

Puedes seleccionar .caja dependiendo de la existencia de .destacado de esta forma:

.caja:has(.destacado) {
    background: #f5f5f5;
}

El resultado es que el estilo se aplica al elemento padre .caja y no al elemento .destacado.

🧩 Sintaxis básica del selector :has()

La sintaxis de :has() es bastante sencilla una vez entiendes su lógica.

elemento:has(selector) {
    /* estilos */
}

Dentro de los paréntesis puedes introducir clases, etiquetas, identificadores, atributos, pseudoclases o combinaciones de selectores.

Por ejemplo:

div:has(img) {
    padding: 20px;
}

Este código seleccionará cualquier <div> que contenga al menos una imagen.

También puedes utilizar clases:

.tarjeta:has(.boton) {
    border: 1px solid #ccc;
}

En este caso solamente se modificarán las tarjetas que contengan un elemento con la clase .boton.

👨‍👦 Cómo seleccionar el elemento padre con CSS

Supongamos que tienes varias cajas pero solamente quieres modificar aquellas que contienen una imagen.

Tu HTML podría ser similar a este:

<div class="caja">
    <p>Contenido sin imagen</p>
</div>
<div class="caja">
    <img src="imagen.jpg" alt="Ejemplo">
    <p>Contenido con imagen</p>
</div>

Con CSS tradicional tendrías que añadir otra clase manualmente o utilizar JavaScript para diferenciar ambas cajas.

Con :has() solamente necesitas:

.caja:has(img) {
    border: 2px solid;
    padding: 20px;
}

CSS buscará las cajas que contienen una etiqueta <img> y aplicará los estilos directamente al elemento padre .caja.

📋 Pasos para utilizar :has() correctamente

Si quieres empezar a utilizar este selector en tus propios proyectos, puedes seguir este procedimiento:

  1. Identifica el elemento padre que quieres modificar.
  2. Localiza el elemento hijo o condición que determinará si debe aplicarse el estilo.
  3. Escribe el selector correspondiente al padre.
  4. Añade inmediatamente :has().
  5. Introduce dentro de los paréntesis el selector del elemento que quieres detectar.
  6. Añade las propiedades CSS que quieras aplicar al padre.
  7. Comprueba el resultado en diferentes situaciones para asegurarte de que solamente se seleccionan los elementos deseados.

Por ejemplo:

.contenedor:has(.error) {
    border: 2px solid red;
}

Este código modifica .contenedor únicamente cuando en su interior existe un elemento con la clase .error.

✅ Seleccionar un padre cuando contiene una clase concreta

Uno de los usos más habituales consiste en detectar si un elemento contiene una clase determinada.

Puedes hacerlo así:

.tarjeta:has(.oferta) {
    transform: scale(1.02);
}

La regla anterior solamente afectará a las tarjetas que contengan .oferta, permitiéndote crear estilos condicionales únicamente con CSS.

Esta técnica puede ser especialmente útil en tiendas online, listados de productos, tablas de precios o cualquier diseño generado dinámicamente.

🖼️ Seleccionar un padre cuando contiene una imagen

También puedes comprobar fácilmente si un contenedor contiene una imagen.

.articulo:has(img) {
    padding-top: 30px;
}

Todas las cajas .articulo que tengan una etiqueta <img> recibirán el nuevo espaciado mientras que los artículos sin imágenes permanecerán sin cambios.

Incluso puedes buscar imágenes con determinados atributos:

.articulo:has(img[loading="lazy"]) {
    margin-bottom: 30px;
}

En este caso solamente se seleccionarán los artículos que contengan imágenes configuradas con carga diferida.

📝 Utilizar :has() con formularios

Los formularios son uno de los lugares donde :has() resulta especialmente práctico.

Imagina esta estructura:

<div class="campo">
    <input type="email" required>
</div>

Puedes modificar el contenedor cuando el campo tenga un estado determinado:

.campo:has(input:focus) {
    border-color: blue;
}

Cuando el usuario coloque el cursor dentro del input, será el elemento .campo el que recibirá el estilo.

También puedes trabajar con campos marcados:

.opcion:has(input:checked) {
    background: #eee;
}

Esto permite modificar visualmente toda una opción cuando su checkbox o radio button está seleccionado.

🎯 Combinar :has() con selectores hijos

No siempre necesitas buscar cualquier elemento descendiente, ya que también puedes especificar que el elemento detectado debe ser hijo directo.

Para ello puedes utilizar el selector >:

.contenedor:has(> img) {
    padding: 20px;
}

Este selector solamente afectará a .contenedor cuando la imagen sea un hijo directo del contenedor.

Por ejemplo:

<div class="contenedor">
    <img src="foto.jpg" alt="">
</div>

Sí cumpliría la condición.

Sin embargo:

<div class="contenedor">
    <div>
        <img src="foto.jpg" alt="">
    </div>
</div>

No cumpliría esa condición porque la imagen ya no es hija directa de .contenedor.

🚀 Seleccionar un elemento según su hermano

Una de las características más interesantes de :has() es que no se limita estrictamente a buscar descendientes.

También puedes utilizar combinadores como + y ~ para detectar elementos hermanos.

Por ejemplo:

h2:has(+ p) {
    margin-bottom: 10px;
}

Esta regla selecciona los <h2> que tengan inmediatamente después un párrafo <p>.

También puedes escribir:

h2:has(~ .boton) {
    color: #333;
}

En este caso se seleccionarán determinados encabezados cuando posteriormente exista un hermano con la clase .boton.

🛒 Ejemplo práctico con WooCommerce

:has() también puede resultar muy útil cuando personalizas WooCommerce mediante CSS.

Por ejemplo, imagina que quieres modificar los productos que contienen una etiqueta de oferta:

.product:has(.onsale) {
    border: 2px solid;
}

El estilo se aplicará directamente al contenedor .product siempre que exista .onsale en su interior.

De esta manera puedes personalizar productos en oferta sin modificar plantillas PHP ni añadir clases CSS adicionales.

Si trabajas con este CMS también puedes consultar la documentación para desarrolladores de WordPress para conocer mejor la estructura generada por sus temas y plugins.

🔗 Combinar :has() con :not()

Puedes llevar los selectores condicionales todavía más lejos combinando :has() con :not().

Por ejemplo:

.tarjeta:not(:has(img)) {
    padding-top: 0;
}

Este selector seleccionará las tarjetas que no contienen ninguna imagen.

Otro ejemplo podría ser:

.formulario:not(:has(.error)) {
    border-color: green;
}

El formulario recibirá ese estilo únicamente cuando no exista ningún elemento .error en su interior.

💡 Utilizar varios selectores dentro de :has()

También puedes comprobar varias condiciones separándolas mediante comas.

.caja:has(img, video) {
    padding: 30px;
}

La regla se aplicará cuando .caja contenga una imagen o un vídeo.

Esta posibilidad permite reducir considerablemente la cantidad de CSS necesario cuando varios elementos deben provocar el mismo cambio visual en su contenedor.

📊 Tabla resumen de :has() en CSS

ObjetivoSelector CSSResultado
Detectar un hijo.caja:has(.hijo)Selecciona .caja si contiene .hijo
Detectar una imagen.caja:has(img)Selecciona cajas con imágenes
Detectar hijo directo.caja:has(> img)Detecta una imagen hija directa
Detectar campo enfocado.campo:has(input:focus)Modifica el padre al enfocar el input
Detectar checkbox marcado.opcion:has(input:checked)Modifica la opción seleccionada
Excluir elementos.caja:not(:has(img))Selecciona cajas sin imágenes
Detectar varios elementos.caja:has(img, video)Busca imágenes o vídeos
Detectar hermano siguienteh2:has(+ p)Selecciona un H2 seguido de un párrafo

⚡ Ventajas de utilizar :has()

La principal ventaja de :has() es que permite crear CSS más dinámico y dependiente de la estructura del documento.

También puedes reducir la cantidad de JavaScript necesaria para pequeños cambios puramente visuales.

Otra ventaja importante es que evita añadir clases auxiliares únicamente destinadas al diseño.

Además, puedes combinarlo con pseudoclases como :hover, :focus, :checked, :invalid o :not() para crear comportamientos bastante sofisticados.

Si quieres experimentar con estos selectores puedes utilizar herramientas como CodePen para probar rápidamente diferentes estructuras HTML y CSS.

⚠️ ¿Debes preocuparte por la compatibilidad de :has()?

Actualmente, :has() dispone de un soporte muy amplio en los navegadores modernos, por lo que ya puede utilizarse en la mayoría de proyectos web actuales.

Aun así, si tu web necesita funcionar en navegadores muy antiguos, conviene comprobar la compatibilidad específica antes de utilizarlo como parte imprescindible de una interfaz.

Puedes revisar el soporte actualizado del selector en Can I Use.

Una buena práctica consiste en utilizar :has() principalmente para mejoras visuales, evitando que una funcionalidad esencial dependa exclusivamente de un selector CSS cuando tienes requisitos especiales de compatibilidad.

🧠 Ejemplo completo de selección del padre

Imagina que tienes varias tarjetas y quieres destacar solamente aquellas que incluyen un botón.

El HTML sería:

<div class="tarjeta">
    <h3>Artículo normal</h3>
    <p>Contenido del artículo.</p>
</div>
<div class="tarjeta">
    <h3>Artículo destacado</h3>
    <p>Contenido del artículo.</p>
    <a class="boton">Leer más</a>
</div>

Solamente necesitas este CSS:

.tarjeta:has(.boton) {
    padding: 25px;
    border: 2px solid;
}

El navegador detectará automáticamente qué tarjeta contiene .boton y aplicará los estilos al contenedor padre correspondiente.

🎓 Conclusión

Aprender cómo seleccionar el elemento padre con CSS usando :has() te permite resolver situaciones que durante mucho tiempo requerían añadir clases adicionales o escribir JavaScript.

Su sintaxis básica, .padre:has(.hijo), resulta sencilla pero abre la puerta a selectores condicionales extremadamente versátiles.

Puedes detectar imágenes, botones, campos activos, checkboxes seleccionados, errores de formulario, hijos directos e incluso elementos hermanos.

Además, combinando :has() con selectores como :not(), :focus, :checked, > o +, puedes construir hojas de estilo mucho más inteligentes.

Si utilizas CSS habitualmente, :has() es uno de esos selectores que merece la pena incorporar a tu repertorio, porque puede simplificar notablemente muchas personalizaciones que anteriormente resultaban bastante engorrosas.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

¿Necesitas ayuda?

Si estás teniendo problemas con tu proyecto online, si estás en proceso de crearlo, si necesitas una web o si la tuya no funciona como debería puedo ayudarte.

¿Quién soy?
Blog
Portfolio

Carrito de compra
Scroll al inicio