Accelerated mobile pages: build a mobile navigation in AMP HTML

  • -

Accelerated mobile pages: build a mobile navigation in AMP HTML

This tutorial is about how to build a fully functional dropdown navigation menu in compliance with the guidelines for building accelerated mobile pages (AMP).

For those who don’t know about Accelerated Mobile Pages yet, have a look at your Google Webmaster Tools Search Console: Google has added its own section for Accelerated Mobile Pages and is one of several Tech Platforms making use of AMP, such as twitter, Pinterest and LinkedIn, too.

The Accelerated Mobile Pages Project defines AMP HTML as a subset of HTML for authoring content pages such as news or blog entries and is focused on perfomance. Valid AMP HTML pages load up to ten times faster than regular mobile optimized HTML pages but come with some limitations, such as user written JavaScript forbidden! 

Yes, due to performance issues the AMP Project decided in an early stage, that AMP HTML would not include any user written JavaScript nor any third party libraries.

Since JavaScript is not allowed in AMP HTML (and thus all kinds of jQuery or whatever libs you load normally) most AMP HTML content comes without a nice user-friendly mobile navigation with dropdown lists and so on.

How to build a user-friendly mobile navigation without JavaScript or jQuery

Build you naviation tree

You should build your navigation tree for the mobile menu as you are most propably used to with list elements.

<div class="nav">
  <ul>
    <li>
      <a href="/some/link/url/">some link text</a>
    </li>
  </ul>
</div>

Normally you would use some JavaScript (or jQuery) to show and hide elements of the navigation.

Replace JavaScript functionality with CSS

To build a fully functional dropdown mobile menu with first level main navigation menu entries and dropdown sub navigation you have to replace all the JavaScript / jQuery logic you use normally with onclick events, data-toggle and so on with CSS. This could not be true? We’ll show how to do it! It’ very easy if you know what to do, but took us a while to elaborate this very different approach for a fully functional mobile nav.

Dropdown navigation menu lists in CSS

It is assumed that you have a mobile friendly navigation coming with your regular HTML version for mobile devices. Normally this would be some kind of list tree as shown above with some unsorted list <ul> and <li> list elements and maybe even more nested <ul> and <li>.

In our example we will just stick to a simple 2 level menu with main navigation entries containing some sub navigation

<div class="nav">
  <ul class="main-ul">
    <li class="main-li">
      <a href="/some/link/url/">some link text</a>
      <ul class="sub-ul">
        <li><a href="/some/link/url/1.1/">some link text 1.1</a></li>
        <li><a href="/some/link/url/1.2/">some link text 1.2</a></li>
        <li><a href="/some/link/url/1.3/">some link text 1.3</a></li>
      </ul>
    </li>
    <li class="main-li">
      <a href="/some/link/url/2/">some link text 2</a>
      <ul class="sub-ul">
        <li><a href="/some/link/url/2.1/">some link text 2.1</a></li>
        <li><a href="/some/link/url/2.2/">some link text 2.2</a></li>
        <li><a href="/some/link/url/2.3/">some link text 2.3</a></li>
      </ul>
    </li>
    <li class="main-li">
      <a href="/some/link/url/3/">some link text 3</a>
      <ul class="sub-ul">
        <li><a href="/some/link/url/3.1/">some link text 3.1</a></li>
        <li><a href="/some/link/url/3.2/">some link text 3.2</a></li>
        <li><a href="/some/link/url/3.3/">some link text 3.3</a></li>
      </ul>
    </li>
  </ul>
</div>

What we want to achieve is a visible first level navigation like

  • some link text
  • some link text 2
  • some link text 3

unfolding the deeper navigation levels when clicked or getting touched. Since it is hard to do real coding onlywith CSS, we should focus on what is absolutly necessary and what is irrelevant. We want a menu that reveals the sub-entries when we touch it on our smartphone. There are some CSS pseudo classes, that can handle some basic events or states and the most closest to some onclick event would be

  • :target
  • :active
  • :visted
  • :hover

Most useful would be :active and :hover since they could imitate some onclick and mouseover events. In this case something like a mouseover event would be most helpful, since a simulated click event as it could be done with the :active pseudo class would stick to the moment when an element is getting clicked without a state change (more like a onmousedown event in JavaScript or .mousedown() in jQuery)

The element of choice where to bind the :hover CSS pseudo class would be the first level <li> element (here with class “main-li”) of the navigation, since the :hover is still triggered when moving downwards to the nested sub-entries.

First we want to hide all nested sub-entries. In CSS this is done

div.nav ul.sub-ul{
  display:none;
}

Next, when we hover over one of the first level list entries, we want the sub-entries to show up, which is done in CSS by

div.nav ul.main-ul > li:hover > ul.sub-ul {
  display:block;
}

Notice that the :hover pseudo class is bind to the <li> element and then triggers the nested <ul> element of the sub-entries!

This is all the necessary CSS for the sub-entries to show up when hovering over a first level list entry.

Toggle Menu in CSS (Show/Hide)

The same trick could be used to show up the entire navigation when hovering over a “Show Menu” text link in the header or maybe you want to use the well-known hamburger symbol ☰ for the mobile nav.

Just add another few lines to your navigation which is now of the structure

<div class="nav">
  <ul class="main-ul">
    <li class="main-li">
    ...
    </li>
  </ul>
</div>

and add a text link or symbol image and another surrounding div for the naviagation tree

<div class="nav">
  <div class="nav">
    <div class="hamburger">
      <a href="#" class="toggle-button"><!--SHOW MENU--><amp-img src="hamburger.png" width="45px" height="40px" /></a>
    </div>
    <div class="main-navigation">
      <ul  class="main-ul">
        <li class="main-li">

        ...

        </li>
      </ul>
    </div>
  </div>
</div>

Then add the CSS to first hide the entire navigation

div.main-navigation {
  display:none;
}

and then the CSS to show it when hovering over the visible hamburger nav symbol (or your text link…)

div.nav:hover > div.main-navigation {
  display:block;
}

That’s it

Style your navigation list as usual

If you want to add some styling to remove the listing symbols and link decoration and perhaps do some indention and positioning on your own you can do it the same way as your used to with CSS.

Complete listing of dropdown mobile navigation with CSS in AMP HTML

A simple demo of a working mobile navigation for AMP HTML would be

<!doctype html>
<html amp lang="en">
  <head>
    <meta charset="utf-8">
    <title>AMPHTML mobile navigation demo</title>
    <link rel="canonical" href="http://www.da-agency.de/wp/wp-content/uploads/ampdemo/amphtml-mobile-navigation-demo.html" />
    <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
    <script type="application/ld+json">
      {
      "@context": "http://schema.org",
      "@type": "NewsArticle",
      "headline": "AMPHTML mobile navigation demo",
      "datePublished": "2016-03-09T10:00:00Z",
      "image": [
        "logo.jpg"
      ]
      }
    </script>
    <style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style><noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>
    <style amp-custom>
      div.test{
        width:100px;
        height:100px;
        background-color: red;
      }
      div.logo{
        float:left;
        display:block;
      }
      div.toggle{
        float:right;
        display:block;
      }
      div.nav{
        top: 0px;
        width: 100%;
        position: relative;
      }
      div.hamburger{
        text-align: right;
      }
      div.nav, 
      div.main-navigation, 
      div.main-navigation ul, 
      div.main-navigation li, 
      div.main-navigation a {
        text-decoration: none;
        list-style: none outside none;
        display: block;
        line-height: 22px;
        font-size: 15px;
        font-family: Arial,Helvetica;
        color: #777;
      }

      div.nav ul.sub-ul{
        display:none;
      }

      div.nav  ul.main-ul > li:hover > ul.sub-ul {
        display:block;
      }

      div.main-navigation {
        display:none;
      }

      div.nav:hover >  div.main-navigation {
        display:block;
      }
      body{
        background-color: #eee;
      }
      div.page{
        width: 100%;
        height: 100vw;
        max-width: 320px;
        background-color: #fff;
        margin-left: auto;
        margin-right: auto;
        padding: 10px 20px;
      }
    </style>
    <script async src="https://cdn.ampproject.org/v0.js"></script>
  </head>
  <body>
    <div class="page">
      <div class="header">
        <div class="logo">
          <amp-img src="logo.png" width="190px" height="51px" />
        </div>

        <div class="nav">
          <div class="hamburger">
            <a href="#" class="toggle-button"><!--SHOW MENU--><amp-img src="hamburger.png" width="45px" height="40px" /></a>
          </div>
          <div class="main-navigation">
            <ul class="main-ul">
              <li class="main-li">
                <a href="/some/link/url/">some link text</a>
                <ul class="sub-ul">
                  <li><a href="/some/link/url/1.1/">some link text 1.1</a></li>
                  <li><a href="/some/link/url/1.2/">some link text 1.2</a></li>
                  <li><a href="/some/link/url/1.3/">some link text 1.3</a></li>
                </ul>
              </li>
              <li class="main-li">
                <a href="/some/link/url/2/">some link text 2</a>
                <ul class="sub-ul">
                  <li><a href="/some/link/url/2.1/">some link text 2.1</a></li>
                  <li><a href="/some/link/url/2.2/">some link text 2.2</a></li>
                  <li><a href="/some/link/url/2.3/">some link text 2.3</a></li>
                </ul>
              </li>
              <li class="main-li">
                <a href="/some/link/url/3/">some link text 3</a>
                <ul class="sub-ul">
                  <li><a href="/some/link/url/3.1/">some link text 3.1</a></li>
                  <li><a href="/some/link/url/3.2/">some link text 3.2</a></li>
                  <li><a href="/some/link/url/3.3/">some link text 3.3</a></li>
                </ul>
              </li>
            </ul>
          </div>
        </div>
      </div>
      <div class="content">
        <h1>AMPHTML mobile navigation demo</h1>
        <p>See a fully functional dropdown mobile navigation in action, that comes with absolutly no JavaScript / jQuery and is fully built on CSS and 100% AMP HTML compliant and AMP validating</p>
      </div>
    </div>
   </body>
</html>

 

See AMP HTML mobile nav demo in action

Follow this link to see the AMPHTML compliant & validating dropdown mobile navigation menu in action (Click for demo)

 

iPhone and Android

The :hover pseudo class works on both major smartphones as the Apple iPhone and all Android based mobile devices. On the iPhone please make sure, that you always have a real link element inside the element, where the :hover is bind to, even if its Target would be self like

<ul>
  <li>
    <a href="#"><!-- TEXT or IMAGE --></a>
  </li>
</ul>

In this use case you cold bind the :hover pseudo class to the <ul> or <li> element. A HTML nesting like

<ul>
  <li>
    <img src="some-pic.jpg" />
  </li>
</ul>

won’t work on iPhones

Limitations

The usage is of course somehow limited cause you cannot really toggle the menu on and off and on and off and over again… This means you can only dropdown the mobile menu once and then it stays visible. But in most real life use cases this should be sufficient, since you go to navigation menu to switch to another page. As soon as we found a fix for this, we’ll update this blog entry.

Aberrancy: Try to toggle Menu in CSS with :target

Another way in CSS would be the CSS pseudo class :target to activate the mobile navigation. This is done by overwriting the default setting display:none; to hide the element (in this case the entire mobile nav) with a display:block; which makes the element visible

<style amp-custom>
  div#nav-toggle{
    display:none;
  }
  #nav-toggle:target{
    display:block;
  }
</style>
<div class="toggle">
  <a href="#nav-toggle">Show Menu</a>
</div>
<div id="nav-toggle" class="nav">
  <ul>
    <li>
      <a href="/some/link/url/">some link text</a>
    </li>
  </ul>
</div>

Of course you could use an image instead of simple text, e.g.

<div class="toggle">
  <a href="#nav-toggle">
    <amp-img src="hamburger.png">
  </a>
</div>

This works using regular HTML, but when it comes to the AMP HTML subset it just does not do what it’s supposed to: show the menu