Skip to main content
Dublin Library

The Publishing Project

Container Queries and new CSS to go along with them

 

The CSS Containment Module Level 3 has a formal definition of containers, container queries, and container relative length units.

This post contains both parts that are supported in Chromium browsers behind a flag and others that are under development. It is not production code and should not be used as such.

Defining the container #

Before we use container relative length units we need to define a container that the units will refer to.

Containers allow you to create a finer-grained level of sizing for components that will be more specific than regular units (that refer to a window) or viewport units that refer to the viewport (usually the same as the window)

If you set a container, then you can choose to size the components based on the container's size rather than the viewport or Window.

The following table shows the different values for the contain property. Some of these values were defined in the level 2 CSS containment module so I indicate the spec version they were defined in.

Types of Containment Spec Introduced in Description
Size Level 2 size: The size of the element can be computed without checking its children, the element dimensions are independent of its contents.
Layout Level 2 The internal layout of the element is totally isolated from the rest of the page, it’s not affected by anything outside and its contents cannot have any effect on the ancestors.
Style Level 2 The effects of counters and quotes cannot escape this element, so they are isolated from the rest of the page.
Paint Level 2 Descendants of the element cannot be displayed outside its bounds, nothing will overflow this element (or if it does it won’t be visible).
Inline-size Level 3 Descendants of the element will only respond to changes on the element's width, the inline axis in left-to-write languages.
Block-size Level 3 Descendants of the element will only respond to changes on the element's height, the block axis in left-to-write languages.

There are also two compound values that you can use as shorthand for defining multiple types of containment.

  • content: Which is equivalent to contain: layout paint style.
  • strict: This is equivalent to contain: layout paint size style.

An example of a container ready to handle container relative sizes could look like this:

.card-container {
  contain: layout content inline-size style;
}

This container uses the new inline-size and the layout and style containment values from the level 2 specification to indicate the expected behavior for the children of the container.

We then define the elements that we want to use inside the container.

.card {
  display: flex;
  flex-direction: column;
  flex-wrap: wrap;

  gap: 1rem;
}

.card--thumb {
  aspect-ratio: 1 / 1;
  flex: 0 0 150px;
  background-color: #663399;
  border-radius: 7px;
}

.card-title {
  font-weight: bold;
  font-size: 1.5rem;
  margin-bottom: 0.5rem;
}

.card--content {
  flex: 1;
}

We then use one or more @container at-rule to define the changes that we want to make based on the size of the container.

@container (min-width: 400px) {
  .card {
    flex-direction: row;
  }

  .thumb {
    flex: 0 0 100px;
    align-self: flex-start;
  }
}


@container (min-width: 600px) {
  .card--thumb {
    flex: 0 0 150px;
  }
}

@container (min-width: 800px) {
  .card {
    position: relative;
    justify-content: center;
    align-items: center;
    min-height: 350px;
  }

  .thumb {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    opacity: 0.25;
  }

  .content {
    position: relative;
    flex: unset;
  }

  .title {
    font-weight: bold;
    font-size: 1.5rem;
    margin-bottom: 0.5rem;
  }

  .desc {
    max-width: 480px;
    margin-left: auto;
    margin-right: auto;
    text-align: center;
    color: #222;
  }
}

In the near future, we will have to change the code above to accommodate the new syntax as specified in this tweet:

Container type #

Note:

The properties described below are different than the contain properties in the CSS Containment Module Level 2. You can use container-type without using contain.

The container-type property establishes the element as a query container for the purpose of container queries, allowing style rules styling its descendants to query various aspects of its sizing, layout, and style and respond accordingly.

The available values are:

size
Establishes a query container for size queries on both the inline and block axis. Applies layout, style, and size containment to the principal box.
inline-size
Establishes a query container for size queries on the container’s own inline axis. Applies layout, style, and inline-size containment to the principal box.
block-size
Establishes a query container for size queries on the container’s own block axis. Applies layout, style, and block-size containment to the principal box.
style
Establishes a query container for style queries.
state
Establishes a query container for state queries.
They have been pushed to the next level of the CSS containment specification

Container name #

The container-name property specifies a list of query container names. These names can be used by @container rules to filter which query containers are targeted.

none
The query container has no query container name.
<custom-ident>
Specifies a query container name as an identifier.
<string>
Specifies a query container name as a </string><string> value; this computes to an identifier with the same value as the given </string><string>.

With container-name developers can specify which containers they want to target with @container queries and use the same container for multiple child elements.

main {
  container-type: size;
  container-name: page-layout;
}

.my-component {
  container-type: inline-size;
  container-name: component-library;
}

@container page-layout (block-size > 12em) {
  .card { margin-block: 2em; }
}

@container component-library (inline-size > 30em) {
  .card { margin-inline: 2em; }
}

Container #

This is a shorthand property to set both container-type and container-name. The values are separated by a slash /.

main {
  container: size / page-layout;
}

.my-component {
  container: inline-size / component-library;
}

Container relative length units #

These units are similar to viewport units except that they are relative to the dimensions of a the closes element that defined a container with container-type.

unit relative to
cqw 1% of a query container’s width
cqh 1% of a query container’s height
cqi 1% of a query container’s inline size
cqb 1% of a query container’s block size
cqmin The smaller value of cqi or cqb
cqmax The larger value of cqi or cqb

We can use these units in a similar way to viewport units, but they will refer to the closest ancestor that defines a container.

aside, main {
  container-type: inline-size;
}

.container {
  h2 {
    font-weight: bolder;
    font-size: clamp(1.25rem, 3qw, 2rem);
    margin-bottom: clamp(0.5rem, 1.5qw, 1rem);
  }
}

What Happens If We Use Query Units Without Defining Containers? #

If no eligible query container is available, then use the small viewport size for that axis.

The browser will deal with query units as if they were viewport units.

Consider the following example:

h2 {
    font-size: clamp(1.25rem, 3qw, 2rem);
}

If there is no container that is defined for the <h2> or parents, the browser will consider 3qw as if it was 3% of the viewport width, most likely not what you want to do.

Gotchas #

The @container API is not stable and is subject to syntax changes. If you try it out on your own, you may encounter bugs.

Right now this only works in Chromium browsers (Chrome, Edge, Opera, and others) if you enable the #enable-container-queries flag in chrome://flags.

Use the following links to track support on your browser:

Currently, you cannot use height-based container queries, using only the block axis. In order to make grid children work with @container, you’ll need to add a wrapper element. Despite this, adding a wrapper lets you still get the effects you want.

Edit on Github