CSS custom properties + CSS grid grid to achieve super layout capability

Time:2019-11-20

I’ve been using CSS grid in my work for several months, and I really like the flexibility it gives me when it comes to page layout. For so long, we haven’t had a real grid layout solution – there are always various limitations to using floats and flexboxes. But now, I really can’t imagine CSS without grid!

One of the things I’ve noticed recently is CSS custom properties. CSS custom properties work a bit like variables in sass and other preprocessors. The main difference is that other methods are generated after compilation in the browser or the original CSS writing method. CSS custom properties are real dynamic variables that can be updated instantly in style sheets or using JavaScript, which makes them more likely. If you’re familiar with JavaScript, I like to think of the difference between preprocessor variables and CSS custom properties as similar to the difference between const and let – they all have different uses.

CSS custom properties can easily implement many functions (such as theme change). Recently, I have been trying to use the combination of CSS custom properties and CSS grid to achieve some magical effects. I need to redefine grid template rows and grid template columns properties at different breakpoints. In the following code, for example, I use the sass variable to define different column width values of the page under different width, which will be passed to the grid template rows attribute. I did the same for the grid gap attribute, so the spacing between elements is different when the page width is different:

$wrapper: 1200px;
$col: 1fr;
$gutter: 20px;

$wrapper-l: 90%;
$col-l: calc((1000px - (13 * 40px)) / 12);
$gutter-l: 40px;

$col-xl: calc((1200px - (13 * 50px)) / 12);
$gutter-xl: 50px;

body {
    background-color: lighten(grey, 30%);
}

.wrapper {
    max-width: $wrapper;
    margin: 20px auto;
    
    @media (min-width: 1300px) {
        max-width: $wrapper-l;
    }
}

.grid {
    display: grid;
    padding: $gutter;
    grid-template-columns: 1fr repeat(12, $col) 1fr;
    grid-template-rows: repeat(2, minmax(150px, auto));
    grid-gap: $gutter;
    border: 1px solid grey;
    background: white;
    width: auto;
    
    @media (min-width: 1300px) {
        grid-template-columns: 1fr repeat(12, $col-l) 1fr;
        grid-gap: $gutter-l;
        padding: $col-l;
    }
    
    @media (min-width: 1500px) {
        grid-template-columns: 1fr repeat(12, $col-xl) 1fr;
        grid-gap: $gutter-xl;
        padding: $col-xl;
    }
}

.grid__item {
    border: 1px solid blue;
}

.grid__item--heading {
    grid-column: 2 / 11;
}

CSS custom properties + CSS grid grid to achieve super layout capability

Click to view all the codes and real-time effects in the figure above

As you can see, you basically have to write the entire code block again in the media query to change the style, because once the variable is defined, it is fixed. (I can use mixin, of course, but the end result is the same – a chunk of code.)

Using CSS custom properties can reduce the amount of code, because I only need to update the variables in the media query, and the browser will recalculate the grid. Ten line (SASS) code may not seem like a huge savings, but the readability of the code is much higher, because we don’t need to add media queries in several places to process our new variables, I just need to declare them at the beginning of the code of the component, and I don’t need to worry about whether I have replaced the value being used:

:root {
    --wrapper: 1200px;
    --col: 1fr;
    --gutter: 20px;
    
    @media (min-width: 1300px) {
        --wrapper: 90%;
        --col: calc((1000px - (13 * 40px)) / 12);
        --gutter: 40px;
    }
    
    @media (min-width: 1500px) {
        --wrapper: 90%;
        --col: calc((1200px - (13 * 50px)) / 12);
        --gutter: 50px;
    }
}

body {
    background-color: lighten(grey, 30%);
}

.wrapper {
    max-width: var(--wrapper);
    margin: 20px auto;
}

.grid {
    display: grid;
    padding: var(--gutter);
    grid-template-columns: 1fr repeat(12, var(--col)) 1fr;
    grid-template-rows: repeat(2, minmax(150px, auto));
    grid-gap: var(--gutter);
    border: 1px solid grey;
    background: white;
    width: auto;
}

.grid__item {
    border: 1px solid blue;
}

.grid__item--heading {
    grid-column: 2 / 11;
}

.grid__item--body {
    grid-column: 2 / 8;
    grid-row: 2 / span 1;
}

.grid__item--media {
    background: hotPink;
    grid-column: 11 / 14;
    grid-row: 1 / span 2;
}

CSS custom properties + CSS grid grid to achieve super layout capability

Click to view all codes and real-time effects

One of the features of using CSS grid is that the syntax is very lengthy, and it is not easy to see what is happening quickly and easily, especially in the complex grid. But in this case, using CSS custom properties, you can set variables for the size and coordinates of grid items, and write the grid column and grid row properties only once. For me, it’s much clearer than writing out the full attributes every time, and it’s easy to see the location of grid items at a glance.

Here is a demo that randomly and dynamically changes a custom variable. In this example, I use JavaScript to loop through grid items and update variables with random values each time I click a button. No classes or extra CSS were added.

In this example demo, the grid items are dynamically changed using the values entered by the user. All you need to update here are the three variables of the X and Y coordinates and the size of the grid item.

Too many possibilities!

Browser support
At present, 88% of browsers around the world support CSS custom properties, with the exception of Internet Explorer 11 and below. This is roughly the same as support for CSS grid grid layout, which means using feature queries to distinguish between supported and unsupported browsers.

You can use the @ supports declaration to test support for CSS custom properties as follows:

@supports(--css: variables) {
        .my-div {
            --size: 2;
            --posX: 3;
            grid-column: var('--posX') / span var('--size');
        }
    }

CSS custom properties + CSS grid grid to achieve super layout capability