Skip to main content

9. Menus & Media

The navigation menu is the primary means by which users find content and explore your website. How often have you visited a website and couldn't find what you were looking for? This is an unnecessary frustration that can be avoided by designing navigation menus with the user in mind.

Placement and Consistency

Users expect your navigation menu to be toward the top of the page, such as the top of the sidebar, across the top of the page, or both.

The most common practice is to place a horizontal menu toward the top of the page. And often websites will have a primary menu across the top and additional navigation links in the sidebar and footer.

The menu should be as high on the page as possible. You do not want your menu to extend "below the fold" so to speak. In other words, users should not have to scroll down to find your menu links.

The placement, functionality, and design of your menu should also be consistent on all pages. Your website visitors should not be required to figure out how to navigate on each new page they visit.

And you should never have a page on your website without any navigation links. Never leave your users stranded.

Your goal is to make the user experience as simple as possible without any unnecessary frustrations.

The text for your menu links should be clear, descriptive, and brief. Commonly used menu labels are "about us," "contact us," and "home." You should use labels that are similar to those used on popular websites. Users already know what these mean and expect to see the menu links labeled as such. Using commonly-used techniques gives your users a sense of familiarity with your website, even if they have never previously visited your site.

The color of the text should have enough contrast from the background color so the text may be easily read. In fact, this is true for all text on your web pages. You should test your text and background colors using this tool.

Usability Is Priority One

Your website navigation should be simple, consistent, and easy to use. Even if you think something looks better or is "cool," if it compromises usability, you should not use it. A menu with spinning animated monkeys may be fun, but it's probably not appropriate for most websites :)

As we've mentioned, part of usability is about giving users what they expect. For example, your logo and site title should link to the home page of your website. Users come to expect that they will always have this option for returning to the home page.

It's a good idea to have a neutral party take a look at your website while you observe their behavior. Get their feedback about how easy or difficult it was to find the information they needed. A simple exercise like this can uncover usability issues that you would never have discovered on your own.

Creating Menus with HTML & CSS

Menus are almost always created using the <ul> element. Using unordered list items provides semantic meaning (that all of these items are related). It also just makes sense because it allows you to easily manipulate and style a group of like items in a similar fashion.

The HTML code below shows a typical navigation menu. Notice that we have used the <nav> element. This is a semantic element made available in HTML5. "Nav" is short for "navigation".

<nav class="primary-menu">
<ul>
<li><a href="index.html">Home</a></li>
<li><a href="about.html">About</a></li>
<li><a href="contact.html">Contact</a></li>
<li><a href="resources.html">Resources</a></li>
</ul>
</nav>

Output:

We're going to use this code to create a horizontal menu that would likely be placed at the top of a web page.

Let's remove the underline for the links, change the font and make it white and bold, and give it a background-color so the text stands out.

.primary-menu a {
text-decoration: none;
font-family: Arial, "Helvetica Neue", Helvetica, sans-serif;
color: #fff;
font-weight: bold;
background-color: #434343;
}
note

For the font-family, I've used what is called a "font stack."

Output:

To add a sense of interactivity, we're going to have the background-color change slightly on mouse hover:

.primary-menu a:hover {
background-color: #555;
}

Output (Hover over the links):

This is a slight color change. But it's more noticeable when the menu buttons are larger.

I don't want any bullets for this, so let's remove those using list-style-type. I'm also going to zero the default padding and margin:

.primary-menu ul {
list-style-type: none;
padding: 0;
margin: 0;
}

Output:

Since li elements are block-level elements, they stack on top of each other by default. In order for them to line up side by side, we have a few options.

One option is make them inline elements with the display property:

.primary-menu li {
display: inline;
}

Output:

The float property is another option that has traditionally been used for this.

BUT modern CSS offers us flexbox, which will give us more options for arranging these list items in the manner we prefer. I'm going to choose this option.

So instead, I will make the ul element a flex container:

.primary-menu ul {
display: flex;
list-style-type: none;
padding: 0;
margin: 0;
}

The <li> elements are immediate children of the ul:

<nav class="primary-menu">
<ul>
<li><a href="index.html">Home</a></li>
<li><a href="about.html">About</a></li>
<li><a href="contact.html">Contact</a></li>
<li><a href="resources.html">Resources</a></li>
</ul>
</nav>

So, these list item elements are the flex items.

Output:

By default, <a> elements are inline elements. You can't add padding to the top or bottom of inline elements. And I want to add padding to each side of the element so the clickable area will be larger. Traditionally, we would use display: inline-block for the <a> elements. This would allow us to keep the element inline, while also allowing us to add padding to each side of the element.

It's still fine to use that. But with flexbox, we can also use display: block. Flexbox is controlling the placement of the elements. By default, elements will be in a row across, regardless of their display type.

.primary-menu a {
display: block;
padding: 0.8em 1.2em;
text-decoration: none;
font-family: Arial, "Helvetica Neue", Helvetica, sans-serif;
color: #fff;
font-weight: bold;
background-color: #434343;
}

Output:

If we want this to appear as a bar that will extend all of the way across, we can add a background-color to the ul.

Full Menu Code:

.primary-menu ul {
display: flex;
list-style-type: none;
padding: 0;
margin: 0;
background-color: #434343;
}

.primary-menu a {
display: block;
padding: 0.8em 1.2em;
text-decoration: none;
font-family: Arial, "Helvetica Neue", Helvetica, sans-serif;
color: #fff;
font-weight: bold;
background-color: #434343;
}

.primary-menu a:hover {
background-color: #555;
}

Output:

Instead of creating a navigation bar like this, you could also create individual menu buttons with space between them, like in my practice 9 example.

And note that if you have a lot of menu links and/or the menu text labels are longer, this might not work great on mobile devices.

One option is to remove display: flex from your default styling for the ul element and instead only use flexbox for large displays, such as:

/* styling for tablets/desktop computers */
@media (min-width: 768px) {
.navigation ul {
display: flex;
}
}

That way, the block-level <a> elements will stack on top of each other on mobile devices and they will only be side-by-side on large displays.

If you have a page with a lot of content, you might want to use intra-page links. This allows users to jump down to specific sections in the page. We discussed this briefly way back in lesson 3.

<h2 id="baked-potato">Baked Potatoes</h2>
<p>Baked potatoes are made from potatoes. These potatoes are baked.</p>

<h2 id="pickles">Pickles</h2>
<p>A lot of people don't realize that pickles used to be cucumbers. Or are they still cucumbers?</p>

You want to add some links above the article that will allow people to jump down to the different sections in the article. This can be accomplished by referencing the element's ID using the hash symbol:

<a href="#baked-potato">Baked Potato</a>
<a href="#pickles">Pickles</a>

And you would probably want to put all of them together in an unordered list:

<ul>
<li><a href="#baked-potato">Baked Potato</a></li>
<li><a href="#pickles">Pickles</a></li>
</ul>

You can also create links from one page to a section in another page. For example, if the #baked-potato section was in a page named food.html, this would be the relative URL:

<a href="food.html#baked-potato">Go to the "baked potato" section on the "food" page</a>

If the website was foodexamples.com, the absolute URL would be:

<a href="https://foodexamples.com/food.html#baked-potato">Go to the "baked potato" section on the "food" page</a>

You can also create links that allow users to jump back up to the top of the page. You could create a link to an element with an ID at the top of the page. Or you can just use this and it will take you to the top of the page:

<a href="#">Back to Top</a>

You can see an example of using intra-page links in my practice 9 example.

Video

In order to play a video in a particular format, such as the antiquated RealMedia or Windows Media format, the user must have that video player installed on their computer.

It was common in years past for web designers to embed RealMedia and other video formats that required specific video players in order to play them. However, this is no longer a reasonable option.

Flash

Adobe once claimed that Flash was installed on more than a billion computers. Flash was the primary method for presenting videos for many years. It served its purpose.

You could create applications, entire websites, and play audio and video using Flash. It was very powerful and versatile.

But it also required installing the Flash plugin, often used too much memory, was often unstable, and had some serious security flaws.

And now Flash is dead.

The move away from Flash had been going on for years. Apple issued a large blow to Flash when it decided to drop Flash support on iPads and other devices.

And when Adobe announced in 2017 that Flash support would end in 2020, it sounded the death knell.

HTML5 and the <video> element has replaced Flash as the primary means of delivering video.

HTML5 Video

HTML5 video eliminates the need for users to download, install, and update plugins. It is definitely a great move in the right direction. But this transition has not been easy or fast.

  • It took a while before browsers fully supported HTML5 video.
  • Coming up with a good DRM solution was holding back HTML5 and kept Flash lingering for longer than expected.
  • There was no universal video format standard for HTML5, although MP4 would eventually emerge as the standard.
  • MP4 relies on the H.264 codec, which is patented. This may require certain application developers to pay royalties. But this issue was tempered just a little bit when Cisco announced that their H.264 codec would be made open source and then Mozilla announced that they would add HTML5 MP4 support to Firefox.
  • Browser developers and other stakeholders have been at odds with each other over issues such as H.264 and DRM.

The video formats:

  • MP4 - H.264 proprietary codec also used by Blu-ray Disc.
  • OGG - Theora format without any licensing issues (.ogv file extension).
  • WebM - Developed by Google, also without licensing issues.

Google developed the royalty-free WebM standard and wanted this to be the HTML5 standard. Opera and Mozilla were on board with this. However, Apple and Microsoft stood in opposition and instead supported H.264/MP4.

Mozilla and Google were taking a stand to promote open standards. But they lost the battle. Apple and Microsoft moved forward with H.264/MP4 and this has emerged as the standard.

Google once planned to drop H.264 support from Chrome, but later backed off. Mozilla conceded as well. Today, all of the major browsers support MP4 for HTML5 video.

Embedding HTML5 Video

While we were waiting for support in all browsers, there was a period of transition where we had to create different versions of the video to support each browser. And we would use a mess of code like this:

<video width="320" height="214" controls poster="media/toad-poster.png">

<source src="media/toadpetting.ogv" type='video/ogg; codecs="theora,vorbis"'>

<source src="media/toadpetting.mp4" type='video/mp4; codecs="avc1.42E01E, mp4a.40"'>

<!--Flash fallback for older browsers-->
<object id="flowplayer" width="320" height="214" data="media/flowplayer/flowplayer-3.2.16.swf" type="application/x-shockwave-flash">

<param name="movie" value="media/flowplayer/flowplayer-3.2.16.swf">

<param name="flashvars" value="config={'clip':{'url':'media/toadpetting.mp4','autoPlay':false}}">

</object>

</video>

The browser would locate the first file that it supported and play that. So, if you were using IE 9+, the code above would provide you with the MP4 video. If you were using an older version of Firefox or Chrome, it would play the OGG file. And if you were using a version of Internet Explorer prior to version 9, you would see the MP4 played through a Flash player.

But, in modern days, we can do this with much less code:

<video width="320" height="214" controls poster="media/toad-poster.png">

<source src="media/toadpetting.ogv" type="video/ogg">

<source src="media/toadpetting.mp4" type="video/mp4">

</video>

The value for src is a relative URL. These URLs indicate that the video files are within a folder named "media".

And if you wanted to support the open standards cause and add in a WebM version, you could include this as well:

<video width="320" height="214" controls poster="media/toad-poster.png">

<source src="media/toadpetting.webm" type="video/webm">

<source src="media/toadpetting.ogv" type="video/ogg">

<source src="media/toadpetting.mp4" type="video/mp4">

</video>
note

In order to convert video files from one format to another, you would need a video transcoder program.

OUTPUT:

NOTE: The video has no sound.

Video Player Software

You can also use video services like JW Player to embed your videos.

These services provide the embed code for you and make sure that the video will display on multiple browsers and devices. And it is likely that the developers will always be on top of the latest technologies and techniques and implement these into their products.

Video Hosting Sites

With all of that said, it is often easier to use a video hosting website like YouTube, Vimeo, or the many others that are out there. As you are probably well aware of, these sites offer embed code that you can copy and paste into your web pages. YouTube even offers an API that allows you to create custom players and other fun options. This requires a bit of programming, but it can offer you more control and make your videos appear more professional.

Responsive Videos

To make HTML5 video embeds responsive, you can simply use the same CSS code that you use to make img elements flexible:

img, video {
max-width: 100%;
height: auto;
}

However, that will not work for YouTube videos and others that use the iframe element.

One solution is to add a class attribute to the iframe element, such as:

<iframe 
class="iframe-video"
src="https://www.youtube-nocookie.com/embed/Iw1DF7rQuDs"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowfullscreen>
</iframe>

And make sure to remove the width and height attributes from the YouTube embed code.

And use the aspect-ratio and width properties in your CSS:

.iframe-video {
aspect-ratio: 16 / 9;
width: 100%;
}

Audio

Embedding MP3, WAV, or other audio formats once brought up the same issues as video. These same RealMedia and Windows Media players were once used to play audio. But those players are now relics of the past.

The above-mentioned JW Player can also be used to play audio. Or you can embed it yourself using HTML5.

HTML5 Audio

It's the same idea when embedding HTML5 audio. You might want to create an OGG audio file (sometimes with .oga extension) for older versions of Firefox and Opera that do not support MP3. You will also need an MP3 file.

<audio controls>
<source src="path/to/cash.mp3">
<source src="path/to/cash.ogg">
</audio>

Or if it works for your situation, why not simplify this and use an audio hosting service like SoundCloud?

Documents

In most situations, it is best to markup documents as HTML rather than using PDF, Word, or other proprietary formats. When using these files, it requires that the user has one of those particular programs installed on their computer. And starting up one of these programs is usually much slower than loading a simple HTML page.

However, there are some occasions when you may want to use PDF, Microsoft Office, or other types of documents. The simplest option is to create a link to the document:

<a href="documents/my_paper.pdf">Read my paper</a>

Or you can host your documents on an external service like Google Docs and use the code they provide for embedding the document in your web page.

It makes sense to make it as easy as possible for all users. You should make sure that no user will be required to install plugins or other software to view your content.

CSS for Printing

Even in this modern paperless age, people still may want to print your web page.

Maybe you want to print a recipe to send to grandma. Or maybe you want a printed copy of a concert ticket, a receipt, or the text of an article from a web page.

We can create CSS specifically for printing to make this experience better for users.

Location of Print CSS code

Your CSS for printing can be inside your regular stylesheet or in a separate CSS file.

@media print within existing stylesheet

One option is to use the @media print directive in the CSS file for your website:

@media print {

.something {
color: black;
}

.something-else {
display: none;
}

} /* ending print curly bracket */

Notice that we are nesting curly brackets inside of curly brackets, just like we do when creating a media query for responsive design.

When a page is printed, the browser will use the CSS inside these curly brackets to style the print output.

Separate CSS file for print

Another option is to create a separate file for your print CSS and add a stylesheet link within the head of your page(s). In this example, the URL indicates that I have a folder named "css" with a file inside named print.css:

<link rel="stylesheet" media="print" href="css/print.css">

There are advantages and disadvantages to both of these approaches. For our practice exercise, we will create a separate print CSS file.

Screen and print styling: Work together or apart?

If your stylesheet links look like the example below, all of the styling from style.css will apply to the printed page and the styling in print.css will be used in addition to that.

<link rel="stylesheet" href="css/style.css">
<link rel="stylesheet" media="print" href="css/print.css">

The 2 stylesheets will be combined. And "the Cascade" (i.e., precedence and specificity) will decide which styling will apply to which elements in the print output.

If you used this approach, your print CSS would need to override any styling from style.css that would not be appropriate for a printed page. For example, you would need to remove any unnecessary design elements that would waste ink and paper when printing. Accomplishing this can sometimes require a strong understanding of CSS specificity and precedence.

note

However, note that modern browsers will often ignore most styling in your CSS that would be inappropriate for a printed page. Only some of the styling from your CSS may be applied to the print styling.

Instead, if you use the following approach, the code in style.css will be ignored when the page is printed. Only the CSS in print.css (and the browser's default styling) will be used to style the print output:

<link rel="stylesheet" media="screen" href="css/style.css">
<link rel="stylesheet" media="print" href="css/print.css">

Using media="screen" specifies that the style.css file should only be used for the web page on the screen. And print.css will control styling for the printed page. This is probably the best approach. It makes it easier to create a "clean" print output without a lot of unnecessary styling.

Save ink and paper for users

Paper isn't cheap. And the price of printer ink is absolutely ridiculous. Printer ink is one of the most expensive liquids that we purchase. It costs WAY more per gallon than gasoline, beer, and many fine wines and perfumes :)

Help your users out and avoid styling that will unnecessarily use their ink and paper.

  • Don't use unnecessary backgrounds and other decorative items.
  • If something is purely decorative, it's probably best to avoid using it. People probably don't want to print all of your fancy and colorful design stuff. They probably just want the content from the page.
  • Avoid leaving large amounts of empty space. Don't use large values for padding and margin or unnecessarily restrict the width of elements containing text. Allow the content to fill the horizontal space across the paper. This can save paper for users.
  • Remove unnecessary content (More on this further along in this lesson).

Think physical, not digital

When providing styling for content on a piece of paper, we are moving from the digital world to the physical world.

Physical units of measure

CSS has several physical units of measure, such as inches (in) and centimeters (cm). It doesn't make sense to use these units for web pages, but it is perfectly fine for print styling.

And it is fine to use points (pt), which is a unit of measure that is commonly used for font sizes in the physical world. 1 point is equal to 1/72 inches.

Accessibility in the physical world

You should think about how well certain content will translate to a physical medium. For example, you can click this link and access another web page. But if you were reading this on a piece of paper, you wouldn't know what web page that link is pointing to.

In our print CSS, we can instruct the browser to print the URL so it is accessible:

a::after {
content: " (" attr(href) ")";
}

This will select all <a> elements and insert the value for its href attribute within parentheses.

... click this link (https://www.youtube.com/watch?v=1nF9rhCbEpQ) ...

That will work fine for absolute URLs. But what about for relative URLs like this?

<a href="about.html">About this website</a>

This is fine. But it doesn't provide the entire URL to the web page:

... About this website (about.html) ...

If you want to get super fancy, you could use the not() pseudo-class selector and an attribute selector:

a:not([href^="http"])::after {
content: " (https://40px.org/" attr(href) ")";
}

This will select <a> elements, but not those where the href value begins with "http", and insert the full absolute URL within parentheses. And this is the result:

... About this website (https://40px.org/about.html) ...

The person printing the page might want the URL to a video that is embedded in the page.

To accomplish this, we could enclose our iframe element within a div and add a data attribute that provides the URL to the video:

<div class="media" data-url="https://www.youtube.com/watch?v=1nF9rhCbEpQ">
<iframe width="420" height="315" src="https://www.youtube.com/embed/1nF9rhCbEpQ" allowfullscreen></iframe>
</div>

I have added an attribute named data-url that provides the URL to the video on YouTube's website.

Optionally, you could choose to remove the video from the print output. I've chosen to do this.

The following CSS will remove the iframe element and print the URL provided by the data-url attribute:

.media iframe {
display: none;
}

.media::after {
content: " [Media URL: " attr(data-url) "]";
}

And this is the result in the print output:

[Media URL: https://www.youtube.com/watch?v=1nF9rhCbEpQ]

Hide unnecessary content

You could use display: none in your print CSS to hide elements that you determine are unnecessary in the print output.

You would probably want to retain images that are in the main content of the page. It is likely that those images are an important part of the content and are helping to convey meaning. However, images in the banner, sidebar, and footer may be deemed superfluous. We could choose to remove img elements in certain portions of the page.

And we could create a class and add it to certain elements that we want to exclude from the print output. In my example, I have created a class named "no-print" for this purpose.

We can create a group selector in the print CSS to hide all of these elements that we deem unnecessary:

a[href^="#"], nav, .no-print, .sidebar img, .banner img, .site-footer img {
display: none;
}
note

This will hide all intra-page links, nav elements, elements with a class named "no-print", and img elements within elements with classes named "sidebar", "banner", and "site-footer".

Finishing touches

As we have said, if we use media="screen" for our primary stylesheet link and media="print" for our print stylesheet link, the primary CSS file for our website will be ignored when printing and our print.css file will take control. There is also a minimal amount of default styling that will be applied by the browser.

The browser's default CSS will add margin to create space between paragraphs and headings, along with some other very basic styling. We might want to add some of our own basic styling to improve the readability of the output.

For example, the default browser styling does not add borders to tables and their td and th elements. Borders can help make it easier to read and understand the data being presented in the table.

table, td, th {
border-collapse: collapse;
border: 1px solid #555;
}

We also might want to separate sections in the content with borders. For example, this would add a border at the end of the banner, main, and sidebar content.

.banner, main, .sidebar {
border-bottom: 1px dotted #555;
}

Example Print CSS

note

This is just an example. What is deemed appropriate for your particular website may vary.

body {
font-family: Georgia, "Times New Roman", Times, serif;
}

/* add url after link text */
a::after {
content: " (" attr(href) ")";
}

/* print relative urls as absolute urls */
a:not([href^="http"])::after {
content: " (https://40px.org/" attr(href) ")";
}

/* print source url for media */
.media::after {
content: " [Media URL: " attr(data-url) "]";
}

/* hide intra-page links, iframe embeds, nav elements, elements with 'no-print' class, img elements in sidebar, banner, footer */
a[href^="#"], .media iframe, nav, .no-print, .sidebar img, .banner img, .site-footer img {
display: none;
}

table, td, th {
border-collapse: collapse;
border: 1px solid #555;
}

/* borders to separate sections of content */
.banner, main, .sidebar {
border-bottom: 1px dotted #555;
}

.banner, .site-footer {
text-align: center;
font-style: italic;
}

Testing print output

If you use the media attribute in your stylesheet links to completely separate the screen and print styling, it's pretty easy to test the print CSS. You could just start to print the page and view the "print preview". It will most likely look about the same, regardless of which browser you are using.

If instead, you combine the screen and print styling, you are relying on the browser's interpretation of the "cascade". Most browsers are fairly consistent these days. But there can be some significant differences in how browsers render the page. In that case, you would definitely want to test the print output in all modern browsers. You can also use the "Inspect" tool in your browser. In Chrome, you can right-click on the page, select "Inspect", click the dot-dot-dot menu, then select "more tools" and then "rendering". And under "Emulate CSS media type", select "print" from the dropdown menu.