Arranging elements from Top to Bottom using Grid Layout

I hoped being set the challenge of organising a group of list items so that they’re arranged top to bottom, left to right was going to be fairly simple with CSS Grid Layout; but it proved a little tougher than I expected.

With grid-auto-flow:column I expected that I could easily use this, define some columns and it would automagically sort out the number of rows required. However in this instance it appears you must also specify a number of rows for the grid. If you don’t, the grid items appear to overflow the container in order to remain on a single row.

For many, having to set the number of rows wouldn’t be an issue, but with multiple lists of varying length, which could grow in the future, it’s impractical to be so specific with the number of rows in this instance.

After some tinkering, and a few failed attempts, I finally came up with a solution…

See the Pen CSS Grid Top to Bottom by Kean Richmond (@keanr) on CodePen.

click “Edit on Codepen” to play with screen width and view more columns

What’s going on here?

To get the number of rows I first need to know the number of items in each list and deliver that to my CSS. I do this through the use of Custom Properties (a.k.a CSS variables) and including this as inline CSS on each <ul>. As I have a different number of columns at different breakpoints I also specify the number of rows needed when the layout changes to a different number of columns (in the example I have between 1 and 4 columns).

Though not in the example above, my list is generated from a database so I have some simple PHP code that generates the number of rows for my inline CSS.

$num = mysqli_num_rows($query);
$breakpoints = ' style="--grid-rows:' . $num . ';--grid-rows-2:' . ceil($num/2) . ';--grid-rows-3:' . ceil($num/3) . ';--grid-rows-4:' . ceil($num/4) . ';"';

Moving to the CSS file. I use the custom properties to define the number of rows in grid-template-rows at each @media defined breakpoint. In addition to this, to save repetition of the grid-template-rows property I instead redefine the value of the custom property at each breakpoint by changing what I have as my default custom property to the value of one of the others I’ve set depending on the number of columns I have displaying at the time. Unfortunately this does require the use of !important to do this.

Isn’t this a bit hacky?

To be honest it’s not the first solution I aimed for. I’d much prefer to have specified only the number of items in the list and done all the calculations for the number of rows required per column within the CSS file using calc(); but all options I attempted failed.

With CSS Grid Layout and Custom Properties both emerging technologies I’ll admit I’m still learning and that may have worked against me. However the issues I experienced mostly appeared to be due to being unable to use calc() in conjunction with grid-template-rows to define the number of rows required. For example, none of the below would work for me…

.grid-ttb {grid-template-rows:repeat(calc(16/2),1fr);

.grid-ttb {grid-template-rows:repeat(attr(data-gridcol),1fr);

:root{
--grid-col: calc(16/2);
}
.grid-ttb {grid-template-rows:repeat(var(--grid-col),1fr);

I’m hopeful a simpler solution is available and that Google is just playing hide and seek with the answer, but for now this works for modern browsers that support CSS Grid and Custom Properties and may help others attempting to do the same.

If you find or know of a better solution, please add a link in the comments.


We'd love to hear from you!

If you think Bronco has the skills to take your business forward then what are you waiting for?

Get in Touch Today!

Discussion

Add a Comment