Как сохранить обернутые гибкие элементы той же ширины, что и элементы предыдущей строки?

У меня есть <ul>, который является гибкой коробкой и связкой <li> в ней, которые являются элементами flex.

Я пытаюсь получить <li> гибкую ширину, которая остается между двумя размерами, используя min-width и max-width. Он отлично работает, пока они находятся на одной линии. Однако, когда они обертываются, <li> на новой строке использует как можно больше места. Это означает, что они маленькие на первой строке и большие на второй строке, когда их всего лишь несколько.

Есть ли способ сообщить flexbox, чтобы элементы сохранялись после упаковки, сохраняя гибкую ширину?

демонстрационная версия:

enter image description here

Мой код выглядит следующим образом:

<ul>
  <li>
    <figure>
      <img src="http://placekitten.com/g/250/250">
    </figure>
  </li>
  <li>
    <figure>
      <img src="http://placekitten.com/g/100/100">
    </figure>
  </li>
  <!-- ... -->
</ul>

И CSS:

ul
  display: flex
  flex-wrap: wrap

  li
    min-width: 40px
    max-width: 100px
    flex: 1 0 0

Вот живой пример кода coden с дополнительными комментариями, измените размер своего окна, чтобы увидеть его обертывание.

Ответы

Ответ 1

TL; DR

Это не то, что я бы назвал решением как таковым, но это довольно изящное обходное решение, которое использует только медиа-запросы и, что более важно, 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);
    }
  }
}

Использование:

Примените mixin к элементу flex:

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

Обновление:

Вышеуказанный mixin должен делать трюк, если вы используете ширину контейнера гибкого контейнера в соответствии с размером вашего видового экрана, как это имеет место в примере OP. Запросы в средствах массовой информации не помогут вам в противном случае, потому что они всегда основаны на ширине видового экрана. Тем не менее, вы можете использовать библиотеку css-element-queries и свои запросы к элементу вместо запросов к медиа-браузерам. Здесь находится mixin, который вы можете применить к контейнеру flex:

@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);
    }
  }
}

Пояснение:

Скажем, согласно примеру OP, мы хотим, чтобы каждый элемент имел максимальную ширину 100px, поэтому мы знаем, что для ширины браузера 100px мы можем поместить один элемент в строку и так далее:

| 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         |

Мы можем писать медиа-запросы для создания следующих правил:

| 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)     |

Вот так:

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%; }
}

Конечно, это повторяющийся, но, скорее всего, вы используете какой-то препроцессор, который может позаботиться о повторении для вас. Именно это делает mixin в разделе TL, DR.

Теперь нам нужно указать 100px как наш flex-basis и, при необходимости, максимальную ширину окна браузера (по умолчанию - 2000px), чтобы создать медиа-запросы для:

@include flex-wrap-fix(100px)

Пример

Наконец, раздвоенная версия исходного примера CodePen с требуемым выходом, используя вышеупомянутый mixin:

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

демонстрация решения

Ответ 2

Я экспериментировал с вашим кодепом, и я установил flex: 0 1 10%

Конечно, вы можете установить гибкую основу независимо от того, что хотите, я просто хотел доказать суть этого вопроса: если вы установите гибкость базы и позвольте ей сжиматься, в этом случае она будет вести себя намного лучше.

Я думаю, что это то, что вам нужно. Здесь предварительный просмотр: http://codepen.io/anon/pen/bwqNEZ

Приветствия

Ответ 3

Не работает он очень хорошо, но вы можете добиться чего-то в этом направлении с помощью столбцов.

column-gap: 10px;
column-width: 150px;

https://codepen.io/hobbeshunter/pen/OgByNX

Ответ 4

Мое решение не идеально, поскольку оно опирается на JQuery: http://codepen.io/BigWillie/pen/WwyEXX

CSS

ul {
  display: flex;
  flex-wrap: wrap;
}

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

JavaScript

var eqRowFlexItem = function(elem) {
    var w;
    var $elem = $(elem);
    // Clear out max-width on elements
    $elem.css('max-width', '');
    w = $(elem).eq(0).width();
    $(elem).css('max-width', w);
}

eqRowFlexItem('li');

$(window).resize(function() {
    eqRowFlexItem('li');
});

Я не совсем уверен, отвечает ли он на эту проблему. Я нашел этот пост, поскольку название соответствовало проблеме, которую я имел. Я был после эффекта, благодаря которому у меня было бы большее количество элементов в строке на больших экранах - и меньше элементов в строке на меньших экранах. В обоих случаях эти элементы также необходимы для масштабирования, чтобы соответствовать... через устройства.

Однако эти блуждающие элементы в последней строке всегда будут расширяться, чтобы заполнить оставшееся пространство.

JQuery получает ширину первого элемента - и применяет его как максимальную ширину для каждого элемента. OP хотел, чтобы блоки упали в ярость min-width/max-width. Установка max-width в CSS, похоже, работает. Мы очищаем максимальную ширину от элемента, поэтому по умолчанию используется максимальная ширина в CSS... затем получает фактическую ширину.

Ответ 5

Это не идеально, но стоит попробовать. http://codepen.io/anon/pen/MKmXpV

Изменения

li
  width: 7.1428%
  flex: 0 0 auto

figure
  margin: 0 auto
  background-color: darkgreen
  min-width: 40px
  max-width: 100px
  • изменил li flex на "0 0 auto", а ширина li в процентах на основе число lis.
  • переместил минимальную и максимальную ширину от li до фигуры
  • переместил зеленый фон на фигуру и центрировал фигуры в lis

Ответ 6

Установка min-width и max-width в процентах позволила всем изображениям оставаться одинаковой шириной, когда они переходят на следующую строку. Это не идеально, но ближе к тому, что вы после?

li {
  min-width: 15%;
  max-width: 15%;  
}

Ответ 7

Я думаю, что у меня это получилось... но это взломанно. В результате получается 14 изображений, каждое из которых масштабируется от 100 пикселей до 40 пикселей, даже в нескольких рядах.

От 107px до 40px Width

  • Добавлен дублированный набор из 14 оригинальных <li> и добавлен в flex <ul>.
  • Затем второй набор был невидимым:

    li:nth-of-type(n + 15) {
      visibility: hidden;
    }
    
  • Чтобы поддерживать единообразную гибкость, следующие изменения для каждого <li>:

    li {
      min-width: 40px;
      max-width: 10%;
      flex: 1 0 100px;
    }
    

Просмотрите CodePen

и/или Snippet в режиме полной страницы.

ul {
  display: flex;
  flex-wrap: wrap;
  max-height: 258px;
}
li {
  min-width: 40px;
  max-width: 10%;
  flex: 1 0 100px;
}
ul,
li {
  margin: 0;
  padding: 0;
  list-style: none;
}
ul {
  background-color: tomato;
}
li {
  margin: 0.5em;
  background-color: darkgreen;
}
li img {
  width: 100%;
  opacity: 0.5;
}
li figure,
li img {
  margin: 0;
  padding: 0;
}
li:nth-of-type(n + 15) {
  visibility: hidden;
}
<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>



  <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>

Ответ 8

У меня была такая же проблема, поэтому я использовал очень маленький бит JQuery, чтобы контролировать ширину ящиков и сделать их одинаковой шириной даже после их переноса.

Моя демонстрация находится на CodePen Обертка Flex с равной шириной в новой строке

function resize(){
  var colWidth;
  var screen = $(window).width(); 
  
  if(screen < 576){
    colWidth = Math.round(screen / 2) - 31;
    $(".item").width(colWidth);
  } 
  if(screen > 575 && screen < 768){
    colWidth = Math.round(screen / 3) - 31;
    $(".item").width(colWidth);
  } 
  else if (screen > 767 && screen < 992){
      colWidth = Math.round(screen / 4) -31;
      $(".item").width(colWidth);
  }
  else if (screen > 991 ){
      colWidth = Math.round(screen / 6) -31;
      $(".item").width(colWidth);
  }
}
  
window.onresize = function() {
  resize();
}

resize();
html,
body{
  padding:0;
  margin:0;
}
.flex-container {
  padding: 0;
  margin: 0;
  list-style: none;
  -ms-box-orient: horizontal;
  display: -webkit-box;
  display: -moz-box;
  display: -ms-flexbox;
  display: -moz-flex;
  display: -webkit-flex;
  display: flex;
  justify-content: left;
  background-color:#ddd;
}

.wrap    { 
  -webkit-flex-wrap: wrap;
  flex-wrap: wrap;
}  

.item {
  background: tomato;
  height: 100px;
  margin:0 15px;
  line-height: 100px;
  color: white;
  font-weight: bold;
  font-size: 2em;
  text-align: center;
  margin-top:10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="flex-container wrap">
  <li class="item">1</li>
  <li class="item">2</li>
  <li class="item">3</li>
  <li class="item">4</li>
  <li class="item">5</li>
  <li class="item">6</li>
  <li class="item">7</li>
  <li class="item">8</li>
  <li class="item">9</li>
</ul>

Ответ 9

использовать max-width: 40px не max-width: 100px