Excellent Adventures in CSS Grid – ON TOUR!

Recently I did my first talk for about two years at Milton Keynes Geek Night, I was really nervous after such a long break but thoroughly enjoyed it! So much so I decided to take my talk on tour! Which is exciting! 🙂

There is a lot of code examples and links to extra reading in this talk, so this post acts as a “catch all” for all of those extra resources.

Here is the current version of the talk:

You can find the CodePen Collection here: https://codepen.io/collection/AvJKoR/

Complete Reading List:

Tour dates for 2019:

25th June – WordPress Birmingham
27th June – Milton Keynes Geek Night
17th July – Staffs Web Meetup, Stafford
29th August – Frontend Sheffield
17th September – Brum JS, Birmingham
26-27th November – Frontend Connect, Warsaw

Excellent Adventures in CSS Grid

So yesterday I did a thing. I gave a talk called “Kirsty’s Excellent Adventure in CSS grid.” at Milton Keynes Geek Night.

For anyone who may not know, MK Geek Night is an awesome evening event held every 3 months in Milton Keynes. It has a stirling reputation and is super successful, so it was a complete honour to be allowed to come along and talk about CSS stuff. I truly, had a fantastic evening and I would highly recommend going if you ever happen to be in the area.

Anyway, I wanted to be one of those super cool people that had a blog post that both published and tweeted the link to the post automatically, as soon as I finished on stage, but sadly, I was not that organised.

So better late than never, here are my slides for my talk about CSS Grid.

Something I didn’t mention in my talk that I really should have done, is that, as well as all of the reading materials I linked to, I also created a CodePen Collection for this talk that includes all of the examples as well as a few other experiments.

You can find that here: https://codepen.io/collection/AvJKoR/

If you don’t want to skip through the slides for all of the reading materials here is a complete list for you:

If any of you reading this attended the event, I hope you enjoyed the talk. I would like to deliver this talk again so if you have any feedback I would love to hear it 🙂

CSS GRID Fallback for IE using SASS Lists

When placing items in a CSS Grid, in modern browsers we can rely on auto-placement to do most of the heavy lifting for us, however when providing support for IE10 & 11, we have to write CSS code to explicitly place all of your items in the Grid.

This is because auto-placement is not supported in IE10 & 11 and sadly, it is also one area where Autoprefixer can’t help us either 😦

Writing all of this additional code can often be a pain so I’ve created a utility using SASS Lists to help make it a little less painful.

But why can’t Autoprefixer help?

Autoprefixer in its simplest form will look at each line of CSS, check it against caniuse.com and if it is not supported by a certain browser, but a prefixed version is available, it will add a line that includes the vendor prefix. For example:

::placeholder {
  color: gray;
}

Would output the following after Autoprefixer has been run:

::-webkit-input-placeholder {
  color: gray;
}
:-ms-input-placeholder {
  color: gray;
}
::-ms-input-placeholder {
  color: gray;
}
::placeholder {
  color: gray;
}

Great right?

But back to CSS GRID…

If we wanted to have a grid of four items, two in each column and row, we can achieve that easily by defining the grid-template-columns and grid-template-rows on the container:

.grid-container {
    display: grid;
    grid-template-columns: repeat( 2, 1fr );
    grid-template-rows: repeat( 2, 1fr );
}

Thanks to CSS GRIDs auto-placement we don’t need to do anything else, each grid- item will be repeated twice across both columns and rows and will fit 1 fraction so will appear equal in height and width. YAY!

The problem with Internet Explorer

As mentioned at the beginning, Internet Explorer does not support auto-placement. To be able to use GRID, we have to explicitly position grid-items. If we don’t do that then all of the items will stack in the first cell of the grid 😦

This means thats our code goes from:

.grid-container {
    display: grid;
    grid-template-columns: repeat( 2, 1fr );
    grid-template-rows: repeat( 2, 1fr );
}

to:

.grid-container {
    display: -ms-grid;
    grid-template-columns: repeat( 2, 1fr );
    -ms-grid-columns: 1fr 1fr;
    grid-template-rows: repeat( 2, 1fr );
    -ms-grid-rows: 1fr 1fr;
}

.grid-item-1 {
    -ms-grid-column: 1;
    -ms-grid-row: 1;
}

.grid-item-2 {
    -ms-grid-column: 2;
    -ms-grid-row: 1;
}

.grid-item-3 {
    -ms-grid-column: 1;
    -ms-grid-row: 2;
}

.grid-item-4 {
    -ms-grid-column: 2;
    -ms-grid-row: 2;
}

😦

But it’s not all bad, looking at all of those -ms- vendor prefixes used, this is where Autoprefixer has stepped in and fixed it for us right? Sadly no.

Because we haven’t used grid-column and grid-row first, (why would we when we don’t need the grid items to be explicitly placed in any browsers other than IE? ) Autoprefixer can’t see that there is anything that needs to be prefixed.

So, thanks to IE there is now a lot more code for our grid which we have to add manually and it is all starting to get very messy…

SASS to the rescue!

There isn’t a lot we can do about the amount of code needed to ensure our Grid works in IE as well, but we can tidy it up using SASS Lists and a @for loop so that it looks better in our codebase like this:

$total-items: 4;
$ms-layout: 1 1,
            2 1,
            1 2,
            2 2;

@for $i from 1 through $total-items {
    $position: nth( $ms-layout, $i );

    .grid-item-#{$i} {
	-ms-grid-column: nth($position, 1);
	-ms-grid-row: nth($position, 2);
    }
}

There is quite a lot going on in this little snippet so let’s break it down a bit.

This is the number of grid-items on the grid.

$total-items: 4;

This is our SASS List, it contains four rows, each with the position of the grid-column and then grid-row.

$ms-layout: 1 1,
            2 1,
            1 2,
            2 2;

Next we start a loop using $total-items so that the loop does not execute more than four times. Loop through each row using nth to retrieve the values for each grid-item in the $ms-layout list that correlates with where in the loop we are, and create a new list called $position.

The new list contains only the two values relevant to that grid-item. For example grid-item-3 would have a sass list that looks like $position: 1 2;

@for $i from 1 through $total-items {
    $position: nth( $ms-layout, $i );

Finally, we output the column and row positions:

    .grid-item-#{$i} {
	-ms-grid-column: nth($position, 1);
	-ms-grid-row: nth($position, 2);
    }

Using nth again we get the first value of $position for the column and the second value for row. Done!

Here is a complete example using six grid-items:

I’m sure many of you are thinking “Why bother going to this extra effort?”

This technique doesn’t stop the need for all of those extra lines of code to ensure your grid works in IE, and once the SASS has been compiled it will still output all of those lines, so you could stop at writing the vendor prefixes for IE and it would be backwards compatible.

But, if you are like me and find yourself continually copying and pasting them from project to project, it does keep your SASS a little bit neater and for me that is always worth the effort 🙂

Some Further Reading:

CSS Multicolour border and gradient

Recently I was asked to create a container that had a top border with a gradient applied to fade the border from blue to purple. But, the container also needed a background gradient that matched the border, and also faded out to white before the content started. Like this:

There are lots of ways to apply a gradient to a border, many illustrated in this excellent CSS Tricks article, and it is pretty easy to apply gradients to a background-image by using linear-gradient now as well.

The difficulty came when I realised I wanted to apply three different affects (border gradient, background gradient, and fade to white) to the same container without adding any additional markup.

In the end I achieved this by making use of pseudo elements and applying only two effects in total. Here is my solution:

First I started with my container markup and base styles for that.

<div class="container">
</div>
.container {
   display: block;
   width: 100vw;
   height: 100vh;
}

For the sake of this demo, I have set my container to the full width and height of the screen. Next we set both a :before and an :after pseudo element on the container.

.container {
   [...]

   &::before,
   &::after {
     content: "";
     position: absolute;
     left: 0;
     right: 0;
   }
}

Now that we have the foundations set all that is left to do is apply the effects.

.container {
   [...]

   &::before {
     background-image: linear-gradient( to right, #6a26b5, #007bc2 );
     height: 100px;
     top: 0;
   }

   &::after {
     background-image: linear-gradient( to top, #ffffff, rgba( 255, 255, 255, 0.7 ) );
     height: 90px;
     top: 10px;
   }
}

To break this down, the :before sets the first of two background gradients. This gradient is linear and flows from purple on the left to blue on the right. It is positioned at the top of the container, because we set position: absolute on both, and is 100px in height (you could easily change this to em or whichever unit you are using in your project).

The :after sets the second background gradient. This gradient is also linear but flows from a solid white at the bottom to a white with an opacity of 0.7, using the rgba() colour function, to the top. Which, when overlaid over the top of the colour gradient set on the :before, creates the fade out affect.

The final effect to achieve here is to create the border with the same gradient. To do that, all that is needed is to move the start position of the white gradient so that instead of starting at 0 it starts lower and displays some of the original solid gradient. In this example, the border needed to be 10px so I added:

top: 10px;
height: 90px;

The top value is then subtracted from the value of the height so that both :before and :after effects finish in the some position and preserve the smoothness of the fade out. If you only needed a the border to be 5px, then it would look like:

top: 5px;
height: 95px;

The full CSS Looks like:

.container {
  display: block;
  width: 100vw;
  height: 100vh;

  &::before,
  &::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
  }

  &::before {
    background-image: linear-gradient( to right, #6a26b5, #007bc2 );
    height: 100px;
    top: 0;
  }

  &::after {
    background-image: linear-gradient( to top, #ffffff, rgba( 255, 255, 255, 0.7 ) );
    height: 90px;
    top: 10px;
  }
}

Here it is in action:

Using linear-gradient meant that although three effects were required, only two needed to be created. This gave a really small performance win because we’ve skipped a third effect that would have needed to be painted, and it is well supported by modern browsers as well. Only a few of the more advanced features are not fully supported by Microsoft IE & Edge. Check out the browser compatibility section on MDN for more advanced details.