Multi-column manipulation
Despite predating both Grid and Flexbox, Multi-column Layout represents—at least to me—an even more radical departure from the way we normally do and think about CSS layout. Dividing just one element into a multi-column representation of its contents feels weird, heretical even.
Setting a multi-column context means asking (flow) content to progress, by column, in a horizontal direction. This invokes one of two issues, depending on whether you set a height on the element.
With no set height, there's no limit to the height of the columns. This will result in vertical overflow, and the necessity to scroll down and up the page to read each successive column. Many are likely to find this arduous.
With a set height, columns are forced to spawn in the inline (horizontal) direction, creating horizontal overflow. Setting overflow: auto
frames this correctly.
.columns {
height: 25vh;
/* ↓ columns defined by width */
columns: 30ch;
overflow: auto;
}
However, despite the increasing popularity of scrolling menus and other such patterns harnessing horizontal scrolling, it is still an unconventional interaction paradigm — and unconventional patterns are liable to be misapprehended by users. There are ways to increase perceived affordance, of course—perhaps by adding some custom styling to the scrollbar (-webkit-scrollbar
), or providing some overflow-dependent shadows. But this may not be enough.
Quantity-dependent columns
One thing I have been experimenting with is the application of multiple columns in response to content quantity.
Let's say I have a bullet list, and let's assume each bullet point is likely to be relatively short; no more than a sentence. There's no benefit to dividing the list into columns when there are only a few points. But the overall height of the list is shortened (and the chance of the reader being able to see the whole list without scrolling is increased) when a long list is divided into two.
In the following example, the list is split into two columns where there are 5 or more list items.
ol, ul {
columns: 2;
column-gap: 1rem;
}
li {
column-span: all;
}
li:nth-last-child(n+5),
li:nth-last-child(n+5) ~ * {
column-span: none;
}
By default, column-span
is set to all
, meaning each list item ignores the two-column mandate. A quantity query (the final declaration block) then resets column-span
to none
where 5 or more list items are present. Despite the misleading none
value, this means list items will span one of the two columns.
To follow is a live demo. Try opening up developer tools and removing a couple of list items. Note that this behavior is not currently available in Firefox. There is a bug open to implement column-span
. Thank you to Erik Wallace for finding it.
-
Ac Feugiat Ante Sed Mauris Iaculis Ac Feugiat Quam Id -
Vulputate Non In Diam Ornare Feugiat Sapien Cubilia -
Posuere Id Mi Morbi Ornare Quam Nullam Amet A -
Tristique Felis Nibh Accumsan Ex Odio Non Tellus -
Ante Sit Quam Quam Tempus Laoreet Sed Morbi Sollicitudin Varius -
At Congue Tempus Ligula Iaculis Euismod Phasellus Neque Consequat Eu
Block direction overflow
As Rachel Andrew has proposed, it would be beneficial to be able to control both the inline and block overflow direction. The support of block overflow would mean we could assume control over both column width and height. So long as the chosen height is no taller than the current viewport, the repetitive vertical scrolling issue described above disappears.
How block overflow direction is implemented and exposed is still up for grabs so, if you have any ideas, you may want to voice them.
My initial thinking is that a column-height
property should be supported alongside column-width
and column-count
. The columns
shorthand property would then need to take height as a third parameter.
Currently, columns
takes column-width
and column-count
in any order—presumably because parsing can identify which is a length value and which is just an integer. This becomes more complex with two length parameters, so an expected order for these properties may need to be set. If that expected order is width-before-height, then the following values would be considered valid (where 30ch
represents the width, and 25vh
represents the height):
.columns {
columns: 30ch 25vh;
}
.columns {
columns: 30ch 25vh 3;
}
.columns {
columns: 30ch 3 25vh;
}
.columns {
columns: 3 30ch 25vh;
}
It's worth noting that 'hard-coding' a column-count
is not likely to be useful in most cases, since both columns and rows are now being dynamically provisioned based on the available space. It's also worth noting that column-width
sets an ideal width, not a fixed one, much like flex-basis
. This eliminates overlaps and gaps.
The column-gap
property injects space between columns. With support of column-height
in place, row-gap
would have to be supported as well. Although you are probably more familiar with the CSS Grid-specific properties grid-gap
, grid-row-gap
, and grid-column-gap
, Firefox already supports the generic gap
, row-gap
, and column-gap
properties for Flexbox. The intention is to normalize gap
across the Grid, Flexbox, and Multi-column modules.
If you find yourself wrestling with CSS layout, it’s likely you’re making decisions for browsers they should be making themselves. Through a series of simple, composable layouts, Every Layout will teach you how to better harness the built-in algorithms that power browsers and CSS.