skip to Main Content

I have a number of DIVs nested within each other:

<div id="outer">
  <div id="inner">
    <div id="content"></div>
  </div>
</div

The width of "outer" is set as a percentage of the viewport width.
In the CSS I have container queries set on both "outer" and "inner":

#outer {
  container: outer / size;
}
#inner {
  container: inner / size;
}

Everything works as expected until I try to set the width of "content" as a percentage of "outer" with :

@container outer (min-width: 100px) {
  #content {
    width: 40cqw;
  }
}

What I expect to happen is that "content" gets sized with respect to "outer". What does happen is that "content" gets size with respect to "inner".

If I delete the container query on "inner" the width of "content" is set with respect to "outer".

How can I get the width of "content" to be set with respect to the width of "outer"?

Edit:
Here’s a simple page that "fails":

#outer {
  box-sizing: border-box;
  position: absolute;
  left: 10%;
  right: 10%;
  top: 10%;
  bottom: 10%;
  border: 1px dotted red;
  container: outer / size;
}

#inner {
  box-sizing: border-box;
  position: relative;
  left: 10%;
  top: 10%;
  width: 300px;
  height: 300px;
  border: 1px dashed blue;
  /* Uncomment the following line to see it fail(?) */
  /*container: inner / size;*/
}

#content {
  height: 100px;
  background-color: aqua;
}

@container outer (min-width: 10px) {
  #content {
    width: 40cqw;
  }
}
<div id="outer">
  <div id="inner">
    <div id="content"></div>
  </div>
</div>

4

Answers


  1. The problem arises because container queries apply to the nearest container ancestor. In your case, #content is inside #inner, which has its own container query. As a result, the width of #content is sized relative to #inner rather than #outer.

    What you could do is either

    1. Remove the container property from #inner if it’s not crucial, ensuring #content only references #outer.

    2. Use a media query for #content that’s based on #outer’s width instead of relying on container queries, since media queries are not restricted by nesting (not the most elegant solutions, but should do the trick) .

       #content {
         width: 100%;
       }
      
       @media (min-width: 600px) {
         #outer {
           width: 80%; /* Outer container grows */
         }
      
         #content {
           width: 50%; /* Content width adapts to outer */
         }
       }
      

    This method lets you adjust #content relative to #outer using media queries, "bypassing" the immediate parent #inner.

    Login or Signup to reply.
  2. Why don’t you use CSS Custom Properties (variables)? Something like this:

        #outer {
          container: outer / size;
          --outer-width: 100%;
        }
    
        @container outer (min-width: 100px) {
          #content {
            width: calc(var(--outer-width) * 0.4);
          }
        }
    
    Login or Signup to reply.
  3. As the outer element has its width set in relation to the viewport, you can use those units (vw) rather than cqw to set the width of content.

    This snippet sets a CSS variable to the % of the left (and right) properties of outer.

    This value is then used to calculate the width of content.

    <style>
      #outer {
        box-sizing: border-box;
        position: absolute;
        --s: 10;
        left: calc(var(--s) * 1%);
        right: calc(var(--s) * 1%);
        top: 10%;
        bottom: 10%;
        border: 1px dotted red;
        container: outer / size;
      }
      
      #inner {
        box-sizing: border-box;
        position: relative;
        left: 10%;
        top: 10%;
        width: 300px;
        height: 300px;
        border: 1px dashed blue;
        /* Uncommented the following line where it used to fail */
        container: inner / size;
      }
      
      #content {
        height: 100px;
        background-color: aqua;
      }
      
      @container outer (min-width: 100px) {
        #content {
          width: calc((100vw - (2vw * var(--s))) * 40 / 100);
        }
      }
    </style>
    <div id="outer">
      <div id="inner">
        <div id="content"></div>
      </div>
    </div>
    Login or Signup to reply.
  4. Maybe you could use grid layout to achieve such condition:

    #outer {
      box-sizing: border-box;
      position: absolute;
      left: 10%;
      right: 10%;
      top: 10%;
      bottom: 10%;
      border: 1px dotted red;
      container: outer / size;
    }
    
    #inner {
      box-sizing: border-box;
      position: relative;
      left: 10%;
      top: 10%;
      width: 300px;
      height: 300px;
      border: 1px dashed blue;
      container: inner / size;
      
      /* use grid layout */
      display: grid;
    }
    
    #content {
      height: 100px;
      background-color: aqua;
    }
    
    /* when container query is active */
    @container outer (min-width: 10px) {
      #inner {
        /* set the grid layout to be 40cqw, so #container could use its size */
        grid-template-columns: 40cqw;
      }
    }
    <div id="outer">
      <div id="inner">
        <div id="content"></div>
      </div>
    </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search