Full height layouts in WordPress block themes


Sometimes there is not enough content on a page to fill the viewport height. Because of the lack of content, the footer renders in the middle of the viewport leaving a bunch of white space under it. On WordPress sites this often happens on a 404 page, a single post page with little content, or an archive page for a post type that doesn’t have a lot of posts.

In WordPress block themes, the content of site editor templates is wrapped in div.wp-site-blocks. Your templates probably contain at least three divs. A header, a main div for the content of the page, and a footer.

<div class="wp-site-blocks">
  <header class="site-header ...">...</header>
  <main class="wp-block-group ...">...</main>
  <footer class="site-footer ...">...</footer>

We can use flexbox and auto margins to push the footer to the bottom of the viewport even if there is not enough content on the page. First, set div.wp-site-blocks to display flex. Flex defaults to row so we also need to set the flex direction to column so the layout stacks. Next set the minimum height to 100% of the viewport height. I like using svh instead of vh so the footer doesn’t get covered by the mobile browser bar. Finally, set the footer’s margin top to auto.

.wp-site-blocks {
	display: flex;
	flex-direction: column;
	min-height: 100svh;

	.site-footer {
		margin-top: auto;

Because the parent div is a flex column that is 100% of the viewport height, setting the footer’s margin top to auto will use the top margin to push the footer down to the bottom of the viewport.

CSS svh works great for accounting for browser bars, but you might notice unnecessary vertical scrolling when you’re logged in and WordPress’ admin bar is visible. To fix this, subtract the admin bar’s height from the viewport height if it is visible.

.admin-bar .wp-site-blocks {
	min-height: calc(100svh - var(--wp-admin--admin-bar--height));

That’s it! Your footer should now be pushed to the bottom of the viewport when there isn’t enough content.

GitHub Gist with full CSS (PostCSS).