How to Use CSS Grid for Sticky Headers and Footers
CSS Grid is a collection of properties designed to make layout easier than it’s ever been. Like anything, there’s a bit of a learning curve, but Grid is honestly fun to work with once you get the hang of it. One area where it shines is dealing with headers and footers. With a little adjustment in our thinking, we can pull off headers and footers that behave like they are fixed, or have that “sticky” treatment (not position: sticky , but the kind of footer that hugs the bottom of the screen even if there isn’t enough content to push it there, and is pushed away with more content). Hopefully this sparks further interest in modern layouts, and if it does, I can’t recommend Rachel Andrew’s book The New CSS Layout strongly enough: it covers both of the major modern layout techniques, grid and flexbox.
Let’s implement a fairly classic HTML layout that consist of a header, main content and footer. We’ll make a truly fixed footer, one that stays at the bottom of the viewport where the main content scrolls within itself, as needed, then later update the footer to be a more traditional sticky footer that starts at the bottom of the viewport, even if the main content is small, but gets pushed down as needed. Further, to broaden our exposure to grid, let’s design our main content holder so that it can either span the whole width of the viewport, or take up a nicely centered strip down the middle.
A fixed footer is slightly unusual. Footers are commonly designed to start at the bottom of the viewport, and get pushed down by main content as needed. But a persistent footer isn’t unheard of. Charles Schwab does it on their homepage. Either way, it’ll be fun to implement! But before we move on, feel free to actually peek at the fixed footer implemented on the Charles Schwab site. Unsurprisingly, it uses fixed positioning, which means it has a hard-coded size. In fact, if we crack open DevTools, we see that right off the bat:
Not only that, but there’s the balance of making sure the main content doesn’t get hidden behind that fixed footer, which it does by setting hard-coded paddings (including 15px on the bottom of the
Let’s sketch out a bare minimum UI to get us started, then enhance our grid to match our goals. There’s a CodeSandbox below, plus additional ones for the subsequent steps that get us to the end result. First, let’s do some prep work. We’ll make sure we’re using the whole height of the viewport, so when we add our grid, it’ll be easy to put the footer at the bottom (and keep it there). There’s only going to be one element inside the document’s
with an ID of #app , which will hold the and elements.Next, let’s set up our header, main, and footer sections, as well as the grid they’ll all sit in. To be clear, this will not work the way we want right out of the gate. It’s just to get us started, with a base to build from.
body < margin: 0; >#app < height: 100vh; /* grid container settings */ display: grid; grid-template-columns: 1fr; grid-template-rows: auto 1fr auto; grid-template-areas: 'header' 'main' 'footer'; >#app > header < grid-area: header; >#app > main < grid-area: main; padding: 15px 5px 10px 5px; >#app > footer
We’ve created a simple one-column layout, with a width of 1fr . If that 1fr is new to you, it essentially means “take the remaining space” which, in this case, is the entire width of the grid container, #app . We’ve also defined three rows:
The first and third rows, which will be our header and footer, respectively, are sized with auto, which means they’ll take up as much space as needed. In other words: no need for hard-coded sizes! This is a super important detail and a perfect example of how we benefit from using CSS Grid. The middle row is where we’ll put our content. We’ve assigned it a size of 1fr which, again, just means it takes up all of the remaining space that’s left over from the other two rows. If you’re wondering why we aren’t making it auto as well, it’s because the entire grid spans the viewport’s whole height, so we need one section to grow and fill up any unused space. Note that we do not have, nor will we ever need at any point, any fixed heights, margins, paddings — or even line breaks! — to push things into place. Such is the good life when working with grid !
Shall we try some content?
You’ll notice in the Sandbox that I used React to build this demo, but since this isn’t a post about React, I won’t belabor those details; React has absolutely nothing to do with any of the CSS Grid work in this post. I’m only using it as an easy way to navigate between different chunks of markup. If you hate React, that’s fine: hopefully you can ignore it in this post. We have Header , Main and Footer components that render the expected
Fixed header, fixed footer
When we initially set up our grid, we gave it a height of 100vh, which is the entire height of the viewport. We then assigned the rows for the header and footer an auto height, and the main a height of 1fr to take up the remaining space. Unfortunately, when content exceeds the space available, it expanded beyond the viewport bounds, pushing our footer down and out of view. The fix here is trivial: adding overflow: auto will cause our
Adjustable width main section
We want our
Now let’s position our the content in the grid. Our different modules all render in a
#app > section < grid-area: 1 / 2 / 1 / 3; >#app > section.full < grid-area: 1 / 1 / 1 / 4 >
You might be surprised to see a col-end value of 4 , given that there’s only three columns. This is because the column and row values are column and row grid lines. It takes four grid lines to draw three grid columns. Our will always be in the first row, which is the only row. By default it’ll span column lines 2 through 3 , which is the middle column, unless the section has a full class on it, in which case it’ll span column lines 1 through 4 , which is all three columns. Here’s an updated demo with this code. It’ll probably look good, depending on your CodeSandbox layout, but there’s still a problem. If you shrink the display to smaller than 600px, the content is abruptly truncated. We don’t really want a fixed 600px width in the middle. We want a width of up to 600px. It turns out grid has just the tool for us: the minmax() function. We specify a minimum width and a maximum width, and the grid will compute a value that falls in that range. That’s how we prevent the content from blowing out of the grid. All we need to do is swap out that 600px value with minmax(0, 600px) :
One more approach: The traditional fixed footer
Earlier, we decided to prevent the footer from being pushed off the screen and did that by setting the
…where
…and incorporate
Just two rows, one for the header, and the other for everything else. Now let’s update the grid inside our
We’ve introduced a new auto-sized row. That means we now have a 1fr row for our content, that holds our
Since
We haven’t done anything revolutionary in this post, and certainly nothing that couldn’t be accomplished before CSS Grid. Our fixed width