纯粹的CSS解决scheme,用于将项目拆分为dynamic数量的列

有没有一种方法来alignment列中的项目,列的数量取决于最宽的项目? 项目高度和容器宽度都是固定的,但项目宽度是dynamic的。

我正在寻找一个CSS的唯一方法来实现以下行为:

(假设父容器的宽度是300px。)

  • 如果最宽的项目宽于150像素,请使用单个列
  • 如果最宽的项目在100px和150px之间,则使用两列
  • 如果最宽的项目小于100像素,则使用三列
  • 如果最宽的项目小于容器宽度/ N,则使用N个列

产生这种行为的一种可能的方法是使用display:inline-block并将width属性设置为使用JavaScript的容器中最宽元素的宽度。

看到这个JSFiddle的例子:

例

不过,我认为还应该有一个CSS的唯一方式来做到这一点。 可能吗?

如果没有,也许有一个优雅的CSS的方式分发/捕捉dynamic大小的项目到一个固定宽度的容器中的列?

…我正在寻找一种CSS的方式来实现以下行为…如果最宽的项目比…更广泛…

…我在想这样做也应该有一个CSS的唯一方法…

正如@ Paulie-D所示 ,CSS不能检测到你的子div的变化宽度,因此纯CSS的解决scheme是不存在的。

这是因为你想获得所有元素的宽度,然后获取这些元素的最大值,然后使用该宽度将元素分配到列中。 这个计算超越了CSS。 你将需要使用Javascript来做到这一点。

如果没有,也许有一个优雅的CSS的方式分发/捕捉dynamic大小的项目到一个固定宽度的容器中的列?

我将分两部分来解释:


第1部分,CSS:

当我们说我们想要内容在列中时,意味着从上到下的stream程,而不是从左到右的包装stream程。 为此,我们需要CSS列。

诀窍是指定autocolumn-count / column-width 这将自动将内容分配到父宽度内所需的列数。

我在上面的声明中犯了一个根本性的错误( 因此是另一个编辑 )。 根据这里的规格 ,algorithm说:

  (01)if((column-width = auto)和(column-count = auto))那么
 (02)出口;  / *不是多元素元素* / 

这是我之前错误的地方。 当column-countcolumn-width设置为auto它将被视为不是多元素元素 。 当其中一个属性被设置为非自动值时,则其他属性由该属性确定。

从上面的参考 :

如果column-count设置为auto ,那么列的数量将由其他属性(例如, column-width ,如果它具有非自动值)确定,并且如果column-width被设置为auto ,那么列宽度将由其他属性决定(例如, column-count ,如果它具有非自动值)

一个例子是将column-width设置为固定宽度,例如120px稍后我们将在第二部分中处理 ):

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

这将导致容器将内容放入尽可能多的列中,以使其宽度为120px的列宽。 如果增加容器宽度,将会得到更多的列。 如果减小容器宽度,那么当没有足够的可用空间时,它将获得较less的列,最终会折叠为单个列。

请参阅下面的代码片段中的完整示例:

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

以及所有他们在评论中说,不存在一个CSS的唯一解决scheme,所以我想给你留下一个很好的解决scheme,你甚至不必迭代寻找最广泛的项目,一切都来自一套CSS和math。

您可以更改元素的内容,您将看到如何调整列的数量,如果最宽的项目小于容器宽度/ N,它将自动使用N列。

看看这个JSFiddle的演示

这个想法很简单,你可以set width: 'auto'display: 'inline-block'container ,使它适合宽度最宽的元素的内容在波纹pipe中看到它img:

在这里输入图像说明

现在你可以使用container的宽度来知道最宽项目的宽度,这样可以避免你必须迭代寻找它。 现在你可以使用这个宽度来设置其余的项目,但是让我们做的更好一点,我们可以使元素占据container的整个宽度,只需要一个枯燥的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> 

最接近纯CSS解决scheme的是使用其他人所build议的CSS列(或CSS Grid方法 – 请参阅编辑) 。 但是,关键是要使用相对单位,并非常了解您的布局中的位置和列容器,并使用媒体查询来控制列数。 这绝对不是一个防弹解决scheme。 但是,如果要创build布局并控制列容器元素的位置和范围,则可以相当可靠地控制列计数。 如果这是一个超出你的控制的小部件,你将确实需要实现一个基于Javascript的解决scheme。

参考链接: 响应CSS列 , CSS网格布局

编辑:再次阅读你的问题,看看你的屏幕截图的例子,看起来好像你实际上寻找一个共同的CSS网格网格解决scheme的元素水平,而不是垂直stream动。 我更新了我的答案,其中包括一个片段演示,其中块水平重新stream动。

使用基于媒体查询和容器宽度(近似最小列宽为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的解决scheme。 主要是因为CSS被devise为在dom内容之前加载,所以内容很好地显示。 我们这里主要的问题是,我们不知道元素的宽度,只有在页面加载的时候才知道。 几乎页面上的所有解决scheme都有相同的想法,使用Javascript来循环查找元素,find最宽的元素,并将所有其他元素(具有相同的类)设置为给定的宽度。 为了改进stream程,并使其成为一个单行的解决scheme(使用jQuery,也可以用Javascript来完成,但为了简单起见,我使用了jQuery),我build议下面的“hack / trick”:

1)不要定义容器的宽度,并将显示设置为表格而不是块;

2)不要为div内的项目设置任何宽度

这将使项目具有相同的宽度并显示在一列中,所以当我们使用jQuery获取最大宽度时,我们不需要循环通过元素。

现在使用jQuery将额外的CSS规则注入到容器和项目的文档头中。 我们需要将容器显示types更改为块而不是表格,将它的宽度设置为400px(或者我们需要的任何东西),并且我们需要以设置的宽度制作项目的内嵌块。

由于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中testing过了,它可以在所有的浏览器上运行。

编辑1

如果你不想使用jQuery来保持页面尽可能的轻,你也可以使用下面的一行代码:

 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将包括填充和项目的边界,因为在原始示例中的填充是8px,边框是1px,我们需要从容器的宽度两次(一次左边一次)扣除它。

看到更新的小提琴

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

首先 – 检查小提琴演示 (使用.container的宽度…)

这是不可能的只使用CSS,但这里是一个优雅的解决scheme,使用jquery,它检测容器的宽度,最宽的项目的宽度,并将项目分散到相关数量的列(dynamic创build)。

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

最简单的似乎将宽度设置为32%,再加上clear:none表示所有列,另一个表示clear:两个类每三分之一(最后一列)。 添加媒体查询以解决不同的屏幕尺寸并相应地设置宽度,例如24%,48%等

试试这个例子

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