Using Container Queries

Learn how to use container queries to create more flexible and efficient responsive designs compared to traditional media queries.

Overview

Container Queries are a CSS feature that allows you to apply styles based on the size of an element’s container rather than the viewport. Unlike traditional media queries that depend on the entire viewport size, container queries enable styles to change based on the parent element’s size, making it possible to create more modular and reusable components.

Why Use Container Queries

More Flexible Component Design

Traditional media queries could only reference the size of the entire viewport. However, container queries allow you to determine styles based on the actual container size where the component is placed.

This enables layout decisions based on the space that components actually occupy rather than viewport size, allowing for more precise and intuitive design control.

Distinguishing from Media Queries

Container queries don’t completely replace media queries. The recommended approach is to use them as follows:

  • Media Queries: For overall page layout and position: fixed elements
  • Container Queries: For internal layout of individual components

This distinction allows you to build a more maintainable CSS architecture.

/* Traditional media query (viewport-based) */
@media (max-width: 768px) {
  .cards {
    flex-direction: column;
  }
}

/* Container query (parent element-based) */
@container (max-width: 300px) {
  .cards {
    flex-direction: column;
  }
}

Basic Usage

1. Defining Containers

First, define the parent element of the element you want to use container queries with as a “query container.”

.container {
  container-type: inline-size; /* Enable width-based queries */
}

/* or */
.container {
  container-type: size; /* Enable queries based on both width and height */
}

container-type values:

  • inline-size: Monitor width only (most common)
  • size: Monitor both width and height
  • normal: Disable container queries (default)

2. Writing Container Queries

Apply styles based on the size of the defined container.

.cards {
  display: flex;
  gap: 1rem;
}

@container (max-width: 400px) {
  .cards {
    flex-direction: column;
  }

  .cards__image {
    width: 100%;
  }
}

@container (min-width: 600px) {
  .cards {
    padding: 2rem;
  }

  .cards__title {
    font-size: 2rem;
  }
}

3. Named Containers

When using multiple containers, you can distinguish them by giving them names. This allows you to clearly specify which container the query refers to.

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

.main-content {
  container-type: inline-size;
  container-name: main;
}

/* Queries for specific containers */
@container sidebar (max-width: 250px) {
  .widget {
    /* Styles when sidebar is narrow */
    font-size: 0.875rem;
    padding: 0.5rem;
  }
}

@container main (min-width: 800px) {
  .article {
    /* Styles when main content is wide */
    columns: 2;
    column-gap: 2rem;
  }
}

Shorthand notation:

.container {
  container: sidebar / inline-size; /* name / type */
}

Practical Example: Responsive Card Component

The following is an example of a card component whose layout changes according to container size.

/* Card container definition */
.card-container {
  container-type: inline-size;
  container-name: card;
}

.card {
  display: grid;
  gap: 1rem;
  padding: 1rem;
  border: 1px solid #e0e0e0;
  border-radius: 8px;
  background: white;
}

/* Narrow container: vertical layout */
@container card (max-width: 350px) {
  .card {
    grid-template-columns: 1fr;
    text-align: center;
  }

  .card__image {
    width: 100%;
    max-width: 200px;
    margin: 0 auto;
  }

  .card__title {
    font-size: 1.25rem;
  }
}

/* Medium container: image and content side by side */
@container card (min-width: 351px) and (max-width: 599px) {
  .card {
    grid-template-columns: 120px 1fr;
    align-items: start;
  }

  .card__title {
    font-size: 1.125rem;
  }
}

/* Wide container: spacious layout */
@container card (min-width: 600px) {
  .card {
    grid-template-columns: 200px 1fr;
    align-items: center;
    padding: 2rem;
  }

  .card__content {
    padding-left: 1.5rem;
  }

  .card__title {
    font-size: 1.5rem;
    margin-bottom: 0.75rem;
  }
}

This way, the same card component will always have the optimal layout applied, even when placed in containers of different sizes.

Browser Support

Support Status

Container queries are a relatively new feature, but they are widely supported by major modern browsers:

  • Chrome: 105+ (August 2022~)
  • Firefox: 110+ (February 2023~)
  • Safari: 16.0+ (September 2022~)
  • Edge: 105+ (September 2022~)

Fallback Strategy

If you need to support older browsers, consider the following approaches:

/* Fallback styles */
.card {
  display: block;
}

/* For container query-compatible browsers */
@supports (container-type: inline-size) {
  .card-container {
    container-type: inline-size;
  }
  
  @container (min-width: 400px) {
    .card {
      display: grid;
      grid-template-columns: 200px 1fr;
    }
  }
}

Detailed support status: Can I use: CSS Container Queries

References