Photograph of a woman's face obscured by a hood

Screenshot of Skullduggery responsive site in portrait aspect ratioAdapting UI elements to changing screen sizes and aspect ratios is one of the greatest challenges of responsive web design: a navigation bar that works when a device is held in landscape mode often fails when the screen is turned 90°.

Responsive UI is easier when the design is simple, so I’ll start with just that: a single-column page for the fictional Skullduggery Incorporated. Skullduggery offers a number of services, which are linked in a navigation bar under a header. The <nav> element has an ARIA role to aid in :

<header>
	<h1>Skullduggery, Inc</h1>
	<h2>Service with a smile and a stab</h2>
</header>
<nav role="navigation">
	<a href="#">Defenestration</a>
	<a href="#">Poisoning</a>
	<a href="#">Garroting</a>
	<a href="#">Duels</a>
</nav>

The page has a single fluid image (provided by Aditya Mopur under a Creative Commons license) and some paragraph text. On large and medium format devices the page will look like the illustration above.

The base CSS for the page is:

* { margin: 0; }
html {
	font-size: 62.5%;
	background:#180303;
	}
body, a {
	font-family: Forum, cursive;
	color: #ecede3;
	text-decoration: none;
}
header {
	padding: 2rem 0;
}
h1 {
	font-size: 5rem;
	text-shadow: 4px 4px 3px rgba(0,0,0,0.3);
}
h2 {
	font-size: 2.5rem;
	font-weight: 100;
	margin-left: 10rem;
}
h1, h2 { 
	text-align: center;
}
a, p {
	font-size: 2rem;
	padding: 2rem;
}
a:hover {
	background: #000;
}
p {
	line-height: 160%;
	margin: 8rem;
}
nav { 
	background: #350c0c;
	padding: 1.2rem 0;
	box-shadow: 0 8px 6px rgba(0,0,0,0.3);
}

Creating A Responsive Design

As the viewport narrows, there is reduced space for the design. In response we will use media queries to reduce font sizes and margins at design breakpoints:

@media screen and (max-width: 800px) {
	p { margin: 4rem; }
}
@media screen and (max-width: 490px) {
	h1 { font-size: 4rem; }
	h2 {
		font-size: 2rem;
		margin-left: 4rem;
		}
	nav, nav a {
		padding: 1rem;
	}
	p { margin: 1rem; }
}

Below 460 pixels wide, the links inside the <nav> element begin to wrap to the left. That can be fine in certain instances, but often makes the navigation look cluttered and disorganized. Let’s clean up the navigation by turning the links into display: block, forcing them onto separate lines:

@media screen and (max-width: 460px) {
	nav { padding: 0; }
	nav a {
		display: block;
		padding: 1.2rem;
	}
}

Screenshot of Skullduggery responsive site in portrait aspect ratioAdding An Adaptive Menu

That looks much better, but you can see a problem in the screenshot to the right: the navigation bar now takes up a lot of vertical space, pushing the page content off the screen. What we really want at small viewport widths is for the navigation bar to be minimized until the user needs it. Here, we’re going to achieve that by adding an element at the start of the navbar with a Unicode symbol that has become the broadly accepted visual shortcut for menu access in responsive sites:

<nav role="navigation">
	<a href="#">&#9776; Menu</a>
	<a href="#">Defenestration</a>
	<a href="#">Poisoning</a>
	<a href="#">Garroting</a>
	<a href="#">Duels</a>
</nav>

We only want the new element to appear at small viewport sizes, so we’ll turn it off in our base CSS:

nav a:first-child {
	display: none;
}

… and turn it back on again when the browser is 460 pixels wide or less:

@media screen and (max-width: 460px) {
	nav a:first-child { display: block; }
…
}

Screenshot of Skullduggery responsive site in portrait aspect ratioThat’s doesn’t quite solve our problem... but the next step does. At 460px we’re going to reduce the height of the menu bar so we can only see the first link, i.e. the one we have just made visible, hiding the other links by using overflow: hidden. Finally, we’ll expand the menu bar to its natural height by responding a hover event on it, using :focus as a backup. The final @media query becomes:

@media screen and (max-width: 460px) {
	nav { 
		padding: 0;
		height: 5rem;
		overflow: hidden;
	}
	nav a {
		display: block;
		padding: 1.2rem;
	}
	nav a:first-child {
		display: block;
	}
	nav:hover, nav:focus {
		height: auto;
	}
}

Animating The Menu bar

We can animate the expansion of the navbar with a silky-smooth CSS transition, with one caveat: browsers do not currently support an element’s transition to its “natural” height. To animate the menu we must set an explicit height for it:

@media screen and (max-width: 460px) {
	nav {
		padding: 0;
		height: 5rem;
		overflow: hidden;
		transition: .7s height ease-in-out;
	}
	nav a {
		display: block;
		padding: 1.2rem;
	}
	nav a:first-child {
		display: block;
	}
	nav:hover, nav:focus {
		height: 23rem;
	}
}

(Remember that you’ll need to add a vendor prefix for the animation to work in some browsers).

The one potential downside to this approach is that the menu bar will remain open after the user touches it: the ability to close it with a touch without going to another page would require us to add some JavaScript.

Conclusion

As you can see, creating a responsive UI element is easy for simple pages; design methodologies change when we get to larger and more complex sites, which we will look at shortly.

Banner image provided by Kristina Ruth

Enjoy this piece? I invite you to follow me at twitter.com/dudleystorey to learn more.
Check out the CodePen demo for this article at https://codepen.io/dudleystorey/pen/sHvza