Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make flex items wrap in nested flex containers before containers themselves wrap in main container

Tags:

html

css

flexbox

If I have a flexbox container containing multiple containers, how do I make the containers' contained items wrap before the containers themselves?

For example (codepen):

HTML

<div>
    <row>
        <column id="first">
            <widget width=1 height=8></widget>
            <widget width=1 height=8></widget>
        </column>
        <row id="second">
            <widget></widget>
            <widget></widget>
            <widget></widget>
        </row>
    </row>
</div>

CSS

column, row, widget {
  background: RGBA(0,0,0,.2);
  margin: 1em;
  display: flex;
  flex-wrap: wrap;
  align-items: top;
  align-content: flex-start;
}

row {
  flex-direction: row;
}

column {
  flex-direction: column;
}

widget {
  min-height: 100px;
  flex-grow: 2;
  flex-shrink: 1;
  width: calc(25% - 3em);
  min-width: 300px;
  height: 100px;
  flex-basis: 0;
  padding: .5em;
  display: block;
}

widget[width=1] {
  flex-grow: 1;
  min-width: 150px;
}

widget[width=4] {
  flex-grow: 4;
  min-width: 600px;
}

widget[width=8] {
  flex-grow: 8;
  min-width: 1200px;
}

widget[height=1] {
  min-height: 150px;
}

widget[height=4] {
  min-height: 600px;
}

widget[height=8] {
  min-height: 1200px;
}

widget {
  background: RGBA(200,0,20,.5);
}

I want the items in #second to wrap before #second itself wraps below #first. In other words, I always want to try wrapping the innermost items before trying to wrap the outermost ones, which seems to be the opposite of what happens by default. Is there any way to do this?

EDIT: There were requests for visual clarification.

2 containers with several items each: full width

Desired behavior, slightly smaller. Innermost items wrap before their containers.

partially wrapped

Desired behavior, smaller still.

inner items fully wrapped

Desired behavior, smallest. After the innermost items can't wrap any more, the containers finally wrap.

containers wrapped

What actually happens: the containers wrap before their contents.

enter image description here

enter image description here

like image 419
whereswalden Avatar asked Sep 18 '15 21:09

whereswalden


People also ask

Can you have a flex container within a Flex container?

You can create two dimensional layouts by nesting a flex container inside another one. Flexbox is inherently a one dimensional layout model. Flex items within a flex container can be laid out either horizontally or vertically, but not both.

Can you have nested flex boxes?

Nested flex boxesIt's possible to create some pretty complex layouts with flexbox. It's perfectly OK to set a flex item to also be a flex container, so that its children are also laid out like flexible boxes.

What flexbox property do you use to define how Flex items will be wrapped?

The flex-wrap CSS property sets whether flex items are forced onto one line or can wrap onto multiple lines. If wrapping is allowed, it sets the direction that lines are stacked.


1 Answers

I don't believe there are any flex properties that make this process simple and easy. However, the flexbox specification does allow for absolutely-positioned flex children. So with a combination of media queries and absolute positioning, the flex items within the container can be made to wrap before the container itself wraps.

Try this:

HTML (no changes)

CSS (add media queries and absolute positioning)

#second { position: relative; } 
/* establishes nearest positioned ancestor for absolute positioning */

@media screen and (max-width: 1000px) { 
    #second widget:nth-child(3) { 
        position: absolute; 
        left: 0; 
        bottom: 0; 
        width: 90%; }
    }

@media screen and (max-width: 800px) {  
    #second { height: 375px; }
    #second widget:nth-child(2) { 
        position: absolute; 
        left: 0; 
        bottom: 127px; 
        width: 75%; }
    #second widget:nth-child(3) { 
        position: absolute; 
        left: 0; 
        bottom: 0; 
        width: 75%; }   
    }

/* final media query removes absolute positioning and restores flex properties */       
@media screen and (max-width: 600px) {  
    column, row, widget { flex-wrap: wrap; }
    #second widget {
        position: static;
        width: calc(25% - 3em);
        min-width: 300px;
    }

Revised Codepen

Note that although this code does what the question asks – it wraps flex items in their container before the container itself wraps – it's only meant to convey the basic concept of the solution. Issues like margin and width for flex items, which I considered beyond the scope of this question, may still need to be addressed.

like image 57
Michael Benjamin Avatar answered Oct 28 '22 14:10

Michael Benjamin