How to keep wrapped flex-items the same width as the elements on the previous row?

TL;DR

This is not something I'd call a solution per se, but it's a rather elegant workaround that only uses media queries, and more importantly no JavaScript!

Mixin (SCSS):

@mixin flex-wrap-fix($flex-basis, $max-viewport-width: 2000px) {
  flex-grow: 1;
  flex-basis: $flex-basis;
  max-width: 100%;

  $multiplier: 1;
  $current-width: 0px;

  @while $current-width < $max-viewport-width {
    $current-width: $current-width + $flex-basis;
    $multiplier: $multiplier + 1;

    @media(min-width: $flex-basis * $multiplier) {
      max-width: percentage(1/$multiplier);
    }
  }
}

Usage:

Apply the mixin to your flex item:

.flex-item {
  @include flex-wrap-fix(100px)
}

Update:

The above mixin should do the trick, as long as you your flex container width matches your viewport size, as is the case in OP's example. Media queries won't help you otherwise, because they're always based on the viewport width. However, you could use the css-element-queries library and its element queries instead of browser media queries. Here's a mixin that you can apply to the flex container:

@mixin flex-container-wrap-items($flex-basis, $max-expected-width: 2000px) {
  display: flex;
  flex-wrap: wrap;

  > * {
    max-width: 100%;
    flex-grow: 1;
    flex-basis: $flex-basis;
  }

  $multiplier: 1;
  $current-width: 0px;

  @while $current-width < $max-expected-width {
    $current-width: $current-width + $flex-basis;
    $multiplier: $multiplier + 1;

    &[min-width~="#{$flex-basis * $multiplier}"] > * {
      max-width: percentage(1/$multiplier);
    }
  }
}

Explanation:

Let's say, as per the OP's example, we want each item to have a maximum width of 100px, so we know that for a browser width of 100px we can fit one item per row, and so on:

| Viewport Width | Max Item Count Per Row | Item Width (min-max) |
|----------------|------------------------|----------------------|
| <= 100         | 1                      | 0px - 100px          |
| <= 200         | 2                      | 50px - 100px         |
| <= 300         | 3                      | 50px - 100px         |
| <= 400         | 4                      | 50px - 100px         |
| <= 500         | 5                      | 50px - 100px         |
| <= 600         | 6                      | 50px - 100px         |

We can write media queries to create the following rules:

| Viewport Width | Max Item Count Per Row | Item Max Width | Calculation |
|------------------------------------------------------------------------|
| <= 100px       | 1                      | 100%           | (100/1)     |
| <= 200px       | 2                      | 50%            | (100/2)     |
| <= 300px       | 3                      | 33.33333%      | (100/3)     |
| <= 400px       | 4                      | 25%            | (100/4)     |
| <= 500px       | 5                      | 20%            | (100/5)     |
| <= 600px       | 6                      | 16.66666%      | (100/6)     |

Like this:

li {
  flex: 1 0 0
  max-width: 100%;
}

@media(min-width: 200px) {
  li { max-width: 50%; }
}

@media(min-width: 300px) {
  li { max-width: 33.33333%; }
}

@media(min-width: 400px) {
  li { max-width: 25%; }
}

@media(min-width: 500px) {
  li { max-width: 20%; }
}

@media(min-width: 600px) {
  li { max-width: 16.66666%; }
}

Of course, that's repetitive, but most likely you're using some sort of preprocessor, which can take care of the repetitiveness for you. That's precisely what the mixin in the above TL;DR section does.

All we have to do now is to specify 100px as our flex-basis, and optionally the maximum browser window width (defaults to 2000px) to create the media queries for:

@include flex-wrap-fix(100px)

Example

Finally, a forked version of the original CodePen example with the desired output, using the above mixin:

http://codepen.io/anon/pen/aNVzoJ

demo of the solution


Alternative - grid

its not the answer of what you want, but it nice to use:

display: grid
grid-template-columns: repeat(auto-fill, minmax(70px, 1fr))

https://codepen.io/omergal/pen/povzJrz

ul {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(70px, 1fr));
}

li {
  min-width: 40px;
  max-width: 100px;
}

ul,
li {
  margin: 0;
  padding: 0;
  list-style: none;
}
ul {
  background-color: tomato;
}

li {
  margin: 0.5em;
  background-color: darkgreen;
}

img {
  width: 100%;
  opacity: 0.5;
}
figure,
img {
  margin: 0;
  padding: 0;
}
<ul>
      <li>
        <figure>
          <img src="http://placekitten.com/g/250/250">
        </figure>
      </li>
      <li>
        <figure>
          <img src="http://placekitten.com/g/101/101">
        </figure>
      </li>
      <li>
        <figure>
          <img src="http://placekitten.com/g/201/201">
        </figure>
      </li>
      <li>
        <figure>
          <img src="http://placekitten.com/g/150/150">
        </figure>
      </li>
      <li>
        <figure>
          <img src="http://placekitten.com/g/80/80">
        </figure>
      </li>
      <li>
        <figure>
          <img src="http://placekitten.com/g/111/111">
        </figure>
      </li>
      <li>
        <figure>
          <img src="http://placekitten.com/g/40/40">
        </figure>
      </li>
      <li>
        <figure>
          <img src="http://placekitten.com/g/110/110">
        </figure>
      </li>
      <li>
        <figure>
          <img src="http://placekitten.com/g/75/75">
        </figure>
      </li>
      <li>
        <figure>
          <img src="http://placekitten.com/g/89/89">
        </figure>
      </li>
      <li>
        <figure>
          <img src="http://placekitten.com/g/150/150">
        </figure>
      </li>
      <li>
        <figure>
          <img src="http://placekitten.com/g/32/32">
        </figure>
      </li>
      <li>
        <figure>
          <img src="http://placekitten.com/g/61/61">
        </figure>
      </li>
      <li>
        <figure>
          <img src="http://placekitten.com/g/320/320">
        </figure>
      </li>
    </ul>


I have been experimenting with your codepen and I set flex: 0 1 10%

Of course you can set the flex-basis whatever you want, I just wanted to prove the point, that if you set flex basis and allow it to shrink, it will behave much nicer in this case.

I think this is what you needed. Here's the preview: http://codepen.io/anon/pen/bwqNEZ

Cheers

Tags:

Css

Flexbox