Pancake stack with fixed header and footer
Tags: webdev, css, frontend, layout
Published: 2021-03-29 11:51:21

Not so long ago on one of my projects my task was to refactor our usual Pancake stack. By this we wanted to achieve better maintainability and also better understanding for newcomers. Here I will demonstrate you the separate stages of the fiddling process and of course the result.

## The task at hand
We had in our code base a usual pancake stack with header, content, footer. Let's describe a bit better all the requirements for this layout:
1. Header and footer should be always visible in viewport. 
1. If we have a lot of content the content area should be scrollable. If we have less content the footer should stay on bottom of the viewport.
1. Header/footer should be extensible without coding or modifying existing code too much.

So here I show you how it was looking like before the refactor => 

{% codepen https://codepen.io/jozsefDevs/pen/PoWGwzj default-tab=css,result %}

Okay so this solution is just working fine. Also if you check it out on a real mobile device the requirements are still fulfilled. However there are some key problems with it
- header and footer height is a fix value (meaning we can't easily extend it)
- main element's padding-top and bottom has to know about the height of header and footer. (so heights are actually duplicated in code)
- In this example I wrote the value with `calc`, so `calc(50px + 10px)` to just highlight that the `10px` on the right is the main element's own padding. In the reality this was added together to 60px. So for someone just coming to this code it's really hard to grasp how this height is combined together.

❌ So it's was a nice start, we covered most of the requirements, but fail to fulfil point 3.

## Can we make this better?

Of course, we can iterate once more on this layout code. So notice this new version is also working properly on real mobile devices and has a few noticeable changes. Here it comes:

{% codepen https://codepen.io/jozsefDevs/pen/GRrjgOv default-tab=css,result %}

I will refer with my points here to the little number emojis I placed in the CSS code example:

1️⃣ We removed every "dependency" from the main section's CSS. So main currently just sets its own padding, which makes it more maintainable in the future. Also it adheres the [Single Responsibility Principle](https://en.wikipedia.org/wiki/Single-responsibility_principle) in its own weird frontend way. 🤯
2️⃣ While header/footer height is still fix we are using CSS variables. (Notice that this might be not the best solution for you, if you want [IE11 support](https://caniuse.com/?search=CSS%20variables) still...) So a baby step into a more dynamic version, where we can easily handle if the header gets bigger. See points below.
3️⃣ We can do this trick because we create a `:before` and `:after` element. Those are having exactly the same height as the header/footer. So this way the content can't go under the real ones because they have their "siblings" underneath.
4️⃣ Here comes the power with CSS variables. Whenever we're adding a new component to the header we just need to change the `--header-height` variables height properly. Try fiddling around and push the `Toggle header!` button I've placed there to see how the layout would adjust in case of a new component added. Of course for this we need a little JS code to place `.big-header` class on the body.

## CSS Grid?
Okay so how I went down this path actually... I tried to refactor the initial version to a working CSS Grid solution! That was my motivation to rewrite this layout code in a large SPA. However there were some unexpected hiccups... I will write about that in a follow up post.

## Summary
Okay that's it! We just made a more reliable Pancake stack layout and also our code became cleaner and more maintainable.

I would honour your feedback about this post in the comments section below. ⬇️⬇️⬇️ Feel free to write in case of any questions. You can also ping me on Twitter: [@jozsefDevs](https://twitter.com/jozsefDevs). Have a wonderful day!