Monsoon v0.2.0
Made by Alexandre Kohler Star

Layout

Container queries with utility classes

Viewport breakpoints answer "how wide is the screen". Components usually need to know "how wide is my column". Container queries answer that, and Monsoon exposes them as utility classes you can write straight in your HTML.

3 min readBy Alexandre Kohler

The two pieces

First, mark a parent as a container with the @container class. It sets container-type: inline-size, which makes the element a size container for its width. Then, on any descendant, prefix a utility with a container breakpoint such as @md::

card.html
<div class="@container">
  <div class="flex flex-col @md:flex-row gap-4">
    <img class="rounded-xl @md:w-1/3" src="cover.jpg" alt="Cover">
    <div class="space-y-2">
      <h3 class="text-lg @lg:text-2xl font-bold">Title</h3>
      <p class="text-muted-foreground">Stacks when narrow, sits in a row when wide.</p>
    </div>
  </div>
</div>

The same card now works in a wide main column and in a narrow sidebar, without knowing anything about the page around it. The class container-q does the same as @container if you prefer a name without the at sign.

Container breakpoints

Container breakpoints are measured in rem because containers are usually smaller than screens:

PrefixContainer width at least
@xs:20rem (320px)
@sm:24rem (384px)
@md:28rem (448px)
@lg:32rem (512px)
@xl:36rem (576px)

They are min-width queries, mobile first like the viewport breakpoints: write the narrow layout without a prefix and add the wider layout with a prefix.

Which utilities support them

To keep the stylesheet small, container variants are generated for the utilities you use to rearrange a component:

  • display: block, inline-block, inline, flex, inline-flex, grid, hidden
  • flex direction and wrapping: flex-row, flex-col, flex-wrap, flex-nowrap
  • grid: grid-cols-1 to grid-cols-12, col-span-1 to col-span-12, col-span-full
  • gap, items-* and justify-*
  • padding p-*, px-*, py-* for the common steps
  • width fractions, w-full and w-auto
  • text size text-xs to text-9xl and text alignment

Search the class reference with the "Has @md:" filter for the complete list.

A responsive card grid that needs no breakpoints

Combine the two ideas: the grid uses viewport breakpoints to decide how many columns the page has, and each card uses container queries to decide its own layout inside whatever column width it gets.

layout.html
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
  <div class="lg:col-span-2 @container rounded-2xl border bg-surface p-4">
    <div class="grid grid-cols-1 @md:grid-cols-2 gap-4">...</div>
  </div>
  <aside class="@container rounded-2xl border bg-surface p-4">
    <div class="grid grid-cols-1 @md:grid-cols-2 gap-4">...</div>
  </aside>
</div>
Same card, two container widths

Wide column: this card is at least 28rem, so it uses a row.

Narrow column: same markup, stacked.

Breakpoints or container queries?

Both have a place, and they answer different questions. Use viewport breakpoints (md:, lg:) for decisions about the whole page: how many columns the layout has, whether the navigation collapses, how wide the main content is. Use container queries for decisions inside a component: whether a card shows its image beside or above the text, how many items a list shows per row, how large a heading should be.

A good test is to ask where the component might be reused. A product card that appears in a three column grid, a sidebar and a full width search result cannot know the viewport width that matters to it, because the same viewport gives it three different widths. That card should use container queries. A site header always spans the viewport, so viewport breakpoints are the natural fit.

Because container queries are just classes in Monsoon, you can adopt them gradually. Start with the one component that looks wrong in a sidebar, wrap it in an element with @container, and replace its md: prefixes with @md:. Nothing else on the page has to change, and there is no configuration to update.

Things to know

  • A container cannot query itself. Put @container on a parent and the prefixed classes on its children.
  • container-type: inline-size makes the element ignore the width of its contents for sizing, so give containers a width from their layout (a grid cell, w-full, a flex item).
  • Containers nest. A prefixed class responds to the nearest ancestor container.
  • Container queries are supported in all current major browsers.

Frequently asked questions

What is the difference between md: and @md:?

md: checks the viewport width (768px and up). @md: checks the width of the nearest @container ancestor (28rem and up).

Do I need a build step for container queries?

No. The @container class and the @xs: to @xl: variants are in the stylesheet you link from the CDN.

Can I use container queries and breakpoints together?

Yes. A common pattern is breakpoints for the page grid and container queries inside each component.

Which browsers support container queries?

Current versions of Chrome, Edge, Firefox and Safari. Older browsers ignore the prefixed classes and show the unprefixed, narrow layout.

Try it in ten seconds

Paste this into any HTML page. No install, no build.

index.html
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/monsooncss">

No recent searches

Try , , or .

Recent

Loading the search index

No results for ""

Check the spelling, or search a class name such as px-4.