Simple horizontal scrolling menu in just CSS

I recently visited a site with a horizontally scrolling sub-menu (pictured below) which I really liked. Because of the stigma of horizontal scrolling on desktop fostered from the non-responsive days, I often immediately dismiss it as bad practice but actually I found this pattern to be very usable on my phone.

Compared to other menus for mobile, this is pretty simple to put together, and doesn't require any tweaks between the desktop and mobile versions. It just works at all resolutions. It's also nice that it's CSS only, meaning no hefty Javascript!

Let's try putting our own version together.

Some HTML

First, let's write some HTML. There's nothing fancy here: a top bar and nav element with some anchor links.

<div class="topBar">
    <!-- Logo etc. -->
</div>

<nav class="navBar">
    <div class="container">
        <ul class="nav">
            <li><a href="#" class="active">Home</a></li>
            <li><a href="#">Blog</a></li>
            <li><a href="#">Products</a></li>
            <li><a href="#">Services</a></li>
            <li><a href="#">Help</a></li>
            <li><a href="#">Contact</a></li>
        </ul>
    </div>
</nav>

A little CSS

.topBar {
    background: #263238;
    color: rgba(255, 255, 255, 0.3);
    font-size: 22px;
    font-weight: bold;
    text-transform: uppercase;
    padding: 20px 0;
    text-align: center;
}

.container {
    margin: 0 auto;
    padding: 0 10px;
    max-width: 800px;
}

.navBar {
    background: #455A64;
}

.nav {
    margin: 0 -10px;
    padding: 0 10px;
    list-style: none;
    display: flex;
    overflow-x: scroll;
    -webkit-overflow-scrolling: touch;
}

.nav > li > a {
    padding: 14px 16px;
    display: block;
    color: rgba(255, 255, 255, 0.8);
    text-decoration: none;
    text-transform: uppercase;
    font-size: 14px;
}

.nav > li > a.active {
    border-bottom: 2px solid #E64A19;
}

The key parts here are:

  • We're using display: flex to keep all of the navigation links on the same row. They don't wrap because by default flex-wrap is set to no-wrap (so we don't have to explicitly set it).
  • We've set overflow-x: scroll on the <nav> element to make the menu horizontally scrollable when it doesn't fit on the screen.
  • The -webkit-overflow-scrolling: touch gives us "momentum" style scrolling on iOS devices (where you can flick your finger and the item scolls past and bounces back again). I like to call it bouncy scrolling.

The Result

This is what we end up with:

Pretty nice, right?