Как сохранить обернутые гибкие элементы той же ширины, что и элементы предыдущей строки?
У меня есть <ul>
, который является гибкой коробкой и связкой <li>
в ней, которые являются элементами flex.
Я пытаюсь получить <li>
гибкую ширину, которая остается между двумя размерами, используя min-width и max-width. Он отлично работает, пока они находятся на одной линии. Однако, когда они обертываются, <li>
на новой строке использует как можно больше места. Это означает, что они маленькие на первой строке и большие на второй строке, когда их всего лишь несколько.
Есть ли способ сообщить flexbox, чтобы элементы сохранялись после упаковки, сохраняя гибкую ширину?
демонстрационная версия:
Мой код выглядит следующим образом:
<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 пикселей, даже в нескольких рядах.
- Добавлен дублированный набор из 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