The same header and footer on every page, without JavaScript
A hand-made site with five pages has five copies of its menu. Add a page and you edit all five. HTML has no built-in way to include one file in another, but web servers do, and have for decades: Server Side Includes.
The usual workarounds, and their catches
- JavaScript (
fetch()or a script that writes the menu): the menu appears a moment after the page, jumps the layout, and isn't in the page that search engines and screen readers get first. - An iframe: links open inside the frame, and the frame doesn't size itself to the menu.
- A static site generator (Eleventy, Hugo, Jekyll): works well, but adds a build step, a command line, and a second copy of your site to keep in sync.
Server Side Includes: one line per page
Put the shared part in its own file, say includes/header.html:
<header>
<a href="/">Rose Bakery</a>
<nav>
<a href="/menu.html">Menu</a>
<a href="/about.html">About</a>
<a href="/contact.html">Contact</a>
</nav>
</header>
Then, in every page, where the header goes:
<body>
<!--#include virtual="/includes/header.html" -->
<main>
<h1>About us</h1>
…
</main>
<!--#include virtual="/includes/footer.html" -->
</body>
The server swaps each include line for the file's contents before sending the page, so visitors and search
engines get one complete HTML page. Change header.html once and every page has the new menu.
A different title on each page
If the header file holds the whole <head>, set a variable before including it:
<!--#set var="title" value="About us" -->
<!--#include virtual="/includes/head.html" -->
<!-- in includes/head.html -->
<title><!--#echo var="title" --> · Rose Bakery</title>
Highlight the current page in the menu
Set a variable with the page's name, put it on the <body> as a class, and let CSS do the
rest:
<!--#set var="page" value="about" -->
<!--#include virtual="/includes/head.html" -->
<!-- in includes/head.html -->
<body class="<!--#echo var="page" -->">
/* in your stylesheet */
.about .nav-about, .menu .nav-menu { font-weight: bold; }
Where it works
Includes are processed by the web server, so opening the file straight from your computer shows the include line as an invisible comment instead of the menu. They need a host that supports SSI:
- Pagehaus turns them on for every
.html,.htmand.shtmlfile, on every plan. Nothing to configure. - Apache hosting (most shared hosts) supports SSI, but often only for
.shtmlfiles unless you enable it in.htaccess. - GitHub Pages, Netlify and most static hosts don't process SSI; there you'd use a generator instead.
To preview includes on your own computer, any local server with SSI support works, or edit on Pagehaus directly: the editor's preview shows the page with its includes.
More: dates, file sizes and the other directives are in Server Side Includes.