6

My flex container oddly (in my opinion) ignores max-width and wrap.

The intention is to have a (consistently) large item to the left and zero, one, two or three smaller ones besides or below that one. If there's only one, it should display to the right, if there are two or three, they ought all to go to the next line (equally spaced).

0) -------------------------------
   |         large item          |
   -------------------------------
1) -------------------------------
   |     large item      | small |
   -------------------------------
2) -------------------------------
   |         large item          |
   -------------------------------
   |     small    |    small     |
   -------------------------------
3) -------------------------------
   |         large item          |
   -------------------------------
   |  small  |  small  |  small  |
   -------------------------------

I thought flexbox would "just have to do" exactly that. But now it won't wrap as expected. The items to the right (which should be on the second row) just overflow the flexbox.

Can anyone see what I do wrong? Thank you very much!

An Example is here: Codepen

.container {
  display: flex;
  flex-wrap: wrap; /* ? */
  
  background-color: #ccc;
  padding: 10px 0;
  max-width: 1024px;
  margin: 0 auto;
}
   
.item_large {
  flex: 1 0 450px;
  background-color: green;
  height: 40px;
  border-radius: 2px;
}
   
.container_2 {
  display: flex;
  flex-wrap: nowrap;
  flex: 1 0 190px;
  margin: 0 -12px;
}
   
.item_small {
  flex: 1 0 190px;
  background-color: blue;
  height: 40px;
  border-radius: 2px;
  margin: 0 12px;
}

@media screen and (max-width: 719px) {
  .container_2 {
    flex-wrap: wrap;
  }
    
  .item_small {
    flex: 1 0 320px;
  }  
}

@media screen and (min-width: 720px) {

  .item_small:first-child:nth-last-child(1) {
    margin-left: 36px;
  }
}
<div class="container">
  <div class="item_large"></div>
</div>
</div><br /><br />
<div class="container">
  <div class="item_large"></div>
  <div class="container_2">
    <div class="item_small"></div>
  </div> 
</div><br /><br />
<div class="container">
  <div class="item_large"></div>
  <div class="container_2">
    <div class="item_small"></div><div class="item_small"></div>
  </div>
</div><br /><br />
<div class="container">
  <div class="item_large"></div>
  <div class="container_2">
    <div class="item_small"></div><div class="item_small"></div><div class="item_small"></div>
  </div>
</div>
Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
Pumba Njie
  • 63
  • 1
  • 5
  • they are not overflowing the main container, but you have nested container and the in inner one you have `nowrap` – Temani Afif Apr 14 '18 at 14:17
  • Yes, the inner container shouldn't wrap (its content) because if there's only one element inside, it ought to remain on line one, if there's more than one, they're expected to overflow the main container and therefore align (unwrapped) all on the line below. How do you (@temani-afif) mean: they're not overflowing? I do think they are (?) – Pumba Njie Apr 14 '18 at 14:27
  • check the console and you will see that the element are overlfow the inner container ... and the main container is not getting overflowed, so the issue is with the inner container – Temani Afif Apr 14 '18 at 14:29
  • Sorry, I don't get it :/ How come the "primary" container (with two children) doesn't get overflown by a too large second child? – Pumba Njie Apr 14 '18 at 14:44
  • because the second one is not large :) check the console and inspect the element .. the second one is getting overflowed so it's not too large as you think, he is small but content are outside – Temani Afif Apr 14 '18 at 14:50
  • right :( looks like a completely hopeless situation. Is there any way I get it (the overflown second container) to "properly register" its escaping children and take its appropriate width? – Pumba Njie Apr 14 '18 at 14:54
  • you can simply remove the inner container and make all the element with the same one so you can you easily manage – Temani Afif Apr 14 '18 at 14:59
  • I did try that before... and thought it might work more easily with the second container. If I remove it [like here](https://codepen.io/aebbeeri/pen/ZxdeGL) the wrapping doesn't (magically) happen how I wish :) => meaning: I don't know how I make the two or three small items evenly spaced and neatly (and unitedly) go to the second row. – Pumba Njie Apr 14 '18 at 15:15
  • 1
    Update: with a little "cheating" we might (after a bit more work to get the margins to behave nicely) get there: [updated example from above](https://codepen.io/aebbeeri/pen/ZxdeGL). Thank you very much @Temani Afif for pushing me in the right direction! – Pumba Njie Apr 14 '18 at 15:52

3 Answers3

1

You need to understand better the flex grid. Here is a good post Flex Docs.

The main issue you are having id flex-grow: 1

  .container {
        display: flex;
        justify-content: space-between;
        align-items: center;
        margin-bottom: 1em;
    }

    .item_large {
        flex: 1;
        background-color: green;
    }

    .item_small {
        flex: 0 0 190px;
        background-color: steelblue;
    }
    
    [class^="item_"] {
      height: 2em;
      border-radius: 5px;
      margin: 0.5em;
      display: flex;
      align-items: center;
    }
<div class="container">
    <div class="item_large"></div>
</div>
<div class="container">
    <div class="item_large"></div>
    <div class="item_small">190px</div>
</div>
<div class="container">
    <div class="item_large"></div>
</div>
<div class="container">
    <div class="item_large"></div>
    <div class="item_large"></div>
</div>
<div class="container">
    <div class="item_large"></div>
</div>
<div class="container">
    <div class="item_large"></div>
    <div class="item_large"></div>
    <div class="item_large"></div>
</div>

You might want to learn a bit more about flex grid, so you can make any grid you want in the future. You can use the same idea on .item_small to make a grid item_1 --> 10% | item_2 --> 20% | and so on...

T04435
  • 12,507
  • 5
  • 54
  • 54
  • Thank you! That looks great and I absolutely do have to digg a lot deeper into the workings of flexbox. – Pumba Njie Apr 15 '18 at 12:03
  • With some adjustments it does just what I need: [Codepen](https://codepen.io/aebbeeri/pen/KojGzy)) :) – Pumba Njie Apr 15 '18 at 12:36
  • Thanks @PumbaNjie If you ready to mark [Correct Answer](https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work) – T04435 Apr 16 '18 at 01:17
0

You have the flex container set to max-width: 1024px.

You have the left-side item (.item_large) set to flex-basis: 450px.

You have the right-side item (.container_2) set to flex-basis: 190px.

450 + 190 = 640

Since the combined width of the primary flex items is 640px, which is substantially less than the max-width: 1024px on the container, why would they wrap? There's still a lot of space on the line.

Instead of 190px on .container_2, try something like 600px, which will make the items exceed the 1024px max-width on the container. Actually, 575px on the .container_2 would be enough (1025px total for both items), except you have negative margins that need to be factored in.

.container {
  display: flex;
  flex-wrap: wrap;  /* ? */
  background-color: #ccc;
  padding: 10px 0;
  max-width: 1024px;
  margin: 0 auto;
}

.item_large {
  flex: 1 0 450px;
  background-color: green;
  height: 40px;
  border-radius: 2px;
}

.container_2 {
  display: flex;
  flex-wrap: nowrap;
  flex: 1 0 600px;  /* adjusted */
  margin: 0 -12px;
}

.item_small {
  flex: 1 0 190px;
  background-color: blue;
  height: 40px;
  border-radius: 2px;
  margin: 0 12px;
}

@media screen and (max-width: 719px) {
  .container_2 {
    flex-wrap: wrap;
  }
  .item_small {
    flex: 1 0 320px;
  }
}

@media screen and (min-width: 720px) {
  .item_small:first-child:nth-last-child(1) {
    margin-left: 36px;
  }
}
<div class="container">
  <div class="item_large"></div>
</div>
</div><br /><br />
<div class="container">
  <div class="item_large"></div>
  <div class="container_2">
    <div class="item_small"></div>
  </div>
</div><br /><br />
<div class="container">
  <div class="item_large"></div>
  <div class="container_2">
    <div class="item_small"></div>
    <div class="item_small"></div>
  </div>
</div><br /><br />
<div class="container">
  <div class="item_large"></div>
  <div class="container_2">
    <div class="item_small"></div>
    <div class="item_small"></div>
    <div class="item_small"></div>
  </div>
</div>

revised codepen

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • But if you look at his diagram, he want to have 1 green + 1 blue in one line ... and if there is more than 1 blue, they will wrap. Check his last comment and you will see that he got what we want we a bit of cheating – Temani Afif Apr 14 '18 at 21:59
  • Right. I posted the answer primarily to identify the problem. My solution is of secondary importance and meant to illustrate the problem. – Michael Benjamin Apr 15 '18 at 03:38
0

The desired effect (as described in the question) can be achieved through the use of flexbox (for the equal spacing) and a bit of item counting (inspired by thist post).

This might look something like the following Codepen

.container {
  display: flex;
  flex-wrap: wrap;
  padding: 10px 0;
  background: #ccc;    
  margin: 0 -20px;
}
  
.item_large, 
.item_small {
  height: 40px;
  border-radius: 2px;
  margin: 0 12px;   
}
  
.item_large {
  flex: 1 0 450px;
  background-color: green;
}
  
.item_small {
  flex: 1 0 202px;
  background-color: blue;
}

@media screen and (max-width: 719px) {   
  .item_large, 
  .item_small {
 flex: 1 0 100%;
 margin: 0;
  } 
}
  
@media screen and (min-width: 720px) {   
  .item_large:first-child:nth-last-child(3), 
  .item_large:first-child:nth-last-child(4) {
    flex: 0 1 calc(100% - 24px);
  }
}
<div class="container">
     <div class="item_large"></div>
</div><br /><br />
<div class="container">
  <div class="item_large"></div>
     <div class="item_small"></div> 
</div><br /><br />
<div class="container">
  <div class="item_large"></div>
  <div class="item_small"></div><div class="item_small"></div>
</div><br /><br />
<div class="container">
  <div class="item_large"></div>
     <div class="item_small"></div><div class="item_small"></div><div class="item_small"></div> 
</div>

Thanks to (insistance from) @temani-afif and (research by) @matthematics :). You saved my day (and much more)!

Pumba Njie
  • 63
  • 1
  • 5