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

前端 未结 13 1172
一整个雨季
一整个雨季 2020-11-29 01:24

I have a

    that is a flex-box and a bunch of
  • s in it which are the flex-items.

    I am trying to get the

13条回答
  •  眼角桃花
    2020-11-29 02:09

    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

提交回复
热议问题