Creating the New Google Play’s Multi-Level Navigation from Scratch

Google have recently released a new Google Play website complete with a new redesign and what caught my attention was the way they implemented their navigation bar. With the smooth animation and how they let users peek at the root-level menu by simply hovering a back button, I decided to build a similar navigation menu from scratch using HTML, CSS and jQuery.

In this demo, I decided to use an awesome icon webfont called Elusive Icons created by a Github user, aristath in place of Google’s own icons, so make sure you’ve included this webfont and a jQuery library before you begin.

Creating the New Google Play’s Multi-Level Navigation from Scratch

Creating A Multi-Level Navigation

HTML

<nav class="navigation">
      <a href="#" class="active home">
        <span class="icon"><i class="icon-home"></i></span> <span class="content">Home</span>
      </a>
      <a href="#app_nav" class="green">
        <span class="icon"><i class="icon-website"></i></span> <span class="content">Apps</span>
      </a>
      <div class="hide second_level" id="app_nav">
        <a href="#" class="back">
          <i class="icon-chevron-left"></i>
        </a>
        <div class="content">
          <a href="http://www.google.com">
           <span class="content">Popular Apps</span>
          </a>
          ….
         </div>
      </div>
      ….
</nav>

 

The HTML part is pretty straightforward. I have a default selected link called “Home” which we will use to return to the root-level of the menu. This link will not trigger anything if the user is already on the root-level of the navigation, that’s why I had the href attribute as “#”. This link is needed for the user to navigate back so do not remove/change this.

The second link and the rest that follow are links that will take the user to the second-level of the menu. The div tag adjacent to the link is a hidden second-level menu that will appear only if the user clicks the second link. Inside this hidden div, you may notice an empty link called “back”. We will use this to allow users to peek at the root-level and let them switch to other parts with only one click.

You can continue to add this set of snippets as long as the structure is the same and that the href points correctly to the id of the hidden div as seen above.

CSS

Since most of the control and animation is being handled on the JS side, the CSS parts are open for you to customize and experiment in anyway you want.

JS

$(window).load(function () {
  $(".navigation > a").click(function() {
    if (!$(this).hasClass("active")) {
      $(".navigation").unbind('mouseleave');
      $(".navigation .second_level").hide();
      var el = $(this);
      el.addClass("hover");
      $(".navigation > a.active").fadeOut("fast", function() {
        var prev = $(this)
        prev.removeClass('active');
        container_pos = $(".navigation").offset()
        button_pos = el.offset()
        el.animate({ top: container_pos.top - button_pos.top }, 500, function() {
          el.addClass("active").removeClass("hover").css("top", 0);
          if (el.attr("href").length > 1 && el.attr("href") != "#") {
            $(".navigation > a:not(.active)").hide();
            $(el.attr("href")).slideDown("slow");
          } else {
            prev.fadeIn("fast");
          }
        });
      });
    }

  });

  $(".navigation .back").hover(
    function () {
      var el = $(this)
      $(".navigation .second_level").hide();
      $(".navigation > a").show();
      $(".navigation").hover(function() {}, function() {
        $(this).unbind('mouseleave');
        $(".navigation > a:visible:not(.active)").hide();
        el.closest(".second_level").show();
      });

    });
});

 

The JS part is a little difficult to understand. Basically what I did was I assigned all links with a click function that, once clicked, will move the link to the top, hide the root-level menu, and slide down the second-level menu.

The second part of the JS is used to assign all the back buttons inside the second-level menu. Once the back button is hovered, the root-level menu should temporarily appear over the displayed second-level menu and when the mouse is no longer hovering, the root-level menu should disappear leaving the second-level menu useable again.

Although this may look easy, it was a little more complex than that. I needed to determine how each link should perform separately because we need to have a “Home” button for the user to go back to. I decided to add a condition to detect if the clicked link is from a “Home” button or not by simply checking the href attribute. If the href is equal to “#”, then perform the back procedure, if not then perform as usual.

With the snippet above we can integrate Animate.css into our JS by simply using the code below instead and change the animation as instructed below:

In the code below you will see 2 sets of animation, <<first-level-animation>> and <<second-level-animation>>. The first one is to animate the first level menu when the user hover the back button. The second one is to animate when the user clicked the first-level menu and the second-level menu appear.

You can try and play around with it by using values listed here and replace the sets with those values. For example, to have a bounceIn effect on all, change all occurrences of <<first-level-animation>> and <<second-level-animation>>in the code below to bounceIn etc.

$(window).load(function () {
        $(".navigation > a").click(function() {
          if (!$(this).hasClass("active")) {
            $(".navigation").unbind('mouseleave');
            $(".navigation .second_level").removeClass("animated <<second-level-animation>>").hide(); 
            var el = $(this);
            el.addClass("hover");
            $(".navigation > a.active").fadeOut("fast", function() {
              var prev = $(this)
              prev.removeClass('active');
              container_pos = $(".navigation").offset()
              button_pos = el.offset()
              el.animate({ top: container_pos.top - button_pos.top }, 500, function() {
                el.addClass("active").removeClass("hover").css("top", 0);
                if (el.attr("href").length > 1 && el.attr("href") != "#") {
                  $(".navigation > a:not(.active)").removeClass("<<first-level-animation>> animated").hide();
                  $(el.attr("href")).addClass("<<second-level-animation>> animated").show();
                } else {
                  prev.addClass("<<first-level-animation>> animated").fadeIn("fast");
                }
              });
            });
          }

        });

        $(".navigation .back").hover(
          function () {
            var el = $(this)
            $(".navigation .second_level").removeClass("animated <<second-level-animation>>").hide();
            $(".navigation > a:not(.active)").addClass("<<first-level-animation>> animated").show()
            $(".navigation").hover(function() {}, function() {
              $(this).unbind('mouseleave');
              $(".navigation > a:visible:not(.active)").hide().removeClass("<<first-level-animation>> animated");
              el.closest(".second_level").addClass("animated <<second-level-animation>>").show();
            });
          });
      });

Conclusion

I hope you enjoy this little experiment. If you have any questions or need any help, feel free to leave a comment below.