有没有办法在多列中对齐项目,其中列数取决于最宽的项目?项目高度和容器宽度都是固定的,但项目宽度是动态的。
我正在寻找一种仅支持CSS的方法来实现以下行为:
(假设父容器的宽度为300px。)
- 如果最宽的项目大于150px,请使用单列
- 如果最宽的项目介于100px和150px之间,请使用两列
- 如果最宽的项目小于100px,请使用三列
- ...
- 如果最宽的项目小于容器宽度/ N,请使用N列
获得此行为的一种可能方法是使用display:inline-block
并使用JavaScript将width
属性设置为容器中最宽元素的宽度。
有关示例,请参阅this JSFiddle:
但是,我认为应该只有CSS这样做的方法。有可能吗?
如果没有,也许有一种优雅的CSS方式将动态大小的项目分发/捕捉到具有固定宽度的容器中的列?
答案 0 :(得分:25)
...我正在寻找一种只有CSS的方法来实现以下目标 行为......如果最宽的项目比......更宽......
......我认为应该只有CSS的方式 这样做......
As indicated by @Paulie-D,CSS无法检测到您的孩子div
中的宽度变化,因此不存在纯CSS唯一解决方案。
这是因为您希望获取所有元素的宽度,然后获取其中的最大值,然后使用该宽度将元素分配到列中。这个计算超出了CSS。你需要使用Javascript来做到这一点。
如果没有,或许有一种优雅的CSS分发方式/ 将动态大小的项捕捉到容器中的列 固定宽度?
我将分两部分解释:
当我们说我们希望内容在列中时,它意味着从上到下的流程而不是从左到右的包装流程。为此,我们需要CSS Columns。
诀窍是为 auto
指定column-count / column-width
。这将自动将内容分配到父宽度中所需的列数。
我在上面的陈述中犯了一个根本性的错误(因此另一个编辑)。根据{{3}}算法说:
(01) if ((column-width = auto) and (column-count = auto)) then (02) exit; /* not a multicol element */
这是我之前错的地方。当column-count
和column-width
都设置为auto
时,它将被视为而不是多元素。当其中一个属性设置为非自动值时,则另一个属性由此确定。
来自specs here:
如果
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>
&#13;
小提琴1:above ref
在上面的代码段中,我们在容器上使用column-count: auto
,并使用任意column-width: 120px
(仅用于演示)。这就是它的全部。上面的代码中有三个例子:(1)容器宽度小,内容分布在一列,因为它们受column-width
约束; (2)容器中等宽度,内容分为两列,因为现在有更多可用空间; (3)容器宽度大得多,可容纳三根柱子。
作为副作用,如果容器的宽度是百分比,那么整个装置也会自动变为响应。在较大的屏幕上显示更多列,在较小的屏幕上折叠为一列。
但是,这取决于您为容器column-width
提供的固定宽度,因此也可以称为魔术数解决方案。 但是,这不是我们想要的。我们不希望根据容器的宽度确定列,我们希望列由内容宽度确定。我们将在后面的第2部分中看到如何消除该依赖关系。
现在我们已经确定了CSS可以根据父级可用的宽度自动分配元素,我们可以扩展它以消除我们通过Javascript对固定宽度的依赖。
回到你的问题:
......如果最宽的项目比...更宽
为了确定最宽的项目并将该宽度应用于其余项目,您需要的只是http://jsfiddle.net/abhitalks/tgwp4b7a/2/show双线Javascript:
var maxWidth = Math.max.apply(null, $("div.item").map(function () {
return $(this).width();
}).get());
我们还将子div
设置为inline-block
,以防止换行以识别实际宽度。所以,你必须添加到我们在第1部分中编写的CSS中就是:
.container > div {
display: inline-block;
white-space: nowrap; /* prevents wrapping and helps getting actual width */
}
然后我们需要做两件事:(1)将容器上的column-width
设置为我们上面计算的最大宽度; (2)将此宽度设置为所有子div
,以允许它们整齐地堆叠。此外,我们不需要在CSS中设置column-count / column-width
,因为我们必须在Javascript中执行此操作。
$("#container").css({ "column-width": maxWidth }).find('div').width(maxWidth);
请参阅以下代码段中的完整示例:
示例2 :
//large
var maxWidth = Math.max.apply(null, $("#one > div").map(function () { return $(this).outerWidth(); }).get());
$("#one").css({ "-webkit-column-width": maxWidth, "column-width": maxWidth }).find('div').outerWidth(maxWidth);
// medium
var maxWidth2 = Math.max.apply(null, $("#two > div").map(function () { return $(this).outerWidth(); }).get());
$("#two").css({ "-webkit-column-width": maxWidth2, "column-width": maxWidth2 }).find('div').outerWidth(maxWidth2);
// small
var maxWidth3 = Math.max.apply(null, $("#three > div").map(function () { return $(this).outerWidth(); }).get());
$("#three").css({"-webkit-column-width": maxWidth3, "column-width": maxWidth3 }).find('div').outerWidth(maxWidth3);
&#13;
* { box-sizing: border-box; padding: 0; margin: 0; }
p { margin-left: 16px; }
.container { width: 450px; border: 1px solid #f00; margin: 16px; }
.container > div {
-webkit-column-break-inside: avoid; column-break-inside: avoid;
display: inline-block; white-space: nowrap;
padding: 8px; border: 1px solid #ccc;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Normal children (wrapping):</p>
<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>Large children (1-column):</p>
<div id="one" class="container">
<div class="item-min">Maudie Mcmanus Mcmanus 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 children (2-column):</p>
<div id="two" class="container">
<div class="item-min">Maudie Mcmanus 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>Small children (3-column):</p>
<div id="three" class="container">
<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>
&#13;
小提琴2:a well-known
(更改了上面的代码段和小提琴。感谢@Yandy_Viera,他指出应该使用jQuery .outerWdith
而不是.width
(忽略{{1}导致设置不正确的宽度。)
在上面的代码片段中,我们现在使用三个示例变体:(1)其中,子box-sizing: border-box
的宽度较大,并且由于受到容器宽度的限制而分布在一列中; (2)儿童div
的宽度较小,分布在两列,因为现在有更多可用空间; (3)儿童div
的宽度非常小,可容纳三列。
正如您所看到的,CSS可以帮助根据可用宽度将内容分配到列中,但无法计算并将最宽的元素宽度应用于每个列。对于这个,双线Javascript可以让你完成你最初想要的。
注意:当我第一次阅读您的问题时,我的印象是您已经拥有了一个有效的Javascript解决方案,而且我不确定您是否需要它。然而,在第二次阅读时,我意识到你没有,并且Javascript角度对于理解是必不可少的。因此,这个编辑添加了一个Javascript部分。
注意2:此答案的上一版本存在缺陷,我在列属性的自动值中存在一个基本错误。这需要进行另一次编辑。
答案 1 :(得分:10)
他们在评论中所说的一切,都不存在一个只有CSS的解决方案,所以我想给你一个很好的解决方案,使用js
,你甚至不必迭代寻找最宽的项目,一切来自一组CSS和数学。
您可以更改元素的内容,您将看到如何调整列数,如果最宽的项目小于容器宽度/ N,它将自动使用N列。
Check out this JSFiddle for demo
这个想法非常简单,你set width: 'auto'
,display: 'inline-block'
到container
允许它适合其内容,这个内容由最宽元素的宽度定义,请参阅下面的图片img :
现在你可以使用container
的宽度来知道最宽项目的宽度,这样就可以避免你必须迭代寻找它。现在你可以使用这个宽度来设置剩下的项目,但让我们做得更好一点,我们可以让元素占用container
的整个宽度,只需要一个垃圾计算:
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属性,做一点点计算,你就有了你想要达到的目标。
$(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>
如果您想为商品添加保证金,那么在进行数学计算时必须考虑到这一点:
$(document).ready(function() {
var $container = $('.container');
var $item = $('.item');
var initialWidth = $container.outerWidth();
$container.css({
width: 'auto',
display: 'inline-block'
});
var currentWidth = $container.outerWidth();
var itemMargin= parseInt($item.css('margin-right'));
var div = Math.floor(initialWidth / currentWidth);
var itemWidth = initialWidth / div - itemMargin; /*subtracting the item's margin from the compute width*/
$item.css({
width: itemWidth,
float: 'left'
});
$container.css({
width: initialWidth,
display: 'block'
});
})
.container {
width: 400px;
overflow: hidden;
}
.container .item {
padding: 8px;
border: 1px solid rgb(216, 213, 213);
margin-right: 3px;
}
*{
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>
答案 2 :(得分:4)
使用纯CSS解决方案可能获得的最接近的是使用其他人(或CSS网格方法 - 请参阅编辑)建议的CSS列。但是,关键是使用相对单位并非常了解布局中列位容器的位置和位置,并使用媒体查询来控制列数。这绝对是 NOT 一个防弹解决方案。但是,如果要创建布局并控制列容器元素的放置和范围,则可以相当可靠地控制列数。如果这是针对您无法控制的窗口小部件,您确实需要实现基于Javascript的解决方案。
参考链接:Responsive CSS Columns,CSS Grid Layout
编辑:在再次阅读您的问题并查看您的屏幕截图示例后,看起来您实际上正在寻找一种常见的CSS网格网格解决方案,其中元素水平流动而不是垂直流动。我更新了我的答案,包括一个片段演示,其中块重新流动。
基于列的媒体查询和容器宽度的片段演示(大约最小列宽为10em):
#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>
编辑:使用CSS网格方法添加了此片段演示,该方法可以水平而不是垂直地重新流动块。
#main, #sideBar {
box-sizing:border-box;
display:block;
padding:0;
margin:0;
width:100%;
clear:left;
}
.container {
width: 100%;
min-width:10em;
}
.container .item {
display: block;
float:left;
padding: .5em;
border: 1px solid rgb(216, 213, 213);
box-sizing:border-box;
vertical-align: top;
}
@media only screen and (min-width:20em) {
.container .item {
margin: 0 1%;
width:48%;
}
}
@media only screen and (min-width:32em) {
#main {
float:left;
width:65%;
}
#sideBar {
float:left;
clear:none;
width:30%;
margin-left:5%;
}
#sideBar .container .item {
margin: 0;
width:100%;
}
}
@media only screen and (min-width:48em) {
#main .container .item {
width:31%;
}
}
@media only screen and (min-width:52em) {
#sideBar .container .item {
margin: 0 1%;
width:48%;
}
}
@media only screen and (min-width:100em) {
#main .container .item {
width:18%;
}
#sideBar .container .item {
width:31%;
}
}
<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>
答案 3 :(得分:1)
首先 - 看看
Fiddle Demo (使用.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's 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);
}
答案 4 :(得分:0)
最简单的似乎是将宽度设置为32%加上clear:所有列都没有,单独的clear:每三(最后)列都有一个类。添加媒体查询以解决不同的屏幕尺寸并相应地设置宽度,例如, 24%,48%等
答案 5 :(得分:0)
试试这个例子
@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}}