Подтвердить что ты не робот

Чистое решение CSS для разделения элементов на динамическое количество столбцов

Есть ли способ выравнивания элементов в нескольких столбцах, где количество столбцов зависит от самого широкого элемента? Высота элемента и ширина контейнера фиксированы, но ширина элемента динамическая.

Я ищу способ только для CSS, чтобы добиться следующего поведения:

(Предположим, что родительский контейнер имеет ширину 300 пикселей.)

  • Если самый широкий элемент имеет ширину более 150 пикселей, используйте один столбец
  • Если самый широкий элемент находится между 100px и 150px, используйте два столбца
  • Если самый широкий элемент меньше 100px, используйте три столбца
  • ...
  • Если самый широкий элемент меньше ширины контейнера /N, используйте N столбцов

Одним из возможных способов получения этого поведения может быть использование display:inline-block и установка свойства width в ширину самого широкого элемента в контейнере с использованием JavaScript.

См. этот JSFiddle для примера:

Пример

Однако я думаю, что также должен быть способ только для CSS. Возможно ли это?

Если нет, возможно, существует элегантный способ только для CSS-распределения/привязки элементов динамического размера к столбцам в контейнере с фиксированной шириной?

4b9b3361

Ответ 1

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

... Я думаю, что также должен быть CSS-единственный способ от этого...

Как указано в статье @Paulie-D, CSS не может обнаружить различную ширину в вашем дочернем div, и поэтому чистое решение только для CSS не существует.

Это связано с тем, что вы хотите получить ширину всех элементов, затем получите максимальный размер, а затем используйте эту ширину для распределения элементов в столбцы. Это вычисление выходит за рамки CSS. Для этого вам понадобится Javascript.

Если нет, возможно, есть элегантный CSS-единственный способ распространения/ привязка элементов динамического размера к столбцам в контейнере с фиксированной шириной?

Я объясню это в двух частях:


Часть 1, CSS:

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

MNyf9.png

Фокус в том, чтобы указать auto для column-count / column-width. Это автоматически распределит содержимое в количестве столбцов, необходимых в пределах родительской ширины.

Я сделал фундаментальную ошибку в вышеупомянутом утверждении (отсюда и другое редактирование). В соответствии с описанием здесь алгоритм говорит:

(01) if ((column-width = auto) and (column-count = auto)) then
(02)      exit; /* not a multicol element */ 

Вот где я ошибся раньше. Когда оба параметра column-count и column-width установлены на auto, тогда он рассматривается как не многоцветный элемент. Если для одного из этих свойств задано неавтоматическое значение, то другое свойство определяется этим.

Из выше ref:

если column-count установлено в auto, тогда количество столбцов будет определено другими свойствами (например, column-width, если оно имеет неавтоматическое значение) а также если для параметра column-width установлено значение auto, тогда ширина столбца будет определяться другими свойствами (например, column-count, если оно имеет неавтоматическое значение)

Примером может быть установка column-width фиксированной ширины, скажем 120px (мы рассмотрим это в части 2 чуть позже):

.container { -webkit-columns: auto 120px; columns: auto 120px; }

Это приведет к тому, что контейнер будет соответствовать содержимому в столько столбцов, сколько возможно для ширины столбца 120px в пределах его собственной ширины. Если вы увеличите ширину контейнера, он получит больше столбцов. Если вы уменьшите ширину контейнера, он получит меньше столбцов, которые в конечном итоге рухнут в один столбец, когда свободного места не будет.

Ниже приведен полный фрагмент фрагмента ниже:

Пример 1:

* { box-sizing: border-box; padding: 0; margin: 0; }
p { margin-left: 16px; }
.container { width: 400px; border: 1px solid #f00; margin: 16px; }
.container.col { -webkit-columns: auto 120px; columns: auto 120px; }
.container > div { 
	-webkit-column-break-inside: avoid; column-break-inside: avoid; 
	display: block; padding: 8px; border: 1px solid #ccc;
}
#one { width: 200px; }
#two { width: 300px; }
<p>Small Container (1-column):</p>
<div id="one" class="container col">
	<div class="item-min">Maudie Mcmanus</div>
	<div class="item-min">Remedios</div>
	<div class="item-min">Chaya B</div>
	<div class="item-min">Duncan</div>
	<div class="item-min">Lashonda</div>
</div>
<p>Medium Container (2-column):</p>
<div id="two" class="container col">
	<div class="item-min">Maudie Mcmanus</div>
	<div class="item-min">Remedios</div>
	<div class="item-min">Chaya B</div>
	<div class="item-min">Duncan</div>
	<div class="item-min">Lashonda</div>
</div>
<p>Large Container (3-column):</p>
<div id="three" class="container col">
	<div class="item-min">Maudie Mcmanus</div>
	<div class="item-min">Remedios</div>
	<div class="item-min">Chaya B</div>
	<div class="item-min">Duncan</div>
	<div class="item-min">Lashonda</div>
</div>

Ответ 2

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

Вы можете изменить содержимое элементов, и вы увидите, как скорректировать количество столбцов, если самый широкий элемент меньше ширины контейнера /N, он будет автоматически использовать N столбцов.

Посмотрите этот JSFiddle для демонстрации

Идея очень проста: вы set width: 'auto', display: 'inline-block' до container, чтобы она соответствовала ее содержимому, которое определяется шириной самого широкого элемента, см. в следующем img:

введите описание изображения здесь

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

var div = Math.floor(initialWidth / widestItemWidth);     /*this is to get as many items fit with the width of the widest element*/
var itemWidth = initialWidth / div;      /*for the width of the item occupy the entire container*/

Итак, если самый широкий элемент меньше ширины контейнера /N, он будет использовать N столбцов автоматически, и они будут соответствовать ширине container, это все, что вам нужно сделать, просто установите свойство css, сделайте немного calc, и там у вас есть то, что вы хотели достичь.

$(document).ready(function() {
    var $container = $('.container');
    var $item = $('.item');

    var initialWidth = $container.outerWidth();

   $container.css({     /*to allow it to fit its contents which is defined by the width of the widest element*/
        width: 'auto',
        display: 'inline-block'
    });   

    var widestItemWidth = $container.outerWidth();     /*Now this is the width of the widest item*/

    var div = Math.floor(initialWidth / widestItemWidth);     /*this is to get as many items fit with the width of the widest element*/
    var itemWidth = initialWidth / div;      /*for the width of the item occupy the entire container*/
  
  /*if you don't want the items occupy the entire width of the container just use 'widestItemWidth' as width of $item*/

    $item.css({
        width: itemWidth,
        float: 'left'
    });
    $container.css({     /*restoring the initial styles*/
        width: initialWidth,
        display: 'block'
    });
})
.container {
  width: 400px;
  overflow: hidden;
}
.container .item {
  padding: 8px;
  border: 1px solid rgb(216, 213, 213);
}
*{
  box-sizing: border-box;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
    <div class="item">Maudie Mcmanus</div>
    <div class="item">Remedios Arrington</div>
    <div class="item">Chaya B</div>
    <div class="item">Duncan</div>
    <div class="item">Lashonda Tatum Walls</div>
</div>

Ответ 3

Ближе всего вы можете получить чистое решение CSS - использовать столбцы CSS, как это было предложено другими (или подход CSS Grid - см. раздел "Редактирование" ). Но ключ состоит в том, чтобы использовать относительные единицы и быть в курсе местоположения и контейнера столбца в вашем макете и использовать медиа-запросы для управления количеством столбцов. Это, безусловно, НЕ пуленепробиваемое решение. Однако, если вы создаете макет и контролируете размещение и область действия элемента контейнера столбца, вы можете достаточно надежно контролировать количество столбцов. Если это для виджета, который вышел из-под контроля, вам действительно нужно реализовать решение на основе Javascript.

Ссылки: Отзывчивые столбцы CSS, CSS Grid Layout

РЕДАКТИРОВАТЬ:. После повторного просмотра вашего вопроса и просмотра вашего примера скриншота, похоже, вы действительно ищете общее решение сетки сетки, где элементы текут по горизонтали, а не по вертикали. Я обновил свой ответ, включив в него демонстрационный снимок, где блоки перетекают по горизонтали.

Демонстрация сниппета с использованием медиа-запросов на основе столбцов и ширины контейнера (приблизительная минимальная ширина столбца 10 м):

#main, #sideBar {
    box-sizing:border-box;
    display:block;
    padding:0;
    margin:0;
    width:100%;
}

.container {
    width: 100%;
    min-width:10em;
    -webkit-columns: 1;
    -moz-columns: 1;
      columns: 1;
}
.container .item {
    display: block;
    padding: 8px;
    border: 1px solid rgb(216, 213, 213);
    box-sizing:border-box;
    -webkit-column-break-inside: avoid; /* Chrome, Safari, Opera */
          page-break-inside: avoid; /* Firefox */
               break-inside: avoid; /* IE 10+ */
}
@media only screen and (min-width:20em) {
    .container {
    -webkit-columns: 2;
    -moz-columns: 2;
      columns: 2;
    }
}

@media only screen and (min-width:32em) {
    #main {
        float:left;
        width:65%;
    }

    #sideBar {
        float:left;
        width:30%;
        margin-left:5%;
    }
    #sideBar .container {
    -webkit-columns: 1;
    -moz-columns: 1;
      columns: 1;
    }

}

@media only screen and (min-width:48em) {
    
    #main .container {
    -webkit-columns: 3;
    -moz-columns: 3;
      columns: 3;
    }

    #sideBar .container {
    -webkit-columns: 1;
    -moz-columns: 1;
      columns: 1;
    }

}

@media only screen and (min-width:52em) {
    
    #sideBar .container {
    -webkit-columns: 2;
    -moz-columns: 2;
      columns: 2;
    }

}

@media only screen and (min-width:100em) {
    
    #main .container {
    -webkit-columns: 5;
    -moz-columns: 5;
      columns: 5;
    }

    #sideBar .container {
    -webkit-columns: 3;
    -moz-columns: 3;
      columns: 3;
    }

}
<div id="main"><h1>#main</h1>
    <div class="container">
        <div class="item">Maudie Mcmanus</div>
        <div class="item">Remedios Arrington</div>
        <div class="item">Chaya B</div>
        <div class="item">Duncan</div>
        <div class="item">Lashonda Tatum Walls</div>
    </div>
</div>
<div id="sideBar"><h1>#sideBar</h1>
    <div class="container">
        <div class="item">Maudie Mcmanus</div>
        <div class="item">Remedios Arrington</div>
        <div class="item">Chaya B</div>
        <div class="item">Duncan</div>
        <div class="item">Lashonda Tatum Walls</div>
    </div>
</div>

Ответ 4

Ну, как многие другие отметили это, здесь нет решения только для CSS. В основном потому, что CSS был спроектирован для загрузки до содержимого dom, чтобы контент отображался красиво. Наша главная проблема здесь в том, что мы НЕ знаем ширину элемента заранее, мы будем знать это только при загрузке страницы. Почти все решения на странице имеют одинаковую идею, используйте Javascript для прокрутки элементов, найдите самый широкий и установите все остальные элементы (с тем же классом) в заданную ширину. Чтобы улучшить процесс и сделать его одним линейным решением (с jquery, может быть сделано и с Javascript, но для простоты я использовал jQuery), я предлагаю следующий "хак/трюк":

1) Не определяйте ширину вашего контейнера и не устанавливайте отображение в таблицу, а не блок;

2) Не устанавливайте ширину для элементов внутри div

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

Теперь используйте jQuery для добавления дополнительных правил CSS в заголовок документа для контейнера и для элементов. Нам нужно изменить тип отображения контейнера обратно на блок вместо таблицы, установить его ширину в 400 пикселей (или все, что нам нужно), и нам нужно сделать элементы встроенных блоков с заданной шириной.

Так как CSS всегда применяет последнее свойство, это будет довольно просто:

$("<style> .container {display: block; width:400px;} .item-min {width:"+$(".item-min").width()+"px;display:inline-block;}</style>").appendTo("head");

Я обновил ваш пример Fiddler ЗДЕСЬ

Я тестировал его в IE 12, Edge, Chorme и Firefox, и он работает во всех браузерах.

РЕДАКТИРОВАТЬ 1

Если вы не хотите использовать jQuery, чтобы страница была как можно более легкой, вы можете использовать следующий один Jaycript-лайнер:

document.head.innerHTML += "<style> .container {display: block; width:400px;} .item-min {width:"+(document.getElementsByClassName("container")[0].clientWidth-16-2)+"px;display:inline-block;}</style>";

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

См. обновленный Fiddle

РЕДАКТИРОВАТЬ 2

Полный HTML-документ:

<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  <style type='text/css'>
    .container {

    display:table;
    table-layout:fixed;
}

.container .item-min {
    padding: 8px;
    border: 1px solid rgb(216, 213, 213);

}
  </style>


<script type='text/javascript'>
window.onload=function(){
document.head.innerHTML += "<style> .container {display: block; width:400px;} .item-min {width:"+(document.getElementsByClassName("container")[0].clientWidth-16-2)+"px;display:inline-block;}</style>";
}
</script>

</head>
<body>
      <div class="container">
        <div class="item-min">Maudie Mcmanus</div>
        <div class="item-min">Remedios Arrington</div>
        <div class="item-min">Chaya B</div>
        <div class="item-min">Duncan</div>
        <div class="item-min">Lashonda Tatum Walls</div>
    </div>


</body>

</html>

Ответ 5

Прежде всего - ознакомьтесь с Скриншот (играйте с шириной .container...)

Это невозможно с использованием только CSS, но вот элегантное решение с использованием jquery, которое определяет ширину контейнера, самую широкую ширину элемента и распространяет элементы в соответствующее количество столбцов (динамически созданных).

HTML

<p>Without width:
    <div class="container">
        <div class="item">Maudie Mcmanus</div>
        <div class="item">Remedios Arrington</div>
        <div class="item">Chaya B</div>
        <div class="item">Duncan</div>
        <div class="item">Lashonda Tatum Walls</div>
    </div>
</p>

Javascript

$(function(){
    var $items = $('.item');

    // detect the widest column width
    var widestItemWidth = 0;
    $items.each(function(){
        widestItemWidth = Math.max(widestItemWidth, $(this).width());
    });

    // calculate the number of columns
    var $container = $('.container');
    var containerWidth = $container.width();
    var numOfColumns = parseInt(containerWidth / widestItemWidth);

    // create the columns
    for(var i = 0; i < numOfColumns; i++){
        $container.prepend('<div class="column"></div>');
    }
    var $columns = $('.column');
    $columns.css('width', (100/numOfColumns)+'%');

    // spread the items between the columns
    $items.each(function(i){
        var columnIndex = i % numOfColumns;
        $(this).appendTo($columns.eq(columnIndex));
    });
});

CSS

.container {
    width: 400px;
}
.container .column {
    display: inline-block;
    box-sizing: border-box;
    vertical-align: text-top;
}
.container .item {
    display: inline-block;
    padding: 8px;
    border: 1px solid rgb(216, 213, 213);
}

Ответ 6

Самый легкий, по-видимому, устанавливает ширину до 32% плюс clear: none для всех столбцов и отдельный отчет: оба класса для каждого третьего (последнего) столбца. Добавьте медиа-запросы для разрешения различных размеров экрана и соответственно установите ширину экрана, например. 24%, 48% и т.д.

Ответ 7

Попробуйте этот пример

@media only screen and (device-width : 300px) {#container {width:300px; display:block;}}
@media only screen and (device-width : 150px) {#container {width:150px; display:block; float:left}}
@media only screen and (device-width : 100px) {#container {width:150px; display:block; float:left}}