Skip to main content

    Lesson 23 • Advanced Track

    Container Queries & Modern Responsive

    After this lesson you'll build components that style themselves by their container's size — so a single card works in a wide column or a narrow sidebar without a single media query.

    What You'll Learn

    • Why container queries beat media queries for reusable components
    • Turn a wrapper into a query container with container-type
    • Name containers and target them with container-name
    • Write @container (min-width: …) rules that read the parent's size
    • Size things with container units: cqw, cqh, cqi, cqb
    • Know when to still reach for a media query

    Prerequisites: You should be comfortable with selectors from CSS Basics & Selectors and have met @media queries for responsive design. Container queries are the component-level upgrade to that idea.

    💡 Real-World Analogy

    Think of a media query as dressing for the weather forecast for the whole city: everyone hears "it's cold downtown" and puts on a coat, even the person sitting in a warm room. A container query is dressing for the room you're actually in — you check the temperature where you are and react to that.

    A card component is the person. With media queries it dresses for the screen size (the city forecast), which is wrong when it's placed in a narrow sidebar on a big monitor. With a container query it dresses for its own container (the room), so it always fits — wherever you drop it.

    📊 Media Query vs Container Query

    FeatureMedia QueryContainer Query
    MeasuresViewport (screen) sizeA parent container's size
    Reusability⚠️ Tied to page layout✅ Works wherever you place the component
    Syntax@media (min-width: 400px)@container (min-width: 400px)
    Setup neededNonecontainer-type: inline-size on the parent

    1. Make a Container, Then Query It

    Container queries are a two-step deal. First you mark an element as a query container with container-type: inline-size — this says "measure my width so my children can ask about it." inline-size means width-only containment, which is what you want almost every time. Optionally give it a name with container-name so you can target a specific container later.

    Then, on a child, you write an @container rule: @container card (min-width: 400px) { … }. The browser checks the nearest ancestor that is a container and applies those styles when its width crosses the threshold. Run the example — the same card is vertical in the narrow panel and horizontal in the wide one, with no media query anywhere.

    Worked Example: A Card That Responds to Its Container

    Same HTML in a narrow panel vs a wide panel — @container does the rest

    Try it Yourself »
    Code Preview
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Container Query Card</title>
      <style>
        * { box-sizing: border-box; margin: 0; padding: 0; }
        body { background: #0f172a; font-family: system-ui, sans-serif;
               color: #e5e7eb; padding: 30px; }
        h1 { color: #3b82f6; margin-bottom: 6px; }
        h2 { color: #22c55e; margin: 22px 0 10px; font-size: 1rem; }
        .label { color: #64748b; font
    ...

    2. Container Query Units (cqw, cqh, cqi, cqb)

    Queries flip layouts at breakpoints; container units let you scale things smoothly with the container. They mirror viewport units, but relative to the query container instead of the screen: cqw is 1% of the container's width, cqh is 1% of its height, and cqi/cqb are the writing-mode-aware versions (inline/block — width/height in normal left-to-right text).

    They pair beautifully with clamp(): font-size: clamp(1rem, 5cqi, 3rem) means "5% of the container's width, but never smaller than 1rem or larger than 3rem." Resize the box below and watch the text and bar respond to the container, not the window.

    Worked Example: Scaling with cqi Units

    Drag to resize the box — type and bar scale to the container, not the viewport

    Try it Yourself »
    Code Preview
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Container Query Units</title>
      <style>
        * { box-sizing: border-box; margin: 0; padding: 0; }
        body { background: #0f172a; font-family: system-ui, sans-serif;
               color: #e5e7eb; padding: 30px; }
        h1 { color: #3b82f6; margin-bottom: 8px; }
        .hint { color: #94a3b8; font-size: 13px; margin-bottom: 14px; }
    
        /* This box is a container AND is resizable so you can experiment. */
        .box {
          container-
    ...

    🎯 Your Turn 1 — Make It a Container

    The @container rule is already written, but it never fires because the wrapper isn't a container yet. Add the two lines (container-type and container-name) so the badge turns green. The expected result is in the comments.

    🎯 Your Turn 1: Add container-type and container-name

    Fill in the two blanks so the existing @container rule applies

    Try it Yourself »
    Code Preview
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <style>
        * { box-sizing: border-box; }
        body { background: #0f172a; color: #e5e7eb;
               font-family: system-ui, sans-serif; padding: 24px; }
    
        /* 🎯 YOUR TURN 1 — the @container rule below is already written, but it
           never fires because the wrapper isn't a container yet. Add the two
           lines that turn .wrapper into a width-query container. */
    
        .wrapper {
          width: 480px;
          border: 1px dashed #334155;
          border-radi
    ...

    🎯 Your Turn 2 — Write the Query and a Unit

    Containment is set up for you. Now write the @container breakpoint and use a cqi unit: make the heading scale with the container, and switch the tile to two columns when the container is at least 450px wide. Fill in the three blanks.

    🎯 Your Turn 2: Write @container (min-width: …) and a cqi font-size

    Fill in the blanks to flip the tile to two columns and scale the heading

    Try it Yourself »
    Code Preview
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <style>
        * { box-sizing: border-box; }
        body { background: #0f172a; color: #e5e7eb;
               font-family: system-ui, sans-serif; padding: 24px; }
    
        /* 🎯 YOUR TURN 2 — containment is already set up. Write the query and a unit. */
    
        .panel {
          container-type: inline-size;   /* ready to be queried */
          width: 500px;
          border: 1px dashed #334155; border-radius: 10px; padding: 12px;
        }
    
        .tile { background: #1e293b; padding: 1
    ...

    🧩 Mini-Challenge — A Self-Adapting Profile

    Now without the blanks. Build a profile component that stacks vertically by default and goes horizontal (with a larger, cqi-scaled name) once its container passes 380px — then drop the same markup into a narrow frame and a wide frame. No media queries allowed. The brief and expected result are in the comments.

    🧩 Mini-Challenge: Container-responsive profile card

    Outline only — build it yourself; expected result is in the comments

    Try it Yourself »
    Code Preview
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <style>
        * { box-sizing: border-box; }
        body { background: #0f172a; color: #e5e7eb;
               font-family: system-ui, sans-serif; padding: 24px; }
    
        /* 🎯 MINI-CHALLENGE: a self-adapting "profile" component
           1. Make .frame a width container  (container-type: inline-size)
           2. Default (narrow) layout: .profile stacks vertically (flex-direction: column)
           3. Add @container (min-width: 380px):
                - .profile becomes a row (
    ...

    Container or Media Query?

    • Container query: any reusable component (card, widget, media object) that might live in columns of different widths.
    • Container units: type or spacing that should scale fluidly with the component's own width.
    • Media query: page-level decisions — overall margins, how many columns the whole page has.
    • Media query: device-level concerns — print styles, prefers-reduced-motion, prefers-color-scheme.
    • Both together: media query sets the page's column count; each column's components adapt with container queries.

    Common Errors

    • Forgetting container-type. Symptom: your @container block is ignored and nothing changes. Cause: no ancestor is a container. Fix: add container-type: inline-size to the wrapper element you want to query.
    • Querying the element itself. Symptom: you put container-type and the @container styles on the same element and it doesn't react. Cause: an element can't query its own size. Fix: put containment on a wrapper and style the child inside it.
    • Naming mismatch. Symptom: @container card (…) never matches. Cause: the container's container-name isn't card (or you have a typo). Fix: match the names exactly, or drop the name from the query to target the nearest container of any name.
    • Assuming no fallback / ignoring old browsers. Container queries are Baseline in 2026, but if you support legacy browsers the @container block is simply skipped there. Fix: make the styles outside the query a complete, sensible default so the component still works as a progressive enhancement.

    📋 Quick Reference — Container Queries

    WhatSyntaxDoes
    Enable (width)container-type: inline-size;Makes the element a width-query container
    Enable (both axes)container-type: size;Width + height queries (element needs explicit height)
    Name itcontainer-name: card;A name so a query can target this container
    Shorthandcontainer: card / inline-size;Sets name and type in one line
    Query@container card (min-width: 400px) { … }Styles a child when the container is wide enough
    Unitscqw cqh cqi cqb1% of container width / height / inline / block

    💡 Rule of thumb: containment goes on the wrapper; the @container styles and cq* units go on the children inside it.

    Frequently Asked Questions

    What is the difference between a container query and a media query?

    A media query asks about the viewport — 'how wide is the screen?' A container query asks about an element's parent — 'how wide is my container?' That difference is everything for reusable components: a card dropped into a wide main column and the same card dropped into a narrow sidebar can lay themselves out differently, because each reads its own container rather than the shared screen width.

    Why isn't my @container rule doing anything?

    Almost always because the ancestor you expect to query is not actually a container. A @container rule measures the nearest ancestor that has container-type set (inline-size or size). If no ancestor declares container-type, there is nothing to query and the rule is silently ignored. Add container-type: inline-size to the wrapper, then your @container rules will fire.

    Can an element query its own size?

    No. The element you style with a @container rule is a child of the container, never the container itself. A box cannot apply containment to itself and then react to its own size — that would create a layout feedback loop. The standard pattern is a wrapper with container-type, and the component you actually style lives inside it.

    What do cqw, cqh, cqi, and cqb mean?

    They are container query units, sized relative to the query container instead of the viewport. cqw is 1% of the container's width and cqh is 1% of its height; cqi (inline) and cqb (block) are the writing-mode-aware versions — in left-to-right text, cqi tracks width and cqb tracks height. So 50cqi is half the container's width, the container-scoped cousin of 50vw.

    Do container queries replace media queries?

    No — they complement them. Media queries are still the right tool for page-level decisions tied to the device: overall page margins, how many columns the whole layout has, print styles, or prefers-reduced-motion. Container queries are for component-level adaptation, so a component stays reusable wherever you place it. Most modern layouts use both.

    Is browser support good enough to use container queries in production?

    Yes for current browsers — size container queries (container-type, @container, and cq* units) shipped across Chrome, Edge, Safari, and Firefox in 2023, so they are Baseline and widely available in 2026. If you must support older browsers, provide a sensible default layout outside the @container block (it acts as the fallback) and treat the container query as a progressive enhancement.

    🎉 Lesson Complete

    • ✅ Container queries style components by their parent's size, not the viewport
    • ✅ Step 1: container-type: inline-size (and optional container-name) on a wrapper
    • ✅ Step 2: @container (min-width: 400px) on a child to flip its layout
    • cqw / cqh / cqi / cqb scale things to the container, like vw/vh do for the screen
    • ✅ Containment goes on the wrapper — an element can't query its own size
    • ✅ Media queries still own page-level and device-level decisions; use both together

    What's next: take control of which rules win across your stylesheet in CSS Cascade & Layers.

    Sign up for free to track which lessons you've completed and get learning reminders.

    Previous

    Cookie & Privacy Settings

    We use cookies to improve your experience, analyze traffic, and show personalized ads. You can manage your preferences below.

    By clicking "Accept All", you consent to our use of cookies for analytics and personalized advertising. You can customize your preferences or reject non-essential cookies.

    Privacy PolicyTerms of Service

    Install LearnCodingFast

    Learn faster with the app on your home screen.