Gerillass 3.0.0 is out. One gradient mixin replaces two, and text-gradient takes its colours first, so read the migration guide before you upgrade.

Gerillass

v3.0.0

Container Query

Type: Mixin
@include container-query();

* You can call mixins with or without the gls- namespace (e.g. @include gls-container-query();).

The same component often has to work in a narrow sidebar and in a wide main column on the same page. A media query cannot tell those apart, because it only knows the viewport. The Container Query Sass mixin writes a @container rule, so the component responds to the width of its container instead.

It takes the same argument shapes as Breakpoint, so the two read alike: a size, two sizes for a range, or min, max, only or between followed by a size. Sizes may be a key from $map-for-breakpoints or a raw length, and a raw length is the common case here, because a container is usually narrower than the viewport.

A size on its own matches that exact width and no other, (width: 400px), which is a single pixel. The mixin prints a warning for it since 2.2.0. Write only when that is what you mean.

Put the container on an ancestor of the element you are styling. This is the one thing to get right, and nothing tells you when you get it wrong. An element is never matched by a @container rule that reads its own container. Measured in a browser: a 600px element carrying container-type: inline-size did not match @container (min-width: 400px), while a child of it did. An element with no container ancestor at all matches nothing. There is no warning in either case; the rule is just never applied.

Arguments

NameTypeDescription
$params…string, numberAccepts a size, which matches that exact width only and prints a warning, two sizes for a range, or one of min, max, only or between followed by a size. A size cannot be a custom property: var() is not evaluated in a @container condition, so the rule would never apply, and the mixin refuses it.
$namestringAccepts a container name as a string, to query one named container rather than the nearest one. Pass it as a keyword, $name: "card". It has to be one name a browser keeps in an @container rule, so var(), none, and, or, not, default, a CSS-wide keyword, a name with a space and a name starting with a digit are refused. Measured in Chrome 152, each of them dropped the rule, and not turned the query into its opposite.

$name is passed as a keyword rather than by position, because container-query("card", "medium") could not be told apart from container-query("min", "medium").

Examples

The markup all of these assume: the container on the parent, the query on the child.

HTML
<div class="card">
  <h2 class="title">A title that grows once its card is wide enough</h2>
</div>
Sass
.card {
  @include container("card");
}

From a width upwards, which is the one you will reach for most.

Sass
.title {
  @include container-query("min", 400px) {
    font-size: 2rem;
  }
}
CSS
@container (min-width: 400px) {
  .title {
    font-size: 2rem;
  }
}

Up to a width.

Sass
.title {
  @include container-query("max", 399px) {
    font-size: 1rem;
  }
}
CSS
@container (max-width: 399px) {
  .title {
    font-size: 1rem;
  }
}

A range, written either with between or as two sizes. Both produce the same rule.

Sass
.title {
  @include container-query("between", 300px 500px) {
    color: red;
  }
}
.title {
  @include container-query(300px, 500px) {
    color: red;
  }
}
CSS
@container (min-width: 300px) and (max-width: 500px) {
  .title {
    color: red;
  }
}

@container (min-width: 300px) and (max-width: 500px) {
  .title {
    color: red;
  }
}

A predefined breakpoint name works too, resolved through $map-for-breakpoints.

Sass
.title {
  @include container-query("min", "medium") {
    color: red;
  }
}
CSS
@container (min-width: 768px) {
  .title {
    color: red;
  }
}

Naming the container you mean. Without a name the query resolves to the nearest container ancestor, which is the wrong one as soon as containers are nested.

Sass
.title {
  @include container-query("min", 400px, $name: "card") {
    color: red;
  }
}
CSS
@container card (min-width: 400px) {
  .title {
    color: red;
  }
}

What it refuses

Arguments are checked, so a wrong value stops the build with a message instead of quietly producing the wrong CSS.

Sass
.title {
  @include container-query("min", 400px, 800px) {
    color: red;
  }
}
Error: `container-query` takes one or two arguments, and was given 3. Pass a size, two sizes for a range, or one of `min`, `max`, `only` or `between` followed by a size.
Sass
.title {
  @include container-query("min", 400px, $name: 42) {
    color: red;
  }
}
Error: `42` is not a valid $name for `container-query`. Pass a container name as a string, such as `"card"`.

A size no width condition can match is refused, as it is in Breakpoint: a name missing from the map, a percentage, a bare number, or a unit that is not a length. Each used to compile into an @container rule that never applies. Container units such as cqi are lengths and are accepted.

Sass
.title {
  @include container-query("min", 50%) {
    color: red;
  }
}
Error: `50%` cannot be used as a size in `container-query`: a width condition takes a length, and one written with `50%` would never match in @container. Pass a length such as `600px`, `40em` or `calc(30em + 1px)`, or a key from $map-for-breakpoints.

A name from a custom property is refused too. The query needs the name itself, even where the container takes its name from var(), which the Container mixin allows.

Sass
.title {
  @include container-query("min", 400px, $name: var(--container)) {
    color: red;
  }
}
Error: `var(--container)` is not a valid $name for `container-query`: a custom property is not evaluated in a @container condition, so the rule would never apply. Pass the name itself, such as `"card"`; the `container` mixin can still take its name from a custom property.