CSS Container Queries

Media queries para elementos contenedores


Los media queries o regla @media son un mecanismo de CSS para dar estilo a elementos dependiendo de si se cumple una cierta condición, que generalmente tiene que ver con el tamaño, orientación o cierta característica de la página o dispositivo en el que nos encontramos. Es uno de los mecanismos principales del responsive design.

Si has llegado hasta aquí, es muy probable que ya conozcas el concepto de media queries. Si no es así, te recomiendo echarle un vistazo antes de continuar.

¿Qué son los Container Queries?

Los CSS Container Queries son el mismo concepto de las Media Queries, pero en lugar de estar orientados a modificar los estilos dependiendo del tamaño de la página o dispositivo, lo hace dependiendo de un contenedor padre (o ancestro) específico. De esta forma, podemos cambiar el tamaño de ciertos elementos y hacer que tengan una forma o unos estilos concretos dependiendo del contexto donde se encuentren.

CSS Container Queries

El contenedor

Para empezar, tenemos que determinar cuál será el elemento contenedor al que vamos a hacer referencia. En dicho elemento, necesitaremos establecer las siguientes propiedades, donde container-name es siempre obligatoria:

PropiedadValoresDescripción
container-namenone | nombre del contenedorEstablece un nombre de contenedor para poder hacer referencia a él.
container-typenormal | size | inline-sizeEstablece el tipo de tamaño de contenedores (bloque, en linea...).

La propiedad container-name le da un nombre de contenedor al elemento en el que nos encontramos. Sin este nombre no podremos hacer referencia luego, en la regla @container.

Por otro lado, la propiedad container-type, si la definimos, establecerá el tipo de tamaño que va a tener el contenedor en cuestión, donde puede ser size para elementos de tipo bloque, o inline-size para elementos de tipo en línea. Por ejemplo, en el caso de establecer un elemento inline-size, no tendrá en cuenta la altura, si la colocamos en la regla @container, al contrario que si usamos size.

.container {
  container-name: parent;
  container-type: inline-size;
}

Tienes más información sobre elementos en línea y en bloque, en la sección la propiedad display.

Atajo: La propiedad container

Una forma de escribir menos código es utilizar la propiedad de atajo container, a la cuál le podemos indicar dos valores: el valor de la propiedad container-name y el valor de la propiedad container-type, siempre separadas por un /:

PropiedadValor
containercontainer-name / container-type

El ejemplo anterior, se podría simplificar como se ve a continuación:

.container {
  container: parent / inline-size;
}

Muchas veces no necesitaremos establecer el valor de la propiedad container-type, por lo que podemos indicarle simplemente el primer valor, de la propiedad container-name y nada más.

La regla @container

Una vez tenemos nuestro contenedor definido, debemos establecer una regla @container que, de forma muy similar a las reglas @media va a establecer una condición dependiendo de un elemento contenedor específico.

ReglaDescripción
@container <nombre del contenedor> (<condición>)Establece una condición para aplicar estilos al contenedor concreto.

Por ejemplo, en este ejemplo que tenemos a continuación, vamos a establecer nuestro elemento con clase .container con un elemento contenedor parent, y creamos una regla @container que afecta a los hijos del contenedor parent cuando, como máximo, tenga 500px de ancho:

.container {
  container: parent;
}

@container parent (max-width: 550px) {
  .item {
    background: blue;
  }
}

Vamos ahora a aplicar este detalle a un ejemplo completo. Observa que la tarjeta aparece en formato horizontal. Sin embargo, si forzamos a reducir el ancho de la ventana, comprobaremos que el elemento reacciona al cambio y se muestra en versión vertical. Esto puede parecer lo mismo que un media query, pero realmente podemos hacer lo mismo reduciendo el tamaño de la tarjeta (esquina inferior-derecha), y también reacciona a su cambio de tamaño.

Esto ocurre porque hemos usado un Container Query en lugar de un Media Query:

body {
  background: steelblue;
  height: 625px;
}

.container {
  container: card / inline-size;
  max-width: 1024px;
  min-width: 250px;
  overflow: hidden;
  resize: horizontal;
  border: 1px solid white;
  box-shadow: 4px 4px 10px #0005;
  background: white;
  color: black;

  & .item {
    display: flex;
    justify-content: center;
    align-items: center;
    background:
      linear-gradient(to right, transparent 180px, white 180px),
      linear-gradient(to bottom, #9146eb 50%, #ea17cf 50%);

    @container card (max-width: 550px) {
      flex-direction: column;
      background: linear-gradient(#9146eb, #ea17cf 180px, transparent 180px);
    }

    & img {
      position: relative;
      width: 180px;
      height: 180px;
    }

    & .data {
      margin: 1em;
    }
  }
}
<p>Move from bottom-right corner</p>

<div class="container">
  <div class="item">
    <img src="https://manz.dev/apple-touch-icon.png" alt="ManzDev">
    <div class="data">
      <h1>Manz.dev</h1>
      <p>Página del canal de Twitch de ManzDev, donde se habla de Desarrollo web, front-end y se explican o crean proyectos variados utilizando tecnologías web como HTML, CSS y Javascript.</p>
    </div>
  </div>
</div>

En este caso, cuando el elemento .item se encuentre dentro del contenedor .container y este último, tenga menos de 500px de ancho, el estilo del elemento .item cambiará a lo definido en la regla @container.

Unidades de contenedores

Cuando nos encontramos en el interior de una regla @container podemos utilizar ciertas unidades especiales como cqw, cqh, cqi, cqb, cqmin o cqmax. Básicamente, la idea es que si desconocemos el tamaño concreto del contenedor, podemos utilizar estas medidas para aplicar un porcentaje de su tamaño.

De esta forma, si utilizamos 50cqw, significa que va a establecer un tamaño del 50% del ancho del contenedor. Funcionan de forma muy similar a las unidades vw, vh, vmin y vmax.

UnidadDescripción
cqwContainer Query Width. Porcentaje relativo al ancho del contenedor.
cqhContainer Query Height. Porcentaje relativo al alto del contenedor.
cqiContainer Query Inline Size. Porcentaje relativo al tamaño en línea.
cqbContainer Query Block Size. Porcentaje relativo al tamaño de bloque.
cqminContainer Query Mínimo. Valor más pequeño entre cqi y cqb.
cqmaxContainer Query Máximo. Valor más alto entre cqi y cqb.

Las unidades cqi y cqb son las propiedades lógicas equivalentes al ancho y alto. Si tienes curiosidad, echa un vistazo al artículo Propiedades lógicas CSS.

Condiciones con función style()

Aunque aún no tiene muy buen soporte, es posible utilizar la función css style() para realizar comprobaciones concretas en variables CSS y determinar si se deberían aplicar los estilos. Por ejemplo, observa el siguiente ejemplo:

.container {
  container: parent;
}

@container parent (max-width: 500px) and style(--responsive: true) {
  .item {
    background: blue;
  }
}

La función style(--responsive: true) comprueba si existe una variable --responsive y está establecida a true, cosa que se puede hacer desde nuestro código CSS, o establecerla desde Javascript y guardarla en una variable CSS, permitiendo hacer nuestras condiciones de contenedores mucho más flexibles.

¿Quién soy yo?

Soy Manz, vivo en Tenerife (España) y soy streamer partner en Twitch y profesor. Me apasiona el universo de la programación web, el diseño y desarrollo web y la tecnología en general. Aunque soy full-stack, mi pasión es el front-end, la terminal y crear cosas divertidas y locas.

Puedes encontrar más sobre mi en Manz.dev