Overlapping CSS Grid Items for the an easy off-canvas sidebar.
CSS Grid is approaching pretty good availability (almost 90% on caniuse.com), and yet I haven’t seen that much use in the wild. That, and it appears there aren’t a whole lot of write-ups on some common use cases and how CSS Grid can help with those.
Recently I wanted to build an “off canvas” sidebar that appears, or slides into view, when you click on a menu button, both on desktop and on mobile. I found a few relevant articles.
- https://webdesign.tutsplus.com/tutorials/how-to-build-an-off-canvas-navigation-with-css-grid--cms-28191
- https://medium.com/@vdsabev/simplify-your-layout-with-this-one-weird-trick-hint-its-css-grid-b9a2971a5649
The first article, despite it’s name, doesn’t actually use CSS Grid for the off-canvas sidebar. You can quickly see the Grid in devtools by selecting the element.
The issue with the above is you’re still setting the sidebar explicitly, with position: fixed (or absolute), its height, and so on, which comes with all the difficulties of management that those have. For example, if you wanted it below the header and your header changes size… or for responsive you need to have queries that apply to that item specifically.
The second article did use CSS Grid for the sidebar, but simply swapped the sidebars grid positions on the responsive version to the content area, and then slides in and out within that grid item.
In my version, the sidebar stays in the sidebar grid area. The content however will span both the sidebar grid area and the content grid area. It’s a little bit the reverse of the above.
The big advantages for me, and this is more profound in React/Vue, is I am now defining the size of my template items in one location, grid-template-rows and grid-template-columns.
Also here I purposefully made the sidebar very large, to demonstrate now that you also don’t need any media queries to manage the size of the sidebar on mobile. Just using minmax(auto, 500px) will ensure the sidebar doesn’t go off screen.
Simple! (I hope!) :)