Есть ли способ определить поток контента в CSS с помощью гибкости или других методов, таких как «зигзагообразные» или «зигзагообразные» движения контента:
-----------------
|A > B > C > D > E|
|J < I < H < G < F|
-----------------
---
|A H|
|B G|
|C F|
|D E|
---
Предположим, что всегда есть 2 столбца или строки. Я мог бы разделить элементы на 2 и создать 2 обертывающих элемента вокруг них, но я бы хотел, чтобы это было более динамичным.
В принципе, как сделать так, чтобы первая строка располагалась вправо, а вторая - слева?
@Armel Вот и ответ. Напишите это как ответ и приведите пример :)
Либо используйте CSS Grid, либо используйте Flex с flex-wrap. Имейте в виду, что css grid еще не полностью поддерживается всеми браузерами.
Может быть, я что-то упускаю, но сетка не переключается автоматически на макет типа «вперед-назад».
Я думаю, вы не заметили, что я хочу, чтобы первая строка проходила слева направо, а вторая - справа налево ...
Нет, с простым свойством ничего подобного не происходит. Нужно использовать, например, order или аналогичный, и если контент динамический, необходим скрипт. Что ж, у Flexbox есть свойство *-reverse, но то, как его можно использовать, зависит от того, как выглядит разметка.
@LGSON, это действительно хороший совет. Элементы уже создаются сценарием, поэтому установить свойство order на лету очень просто.
@ecc Обратите внимание, что я немного обновил предыдущий комментарий.
Да, свойство order было бы подходящим вариантом, или создание другого row или column и установка flex-direction: row-reverse или column-reverse, хотя это может быть больше работы, чем на самом деле нужно ... посмотрите это, может быть, это может помочь codepen.io/IvanS95/pen/aQjBdz
Есть ли фиксированное количество дочерних элементов?
Неважно, вы сказали, что хотите, чтобы это было динамично.
Как было сказано, это не возможный, если не известно количество дочерних элементов. Следовательно, существующие решения - не масштабируемый.
Как вы планируете равномерно распределить предметы по двум строкам / столбцам?
Я опубликовал решение для любого количества предметов, пока их число четное. Пожалуйста, проверьте его и скажите, подходит ли он вашим потребностям. Спасибо!






Вот трюк, который поможет вам выбрать половину предметов. Используйте float:left по умолчанию и установите float: right на элементы, которые были выбраны в качестве второй половины.
Обратной стороной является то, что вам нужно будет определить множество правил, если вам нужно поддерживать много элементов.
.box{
width: 160px;
}
.item{
width: 40px;
float: left;
}
/* selecting half or more items. Up to 6 */
.item:first-child:last-child,
.item:nth-child(n+2):nth-last-child(-n+2),
.item:nth-child(n+3):nth-last-child(-n+3),
.item:nth-child(n+4):nth-last-child(-n+4),
.item:nth-child(n+5):nth-last-child(-n+5),
.item:nth-child(n+6):nth-last-child(-n+6) {
float: right;
}<div class = "box">
<div class = "item">A</div>
<div class = "item">B</div>
<div class = "item">C</div>
<div class = "item">D</div>
<div class = "item">E</div>
<div class = "item">F</div>
<div class = "item">G</div>
<div class = "item">H</div>
</div>А вертикальный сценарий может быть таким:
.box {
margin-top: 100px;
width: 160px;
transform: rotate(90deg);
}
.item {
width: 40px;
float: left;
transform: rotate(-90deg);
}
/* selecting half or more items. Up to 6 */
.item:first-child:last-child,
.item:nth-child(n+2):nth-last-child(-n+2),
.item:nth-child(n+3):nth-last-child(-n+3),
.item:nth-child(n+4):nth-last-child(-n+4),
.item:nth-child(n+5):nth-last-child(-n+5),
.item:nth-child(n+6):nth-last-child(-n+6) {
float: right;
}<div class = "box">
<div class = "item">A</div>
<div class = "item">B</div>
<div class = "item">C</div>
<div class = "item">D</div>
<div class = "item">E</div>
<div class = "item">F</div>
<div class = "item">G</div>
<div class = "item">H</div>
</div>@AdityaGupta: да, он не поддерживает бесконечное количество элементов, но ему может понадобиться максимум 20, и это можно покрыть ...
Да ладно, просто прочтите комментарии. Он генерирует строки с помощью кода. В своем случае он может использовать «гибкий бокс».
Я смог сделать это с помощью Flexbox и немного JavaScript (я не смог сделать это с Только CSS):
var reverseBoxes = function () {
var flexItems = document.querySelectorAll(".child"),
flexItemsCount = flexItems.length,
reverseAt = flexItems.length / 2,
breakPoint = 480;
for (var i = reverseAt; i < flexItemsCount; i++) {
flexItems[i].style.order = flexItemsCount - i;
}
for (var j = 0; j < flexItemsCount; j++) {
if (window.innerWidth > breakPoint) {
flexItems[j].style.width = (100 / flexItemsCount) * 2 - 2 + "%";
flexItems[j].style.height = "auto";
} else {
flexItems[j].style.height = (100 / flexItemsCount) * 2 - 2 + "%";
flexItems[j].style.width = "auto";
}
}
}
reverseBoxes();
window.addEventListener("resize", reverseBoxes);body {
font-family: Arial, sans-serif;
font-size: 18px;
margin: 0;
padding: 0;
}
.parent {
display: flex;
flex-wrap: wrap;
list-style-type: none;
padding: 0;
height: 100vh;
}
.child {
margin: 1%;
text-align: center;
background: #069;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
}
@media only screen and (max-width: 480px) {
.parent {
flex-direction: column;
}
.child {
width: 48%;
}
}<div class = "parent">
<div class = "child">A</div>
<div class = "child">B</div>
<div class = "child">C</div>
<div class = "child">D</div>
<div class = "child">E</div>
<div class = "child">F</div>
<div class = "child">G</div>
<div class = "child">H</div>
<div class = "child">I</div>
<div class = "child">J</div>
</div>Это то, что вы ищете?
Понятно, что чистого масштабируемого решения CSS на самом деле не существует для достижения такой цели, поэтому вам понадобится сценарий для динамической настройки некоторых свойств, чтобы получить необходимый макет.
Если мы предположим, что все элементы имеют такая же ширина, мы можем определить количество элементов в строке и применить стили к элементам в зависимости от строки.
Вот базовый пример, основанный на коде из предыдущего ответа: https://stackoverflow.com/a/49046973/8620333
//total number of element
var n_t = $('.item').length;
//full width of element with margin
var w = $('.item').outerWidth(true);
//width of container without padding
var w_c = $('.grid').width();
//nb element per row
var nb = Math.min(parseInt(w_c / w),n_t);
console.info(nb);
$('.item:nth-child(1n+'+(nb+1)+')').addClass('right');
$('.item:nth-child(1n+'+(2*nb+1)+')').removeClass('right');
$('.item:nth-child(1n+'+(3*nb+1)+')').addClass('right');
$('.item:nth-child(1n+'+(4*nb+1)+')').removeClass('right');
window.addEventListener('resize', function(event){
//only the width of container will change
w_c = $('.grid').width();
nb = Math.min(parseInt(w_c / w),n_t);
$('.item').removeClass('right');
$('.item:nth-child(1n+'+(nb+1)+')').addClass('right');
$('.item:nth-child(1n+'+(2*nb+1)+')').removeClass('right');
$('.item:nth-child(1n+'+(3*nb+1)+')').addClass('right');
$('.item:nth-child(1n+'+(4*nb+1)+')').removeClass('right');
});.grid {
background-color: #ddd;
padding: 10px 0 0 10px;
overflow:hidden;
}
.item {
width: 80px;
height: 80px;
float:left;
clear:right;
background-color: red;
margin: 0 10px 10px 0;
}
.item.right {
float:right;
clear:left;
background:blue;
}
body {
margin:0;
}<script src = "https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class = "grid">
<div class = "item">A</div>
<div class = "item">B</div>
<div class = "item">C</div>
<div class = "item">D</div>
<div class = "item">E</div>
<div class = "item">F</div>
<div class = "item">G</div>
<div class = "item">H</div>
<div class = "item">I</div>
<div class = "item">J</div>
<div class = "item">K</div>
<div class = "item">L</div>
<div class = "item">M</div>
<div class = "item">N</div>
<div class = "item">O</div>
<div class = "item">P</div>
</div>Этот пример не идеален, поскольку у нас есть проблема с выравниванием, но идея состоит в том, чтобы применить плавающее свойство к строкам путем чередования строк. Я рассматривал только 4 строки, но мы можем легко сделать их динамическими, используя цикл, как показано ниже:
//total number of element
var n_t = $('.item').length;
//full width of element with margin
var w = $('.item').outerWidth(true);
//width of container without padding
var w_c = $('.grid').width();
//nb element per row
var nb = Math.min(parseInt(w_c / w),n_t);
for(var i=1;i<n_t;i++) {
if (i%2==1)
$('.item:nth-child(1n+'+(i*nb+1)+')').addClass('right');
else
$('.item:nth-child(1n+'+(i*nb+1)+')').removeClass('right');
}
window.addEventListener('resize', function(event){
//only the width of container will change
w_c = $('.grid').width();
nb = Math.min(parseInt(w_c / w),n_t);
$('.item').removeClass('right');
for(var i=1;i<n_t;i++) {
if (i%2==1)
$('.item:nth-child(1n+'+(i*nb+1)+')').addClass('right');
else
$('.item:nth-child(1n+'+(i*nb+1)+')').removeClass('right');
}
});.grid {
background-color: #ddd;
padding: 10px 0 0 10px;
overflow:hidden;
}
.item {
width: 80px;
height: 80px;
float:left;
clear:right;
background-color: red;
margin: 0 10px 10px 0;
}
.item.right {
float:right;
clear:left;
background:blue;
}
body {
margin:0;
}<script src = "https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class = "grid">
<div class = "item">A</div>
<div class = "item">B</div>
<div class = "item">C</div>
<div class = "item">D</div>
<div class = "item">E</div>
<div class = "item">F</div>
<div class = "item">G</div>
<div class = "item">H</div>
<div class = "item">I</div>
<div class = "item">J</div>
<div class = "item">K</div>
<div class = "item">L</div>
<div class = "item">M</div>
<div class = "item">N</div>
<div class = "item">O</div>
<div class = "item">P</div>
</div>Для лучшего выравнивания мы можем рассмотреть возможность использования CSS-сетки или гибкого бокса, но в этом случае нам нужно будет настроить свойство порядка элементов.
С сеткой CSS:
//total number of element
var n_t = $('.item').length;
//full width of element with margin
var w = $('.item').outerWidth(true);
//width of container without padding
var w_c = $('.grid').width();
//nb element per row
var nb = Math.min(parseInt(w_c / w), n_t);
//nb rows
var nr = n_t / nb;
//order of element
var or = 0;
for (var i = 0; i < nr; i++) {
if (i % 2 == 0)
for (var j = 0; j < nb; j++) {
$('.item').eq(nb * i + j).css('order', or++);
}
else
for (var j = 0; j < nb; j++) {
$('.item').eq(nb * i + (nb - j - 1)).css('order', or++);
}
}
window.addEventListener('resize', function(event) {
//only the width of container will change
w_c = $('.grid').width();
nb = Math.min(parseInt(w_c / w), n_t);
nr = n_t / nb;
or = 0;
for (var i = 0; i < nr; i++) {
if (i % 2 == 0)
for (var j = 0; j < nb; j++) {
$('.item').eq(nb * i + j).css('order', or++);
}
else
for (var j = 0; j < nb; j++) {
$('.item').eq(nb * i + (nb - j - 1)).css('order', or++);
}
}
});.grid {
background-color: #ddd;
display: grid;
grid-template-columns: repeat( auto-fit, 80px);
padding: 10px 0 0 10px;
}
.item {
height: 80px;
background-color: red;
font-size: 30px;
color: #fff;
font-weight: bold;
margin: 0 10px 10px 0;
}
body {
margin: 0;
}<script src = "https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class = "grid">
<div class = "item">A</div>
<div class = "item">B</div>
<div class = "item">C</div>
<div class = "item">D</div>
<div class = "item">E</div>
<div class = "item">F</div>
<div class = "item">G</div>
<div class = "item">H</div>
<div class = "item">I</div>
<div class = "item">J</div>
<div class = "item">K</div>
<div class = "item">L</div>
<div class = "item">M</div>
<div class = "item">N</div>
<div class = "item">O</div>
<div class = "item">P</div>
</div>Этот метод позволяет лучше выравнивать, но последняя строка не всегда хороша.
Мы можем исправить последнюю строку, настроив последние элементы usgin grid-column, как показано ниже:
//total number of element
var n_t = $('.item').length;
//full width of element with margin
var w = $('.item').outerWidth(true);
//width of container without padding
var w_c = $('.grid').width();
//nb element per row
var nb = Math.min(parseInt(w_c / w), n_t);
//nb rows
var nr = Math.ceil(n_t / nb);
//order of element
var or = 0;
for (var i = 0; i < nr; i++) {
if (i % 2 == 0)
for (var j = 0; j < nb; j++) {
$('.item').eq(nb * i + j).css('order', or++);
}
else
for (var j = 0; j < nb; j++) {
$('.item').eq(nb * i + (nb - j - 1)).css('order', or++);
/*fix the last row*/
if (i == (nr - 1)) {
$('.item').eq(nb * i + j).css('grid-column', " " + (nb - j));
}
}
}
window.addEventListener('resize', function(event) {
//only the width of container will change
w_c = $('.grid').width();
nb = Math.min(parseInt(w_c / w), n_t);
nr = Math.ceil(n_t / nb);
$('.item').css('grid-column', 'auto');
or = 0;
for (var i = 0; i < nr; i++) {
if (i % 2 == 0)
for (var j = 0; j < nb; j++) {
$('.item').eq(nb * i + j).css('order', or++);
}
else
for (var j = 0; j < nb; j++) {
$('.item').eq(nb * i + (nb - j - 1)).css('order', or++);
/*fix the last row*/
if (i == nr - 1) {
$('.item').eq(nb * i + j).css('grid-column', " " + (nb - j));
}
}
}
});.grid {
background-color: #ddd;
display: grid;
grid-template-columns: repeat( auto-fit, 80px);
grid-auto-flow: dense;
padding: 10px 0 0 10px;
}
.item {
height: 80px;
background-color: red;
font-size: 30px;
color: #fff;
font-weight: bold;
margin: 0 10px 10px 0;
}
body {
margin: 0;
}<script src = "https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class = "grid">
<div class = "item">A</div>
<div class = "item">B</div>
<div class = "item">C</div>
<div class = "item">D</div>
<div class = "item">E</div>
<div class = "item">F</div>
<div class = "item">G</div>
<div class = "item">H</div>
<div class = "item">I</div>
<div class = "item">J</div>
<div class = "item">K</div>
<div class = "item">L</div>
<div class = "item">M</div>
<div class = "item">N</div>
<div class = "item">O</div>
<div class = "item">P</div>
</div>Flexbox может быть более подходящим для второго случая (направление столбца). Мы просто делаем то же самое, что и раньше, рассматривая столбцы вместо строк:
//total number of element
var n_t = $('.item').length;
//full height of element with margin
var w = $('.item').outerHeight(true);
//height of container without padding
var w_c = $('.grid').height();
//nb element per row
var nb = Math.min(parseInt(w_c / w), n_t);
//nb rows
var nr = n_t / nb;
//order of element
var or = 0;
for (var i = 0; i < nr; i++) {
if (i % 2 == 0)
for (var j = 0; j < nb; j++) {
$('.item').eq(nb * i + j).css('order', or++);
}
else
for (var j = 0; j < nb; j++) {
$('.item').eq(nb * i + (nb - j - 1)).css('order', or++);
}
}
window.addEventListener('resize', function(event) {
//only the width of container will change
w_c = $('.grid').height();
nb = Math.min(parseInt(w_c / w), n_t);
nr = n_t / nb;
or = 0;
for (var i = 0; i < nr; i++) {
if (i % 2 == 0)
for (var j = 0; j < nb; j++) {
$('.item').eq(nb * i + j).css('order', or++);
}
else
for (var j = 0; j < nb; j++) {
$('.item').eq(nb * i + (nb - j - 1)).css('order', or++);
}
}
});.grid {
display: flex;
height:100vh;
flex-direction:column;
flex-wrap:wrap;
align-items:flex-start;
align-content:flex-start;
padding-top: 10px;
padding-left:10px;
box-sizing:border-box;
}
.item {
height: 80px;
width:80px;
background-color: red;
font-size: 30px;
color: #fff;
font-weight: bold;
margin: 0 10px 10px 0;
}
body {
margin: 0;
}<script src = "https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class = "grid">
<div class = "item">A</div>
<div class = "item">B</div>
<div class = "item">C</div>
<div class = "item">D</div>
<div class = "item">E</div>
<div class = "item">F</div>
<div class = "item">G</div>
<div class = "item">H</div>
<div class = "item">I</div>
<div class = "item">J</div>
<div class = "item">K</div>
<div class = "item">L</div>
<div class = "item">M</div>
<div class = "item">N</div>
<div class = "item">O</div>
<div class = "item">P</div>
</div>В некоторых случаях также возникает проблема с выравниванием последнего столбца, которую мы можем исправить, отрегулировав поля:
//total number of element
var n_t = $('.item').length;
//full height of element with margin
var w = $('.item').outerHeight(true);
//height of container without padding
var w_c = $('.grid').height();
//nb element per row
var nb = Math.min(parseInt(w_c / w), n_t);
//nb rows
var nr = Math.ceil(n_t / nb);
//order of element
var or = 0;
for (var i = 0; i < nr; i++) {
if (i % 2 == 0)
for (var j = 0; j < nb; j++) {
$('.item').eq(nb * i + j).css('order', or++);
}
else {
for (var j = 0; j < nb; j++) {
$('.item').eq(nb * i + (nb - j - 1)).css('order', or++);
}
if (i == (nr - 1)) {
/*we add margin+height of non-existing element*/
$('.item:last').css('margin-top', ((nb * nr - n_t) * (80 + 10)) + "px")
}
}
}
window.addEventListener('resize', function(event) {
//only the width of container will change
w_c = $('.grid').height();
nb = Math.min(parseInt(w_c / w), n_t);
nr = Math.ceil(n_t / nb);
or = 0;
$('.item').css('margin-top', 0); /*reset the margin*/
for (var i = 0; i < nr; i++) {
if (i % 2 == 0)
for (var j = 0; j < nb; j++) {
$('.item').eq(nb * i + j).css('order', or++);
}
else {
for (var j = 0; j < nb; j++) {
$('.item').eq(nb * i + (nb - j - 1)).css('order', or++);
}
if (i == (nr - 1)) {
/*we add margin+height of non-existing element*/
$('.item:last').css('margin-top', ((nb * nr - n_t) * (80 + 10)) + "px")
}
}
}
});.grid {
display: flex;
height: 100vh;
flex-direction: column;
flex-wrap: wrap;
align-items: flex-start;
align-content: flex-start;
padding-top: 10px;
padding-left: 10px;
box-sizing: border-box;
}
.item {
height: 80px;
width: 80px;
background-color: red;
font-size: 30px;
color: #fff;
font-weight: bold;
margin: 0 10px 10px 0;
}
body {
margin: 0;
}<script src = "https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class = "grid">
<div class = "item">A</div>
<div class = "item">B</div>
<div class = "item">C</div>
<div class = "item">D</div>
<div class = "item">E</div>
<div class = "item">F</div>
<div class = "item">G</div>
<div class = "item">H</div>
<div class = "item">I</div>
<div class = "item">J</div>
<div class = "item">K</div>
<div class = "item">L</div>
<div class = "item">M</div>
<div class = "item">N</div>
<div class = "item">O</div>
<div class = "item">P</div>
</div>Следующее решение не использует JavaScript и в некоторой степени масштабируемо. Я использую display: flex, чтобы использовать свойство order.
Основная идея состоит в том, чтобы назначить order: 1 последнему элементу, order: 2 - второму последнему элементу и так далее. Первая половина элементов имеет order: -1, а псевдоэлемент с order: 0 используется в качестве разделителя. Сложная часть - это то, где вы выясняете «первую половину» элементов:
.demo {
display: flex;
flex-direction: row;
flex-wrap: wrap;
background: #EEE;
}
.demo > * {
margin: .5em;
width: 4em;
height: 4em;
background: #0CF;
}
/*
* the example work for a list of 20 elements
* for additional elements extend the repeating selectors
*/
/* all items ordered backwards */
.demo > :nth-last-child(1) { order: 1; }
.demo > :nth-last-child(2) { order: 2; }
.demo > :nth-last-child(3) { order: 3; }
.demo > :nth-last-child(4) { order: 4; }
.demo > :nth-last-child(5) { order: 5; }
.demo > :nth-last-child(6) { order: 6; }
.demo > :nth-last-child(7) { order: 7; }
.demo > :nth-last-child(8) { order: 8; }
.demo > :nth-last-child(9) { order: 9; }
.demo > :nth-last-child(10) { order: 10; }
/* first half items are source ordered */
.demo> :nth-child(-n+0):nth-last-child(n+1),
.demo> :nth-child(-n+1):nth-last-child(n+2),
.demo> :nth-child(-n+2):nth-last-child(n+3),
.demo> :nth-child(-n+3):nth-last-child(n+4),
.demo> :nth-child(-n+4):nth-last-child(n+5),
.demo> :nth-child(-n+5):nth-last-child(n+6),
.demo> :nth-child(-n+6):nth-last-child(n+7),
.demo> :nth-child(-n+7):nth-last-child(n+8),
.demo> :nth-child(-n+8):nth-last-child(n+9),
.demo> :nth-child(-n+9):nth-last-child(n+10),
.demo> :nth-child(-n+10):nth-last-child(n+11) {
order: -1;
}
/* the separator uses flex-basis trick and ordered between the two halves */
.demo::after {
content: "";
flex-basis: 100%;
order: 0;
}<div class = "demo">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>
<div>10</div>
</div>Для макета с двумя столбцами укажите flex-direction: column; height: 25em для родительского элемента (высота должна быть фиксированной).
Это решение настолько безумное, и мне оно нравится
Да, с CSS Grid Layout, посмотрите здесь: gridbyexample.com/examples