...I am looking for a CSS-only way to achieve the following
behavior...If the widest item is wider than...
...I am thinking that there should also be a CSS-only way
of doing this...
As indicated by @Paulie-D, CSS can't detect varying widths in your child div
s and hence a pure CSS only solution is not existent.
This is because you are wanting to get the widths of all elements, then get the max of those, and then use that width to distribute elements into columns. This computation is beyond CSS. You will need Javascript to do that.
If not, perhaps there is an elegant CSS-only way of distributing /
snapping the dynamically-sized items to the columns in a container
with a fixed width?
I will explain that in two parts:
Part 1, the CSS:
When we say that we want content to be in columns, it means a top-to-down flow instead of just left-to-right wrapping flow. For this we require CSS Columns.
The trick would be to specify auto
for column-count / column-width
. This will automatically distribute the content into the number of columns required within the parent width.
I made a fundamental mistake in the above statement (hence another edit). As per the specs here the algorithm says:
(01) if ((column-width = auto) and (column-count = auto)) then
(02) exit; /* not a multicol element */
This is where I was wrong earlier. When both column-count
and column-width
are set to auto
then it is treated as not a multicol element. When one of these properties is set to non-auto value, then the other property is determined by this one.
From the above ref:
if column-count
is set to auto
, then the number of columns will be determined by other properties (e.g., column-width
, if it has a non-auto value)
and
if column-width
is set to auto
, then the column width will be determined by other properties (e.g., column-count
, if it has a non-auto value)
An example would be to set column-width
to a fixed-width, say 120px
(we will deal that in part 2 a little later):
.container { -webkit-columns: auto 120px; columns: auto 120px; }
This will cause the container to fit the content in as many columns as it can for a column width of 120px
within its own width. If you increase the container width, it will get more columns. If you decrease the container width, it will get less columns eventually collapsing to a single column when there is not much space available.
See the complete example in snippet below:
Example 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>
Fiddle 1: http://jsfiddle.net/abhitalks/tgwp4b7a/2/show
In the above snippet, we are using column-count: auto
on the container, and an arbitrary column-width: 120px
(just for demo). It is all there is to it. There are three examples in the code above: (1) where container is of small width and content is distributed in one columns as they are constrained by the column-width
; (2) where container is of medium width and content is distributed in two columns as there is now more space available; and (3) where container is of much larger width and can accommodate three columns.
As a side-effect, if the container's width is in percent, then the whole apparatus automatically becomes responsive as well. On larger screens showing more columns, and on smaller screens collapsing to one column.
However, this is dependent on the fixed-width that you give to the container's column-width
and hence can also be called a magic-number solution. But, this is not what we want. We do not want to determine columns based on container's width, we want the columns to be determined by the content width. We'll see how to eliminate that dependency in the part 2 that follows.
Part 2, extending it with Javascript:
Now that we have established that elements can be distributed automatically by CSS in columns depending on the width available on parent, we can extend this to eliminate our dependence on fixed-width via Javascript.
Coming back to your question of:
...If the widest item is wider than...
In order to determine the widest item and apply that width to the rest of them, all that you require is just a well-known two-liner Javascript:
var maxWidth = Math.max.apply(null, $("div.item").map(function () {
return $(this).width();
}).get());
We also set child div
s to inline-block
prevent wrapping to identify the real width. So, all you have to add to the CSS we wrote in part 1 is this:
.container > div {
display: inline-block;
white-space: nowrap; /* prevents wrapping and helps getting actual width */
}
Then we need to do two things: (1) set the column-width
on container to this max-width that we calculated above; and (2) set this width to all of the child div
to allow them to stack neatly. Also, we will not be needing column-count / column-width
to be set in CSS, because we have to do that in Javascript anyway.
$("#container").css({ "column-width": maxWidth }).find('div').width(maxWidth);
See the complete example in snippet below:
Example 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);
* { 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;
}
<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>
Fiddle 2: http://jsfiddle.net/abhitalks/ojd57678/4/show
(Changed the above snippet and fiddle. Thanks to @Yandy_Viera, who pointed out the fact that jQuery .outerWdith
should be used instead of .width
(which ignores box-sizing: border-box
, causing incorrect widths to be set.)
In the above snippet, we are now using three variations of examples: (1) where child div
s are of larger width and are distributed in one column as they are constrained by the container's width; (2) where child div
s are of smaller width and are distributed in two columns as there is now more space available; and (3) where child div
s are of very small width and can be accommodated in three columns.
As you can see, CSS can help in distributing content into columns based on available width but cannot calculate and apply widest of the element widths to each of them. For this a two-liner Javascript would get you done what you initially wanted.
Note: When I first read your question I was under the impression that you already have a working Javascript solution with you, and I wasn't sure if you wanted one. However, on a second read I realized that you hadn't, and the Javascript angle was essential to understand. Hence, this edit to add a Javascript part.
Note 2: There was a flaw in the previous version of this answer, where I let in a fundamental mistake in auto values of the columns properties. This necessitated another edit.