Learn HTML · Lesson 6 of 8 · about 15 minutes
One header and footer for every page
In lesson 4 you copied the menu into every page. In this lesson you'll write it once, in a file of its own, and have it appear on every page. Change it there, and every page changes.
Includes: one line instead of a copy
HTML itself has no way to put one file inside another. Web servers do, and have since the 1990s: it's called Server Side Includes, or SSI. You write a line like this where the menu should go:
<!--#include virtual="/includes/menu.html" -->
When someone visits the page, the web server swaps that line for the contents of
includes/menu.html before sending the page. The visitor gets one complete page, the same as if
you'd copied the menu in by hand. So do search engines and screen readers.
The line is written like an HTML comment, <!-- -->, on purpose: anything that doesn't
understand includes just ignores it. That includes your browser when you open the file from your computer, which
is why you'll need a web server to see includes work. More on that below.
Put the shared parts in their own files
In your my-site folder, make a folder called includes, and in it a file called
menu.html with just the menu, nothing else: no <!DOCTYPE>, no
<head>, no <body>.
<nav>
<a href="/index.html">Home</a>
<a href="/recipes.html">Recipes</a>
</nav>
Do the same for a footer, in includes/footer.html:
<footer>
<p>Baked and written by Sam Rivera ·
<a href="mailto:sam@example.com">sam@example.com</a></p>
</footer>
Your site now looks like this:
my-site/
index.html
recipes.html
style.css
images/
bread.jpg
includes/
menu.html
footer.html
recipes/
sourdough.html
Why the menu's links start with /
The menu used to say href="recipes.html". That's relative to the page it's on, and the same menu is
now on pages in different folders. On recipes/sourdough.html, recipes.html would
mean recipes/recipes.html, which doesn't exist.
A leading / means "start from the top of the website", so /recipes.html is the same
file from any page, in any folder. Lesson 4 said to avoid these, because they don't work when you open files
from your computer. Includes need a web server anyway, and on a web server, addresses starting with
/ work perfectly. So from now on, use them in anything shared: the menu, the footer, and the
stylesheet link (href="/style.css").
The include line itself uses virtual="/includes/menu.html" for the same reason: it's the same line on
every page, wherever the page is.
Use them in every page
Now replace the <nav> in each page with the include line, and add the footer's at the end.
recipes.html becomes:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Recipes · Sam Rivera</title>
<link rel="stylesheet" href="/style.css">
</head>
<body>
<!--#include virtual="/includes/menu.html" -->
<h1>Recipes</h1>
<p>The things I bake most, written down so I stop forgetting them.</p>
<ul>
<li><a href="recipes/sourdough.html">Sourdough bread</a></li>
<li>Cinnamon buns</li>
</ul>
<!--#include virtual="/includes/footer.html" -->
</body>
</html>
Do the same in index.html and recipes/sourdough.html: exactly the same two lines, even
in the page inside the recipes folder. While you're there, change each page's stylesheet link to
/style.css, so every page can use the same one.
Links that aren't in shared files, like the one to recipes/sourdough.html above, can stay as they
are. Either kind works on a web server.
See it working
Open a page straight from your folder and the menu and footer are missing: your browser read the include lines as comments. To see the finished pages, the files need to come from a web server that does includes. Two ways:
- Put it online with Pagehaus. Create a free site, then drag your
my-sitefolder's contents onto its Files tab. Every Pagehaus site processes includes in.htmlfiles, on every plan, Free included. You can also edit your files there: the editor's preview shows each page with its includes filled in. Lesson 8 covers putting your site online in full; doing it now doesn't hurt. - On your own computer, with
pagehaus serve. It's a small, free tool that runs a web server for your folder, with includes (how to install it). Open a terminal in yourmy-sitefolder, runpagehaus serve, and go tohttp://localhost:8080in your browser. It reloads the page by itself when you save a file.
Includes are an old, widely supported feature of web servers, but not every host turns them on.
Apache-based hosts often do (sometimes only for files ending in .shtml); GitHub Pages, Netlify and
most "static" hosts don't.
Going further: the head too
The top of every page, from <!DOCTYPE html> to the menu, is the same too, except for the title.
You can include all of it, and still give each page its own title, by setting a variable first.
Here's includes/head.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title><!--#echo var="title" --> · Sam Rivera</title>
<link rel="stylesheet" href="/style.css">
</head>
<body>
<nav>
<a href="/index.html">Home</a>
<a href="/recipes.html">Recipes</a>
</nav>
<!--#echo var="title" --> is replaced by the value of title. Each page sets it,
then includes the file. A whole page is now just its own content:
<!--#set var="title" value="Recipes" -->
<!--#include virtual="/includes/head.html" -->
<h1>Recipes</h1>
<p>The things I bake most, written down so I stop forgetting them.</p>
<!--#include virtual="/includes/footer.html" -->
The footer file would then end with </body> and </html>, to close what
the head file opened. It's optional, and a matter of taste: some people like seeing a full page in every file.
But it means a new line in the <head> (a font, a favicon) is added in one place.
A year that updates itself
Includes can do a little more than include. This footer line always shows the current year, so you never have to update it in January:
<!--#config timefmt="%Y" -->
<p>© <!--#echo var="DATE_LOCAL" --> Sam Rivera</p>
More of these, like "last updated" dates, are in the Server Side Includes reference.
If it doesn't work
- The menu doesn't appear, and there's no error: the page isn't coming from a web server that
does includes. Check the address bar: if it starts with
file://, see "See it working" above. - "[an error occurred while processing this directive]": the include file wasn't found. Check
the path after
virtual=, letter by letter, starting from the top of your site. - The include line is ignored even online: it must be written exactly:
<!--#includewith no space after<!--, and a space before the closing-->. The page must end in.html,.htmor.shtml. - The menu works on some pages and not others: a menu link without the leading
/, or a page with an old copy of the menu still in it. - The page has no styles in a folder: its stylesheet link still says
style.cssinstead of/style.css.
Check your work
- Your menu and footer are each in a file of their own, in an
includesfolder. - Every page includes them, with the same lines, and has no copy of the menu left in it.
- The links in the shared files, and the stylesheet links, start with
/. - Seen through a web server (Pagehaus or
pagehaus serve), every page shows the menu and footer, and the menu works from the page inside therecipesfolder. - Add a third link to
menu.html. It appears on every page at once.
Next, you'll add a contact form, so visitors can write to you without leaving your site.