Dynamic number of rows and columns with CSS Grid and CSS variables

Creating responsive layouts back then, without the help of SCSS, was a pain in the ass. SCSS helped a lot, but it is only helpful for ordinary use cases. What if we want users to change the number of columns on the fly? We probably have to use JavaScript to change the class of all grids whenever we change the number of columns. And we need to predefined these classes on our stylesheet. Or we can change the width of all grids using JavaScript. Of course, nothing is impossible with some JavaScript. We all know that CSS and JavaScript together work magic. But, isn’t it awesome that we have a new alternative way to accomplish this with the recent introduction of CSS Grid Layout (Chrome 57, Firefox 52, Safari 10.1, and Edge 14) and CSS Variables (Chrome 49, Firefox 51, and Safari 10) to the browsers ?

The time to learn CSS Grid Layout and CSS Variables is NOW.

CSS Variables

For those who don’t know CSS Variables, do not be scared. It’s actually very simple. Think of these variables like our JS vars, but they are most commonly declared in our CSS inside :root {} (you can also declare the variables in the CSS of the parent element of the element which is going to use the variables), with two dashes as prefix, and can be accessed by JavaScript later.

:root {
--rowNum: 4;
--colNum: 5;
--gridHeight: 120px;
--wrapperH: 40px; // for demonstrating the use of CSS Variables
}

To use these variables in CSS, just wrap a variable in var().

.wrapper { 
height: var(--wrapperH);
}

CSS Grid Layout

CSS Grid Layout comes with so many CSS properties that it certainly deserves a long article on its own. And to be honest, the crucial thing that helps make this dynamic number of columns so much easier is the use of CSS variables. I will only briefly explain the CSS properties of CSS Grid Layout used here. For a more thorough tutorial, please check out the links at the end of this article.

First, let’s take a look at my DOM in Pug (Jade).

.wrapper
- var g = 20
while g--
.grid-item

There is a .wrapper div. Inside it, there are 20 .grid-item divs.

In the CSS, we must give .wrapper display: grid; in order to use CSS Grid Layout.

So what else now?

The 3 variables I declared at the :root are all going to be in .wrapper{}.

There is a CSS property called grid-template-columns. We can declare how many columns we want in a row. There can be many different syntaxes for it. I will use repeat(); to serve my purpose.

repeat(); takes at least two arguments. The first one indicates the number of columns, and the second one indicates the width of each column.

This is what the line in my .wrapper{} looks like:

grid-template-columns: repeat(var(--colNum), auto);

For grid-template-rows, it’s similar. The first argument in repeat(); indicates the number of rows, and the second one indicates the height of each row. I have to use a CSS Variable for the number of rows because I find out that the height argument does not make new .grid-item in a supposedly new row the same height. Instead, the new row (let’s say row number 5), would not be displayed if the CSS line is grid-template-rows: repeat(4, 100px);

With all its CSS styles, .wrapper{} looks like this:

.wrapper {
display: grid;
grid-template-rows: repeat(var(--rowNum), var(--gridHeight));
grid-template-columns: repeat(var(--colNum), auto);
}

For the .grid-item(s), if I want to use the simplest layout, which means filling the whole wrapper with .grid-item(s), leaving no margin, the easiest way is to not give CSS styles to this class. But to show what we can potentially change, I added:

.grid-item {
grid-column-start: auto;
grid-row-start: auto;
margin: 5px;
}

Keep in mind that a margin on .grid-item and a grid-gap on .wrapper produce different results. If you use margin, the sides of the .wrapper would have 5px emptiness, whereas using grid-gap on .grid-item would not leave a margin at the sides. In my codepen I have updated from margin to grid-gap. You can play around with it and see the difference.

Accessing CSS Variables with pure JavaScript

To get the CSS Variables, use

let htmlStyles = window.getComputedStyle(document.querySelector("html"));
let rowNum = parseInt(htmlStyles.getPropertyValue("--rowNum"));

To change the value of the CSS Variable, use

document.documentElement.style.setProperty("--rowNum", 6);

It’s very easy, isn’t it?

Conclusion

Viola! Here is my CodePen demo:

I love that we don’t have to wrap extra divs, nor to write endless position: relative; position: absolute; to get the margin right!

Play around with my CodePen or create your own! Comment below to share your thoughts with me. :)


Follow me if you like this article! I would share my Front-end experiments whenever I have time ;)