Creating a Drop-Down Menu for Mobile Pages

This tutorial will teach you how to create and animate a hamburger menu icon and then attach an event listener through jQuery for triggering a drop-down menu.

Creating a Drop-Down Menu for Mobile Pages

I will be using Jade (Pug) and Sass instead of vanilla HTML and CSS. So you should at least have a basic knowledge of these templating engines.

Creating the Playground

We will start with the implementation of a simple playground. I will only be providing the Jade template along with Sass styling, since this is not the scope of the tutorial. You can take it and use it or you can come up with your own design.

Jade file:

body
    #container
        #header
        #body
            .content
                .left
                .right
                    - for (i=1; i <= 5 ; i++ )
                        div( id="text" + i )
            .content
                .left
                .right
                    - for (j=6; j <= 10 ; j++ )
                        div( id="text" + j )
            .content
                .left
                .right
                    - for (k=11; k <= 15 ; k++ )
                        div( id="text" + k )

Sass file:

=flex()
  display: -webkit-box
  display: -moz-box
  display: -ms-flexbox
  display: -webkit-flex
  display: flex
  
=transition($time)
  -webkit-transition: all $time ease
  -moz-transition: all $time ease
  -ms-transition: all $time ease
  -o-transition: all $time ease
  transition: all $time ease

html, body
  margin: 0
  padding: 20px 0
  +flex()
  justify-content: center

//----------------------------------//

#container
  width: 320px
  height: 550px
  background-color: #ebebeb
  overflow: hidden

#header
  height: 45px
  background-color: #9b9b9b
  position: relative


#body
  padding: 0 20px
  padding-top: 40px
  +flex()

  flex-direction: column
  justify-content: flex-start

.content
  +flex()

  flex-direction: row
  justify-content: flex-start
  margin-bottom: 25px


  .left
    width: 100px
    height: 100px
    margin-right: 15px
    background-color: #e1e1e1

  .right
    @for $i from 1 through 15
      #text#{$i}
        margin-top: 10px
        width: 50 + random(100) + px
        height: 10px
        background-color: #e1e1e1

Note: Here I created two mixins named flex and transition. Mixins make it easier to reuse some CSS rules by grouping them. Whenever I need to add display:flex with all vendor prefixes, I can just use +flex() instead, thanks to the mixin.

We will use this structure and build upon it for the rest of the tutorial.

The final result should look like this:

Creating a Drop-Down Menu for Mobile Pages

View the current code

Hamburger Menu Icon

Now it is time to create a simple yet attractive hamburger menu and animate it through CSS.

Add a new div inside #header and name it #hamburger. Then create two children divs inside #hamburger. They should have a common class and individual IDs.

#hamburger
    .strip#top
    .strip#bottom

Now we need to style the parent #hamburger div and the children divs with the common class of .strip.

#hamburger
  height: 100%
  width: 45
  +flex()

  flex-direction: column
  justify-content: space-between
  padding-left: 20px

We set the height of the div equal to its parent div, which is #header, by defining the height: 100%. Also, we set a width value for this parent div, which will define its “clickable” region.

Next, we add flexbox with all vendor prefixes by using mixins, which we created earlier.

Since we want our .strip divs to be positioned vertically, we set flex-direction: column and then use justify-content: space-between in order to put space in between the .strip divs.

Then we need to push those divs towards each other by adding bottom and top padding to the respective divs.

#top
  margin-top: 17px
  
#bottom
  margin-bottom: 17px

We also added padding-left: 20px in order to move the .strip divs further to the right.

The next thing is to style the strips. This is relatively easy by just defining the size and the color of the divs.

.strip
  width: 25px
  height: 2px
  background-color: #ffffff

The final result with the hamburger menu icon should look like this:

Creating a Drop-Down Menu for Mobile Pages

The next thing is to animate the menu icon so that when it is clicked, it should animate into a cross sign.

Animating the Hamburger Menu Icon

At this point, we are going to use basic jQuery to toggle some CSS classes.

Let’s first create the CSS classes to be toggled.

We are going to utilize the translate and rotate settings of the transform property of CSS along with the transition property.

First, add transitions to both the #top and #bottom divs by using mixins with a specific timing parameter.

#top
  margin-top: 17px
  +transition(.25s)

#bottom
  margin-bottom: 17px
  +transition(.25s)

Now we need to define the styling of the classes to be toggled.

We will be rotating and translating each .strip div individually, so we need to toggle different classes both for the #top and #bottom divs.

#top
  margin-top: 17px
  +transition(.25s)

  &.topRotate
    transform-origin: center
    transform: translateY(4px) rotateZ(45deg)

#bottom
  margin-bottom: 17px
  +transition(.25s)

  &.bottomRotate
    transform-origin: center
    transform: translateY(-5px) rotateZ(-45deg)

Here we defined the styling for two different classes named .bottomRotate and .topRotate, which will be added to and removed from their respective reference divs, #top and #bottom.

Note that different sizing of the .strip class would result in a need for different translateY and rotateZ values in order to animate into a proper cross sign.

Class Toggling With jQuery

We defined how each .strip div will animate when the topRotate and bottomRotate classes are present. However, we have yet to attach an event listener to toggle those classes.

Create a new JavaScript file and use the following code to toggle the topRotate and bottomRotate classes to divs with #top and #bottom IDs respectively.

$(document).ready(function(){
  $("#hamburger").click(function(){
      $("#top").toggleClass("topRotate");
      $("#bottom").toggleClass("bottomRotate");
  });
})

We put all our code inside $(document).ready(function(){}) in order to wait for the whole page to be loaded before taking any action.

When we click the #hamburger div, it will toggle the classes for divs with specific IDs.

Note: Do not forget to add the jQuery source file into your project.

View the current code

Creating the Menu List

The next step is to create a menu with list items.

Use the following structure under the #header:

#dropDown
    #background
    ul
        li Home
        li Blog
        li Projects
        li Authors
        li Jobs
        li Contact

So here we used the ul tag as the parent in order to group the items with li tags as children. Moreover, in order to create an expanding background animation, we also added a div with the ID of #background.

Let’s style the ul and li elements first.

ul
  list-style: none
  padding: 0
  margin: 0

Set the list-style to none in order to remove the bullets from the ul elements and also set both padding and margin to 0 in order to remove all predefined values.

Now style the li elements:

li
    //display: none
    background-color: #9b9b9b
    color: #ffffff

    font-family: 'Quicksand', sans-serif
    font-weight: lighter
    font-size: 15px
    padding: 20px
    padding-left: 60px

    &:after
      position: absolute
      content: ''
      left: 60px
      width: 60%
      height: 1px
      bottom: 4px
      background: rgba(255, 255, 255, 0.25)

    &:last-child:after
      width: 0

Here I commented out the display:none in order to be able to see the result. However, when animating, we will use it to hide the list elements initially.

I also added the after pseudo-element and styled it accordingly in order to separate each li element with a straight line. :last-child:after removes this line for the last li element.

View the current code

Animating the Menu List

Now we are going to use some Sass control directives in order to add CSS keyframe animations with different attributes to each li element.

@keyframes drop
  0%
    opacity: 0
    transform: scale(1.3)

  100%
    opacity: 1
    transform: scale(1)
    
@keyframes fold
  0%
    opacity: 1
    transform: scale(1)

  100%
    opacity: 0
    transform: scale(0.7)

Here we defined our keyframe animations drop and fold.

drop is for animating the opening of the menu list. The initial scaling is 30% more, and it scales back down to the original size as the transparency goes from 0 to 1. The opposite action takes place in fold.

Now we need to attach those keyframes to li elements. This part is where the Sass comes in handy.

@for $i from 1 through 6
  li:nth-child(#{$i})
    animation:
      name: fold
      duration: 80ms*(6-$i) + 1ms
      timing-function: ease-in-out
      fill-mode: forwards

  li.anim:nth-child(#{$i})
    animation:
      name: drop
      duration: 100ms*$i
      timing-function: ease-in-out
      fill-mode: forwards

Here I used a for loop that goes from 1 to 6 with the index of $i.

Now we need to use this index to attach each animation to li elements with different durations.

First, consider the li.anim:nth-child(#{$i}) line.

Here we are grabbing the $ith child of the li element with class of anim.

We will be toggling this anim class. So, when it is added to li elements, the keyframe animation with the name of drop will take action. When it is removed, the fold animation will take action.

The next important thing is the duration attribute.

duration: 100ms*$i for the drop animation is extending the duration of the animation for each incrementing child number. So, when this code is compiled, the first li child will have duration: 100ms, and the last child will have duration: 600ms.

This will give the sense of animating each element one after another.

We do the same thing for the fold animation. This time, the last element should be animated faster, hence duration: 80ms*(6-$i) + 1ms. The 1ms added to the duration is due to the fact that when you set the duration to 0, some problems are likely to occur, and your animation might not work properly.

When we were styling the li element, I mentioned that we needed to use display:none in order to avoid undesired animation playing. If you don’t set it to none, you will see that the fold animation plays once when the page is loaded.

If we set the display property to none, we won’t see that, and then we need to show the li element before toggling the anim class.

We want our animations to play when we click the hamburger icon. So let’s use some jQuery to set the display property of each li item to block and also toggle the anim class.

$(document).ready(function(){
  $("#hamburger").click(function(){
      $("#top").toggleClass("topRotate");
      $("#bottom").toggleClass("bottomRotate");

      $("li").show();
      $("li").toggleClass("anim");

  });
})

View the current code

You will notice that we can see the animation of each li element individually. However, we’d rather have an expanding menu feeling.

In order to fix that, we simply need to expand the height of a div. That div is #background, which we initially added when creating the ul and li elements.

#background
  width: 100%
  height: 0
  background-color: #9b9b9b
  position: absolute
  +transition(.45s)

  &.expand
    height: 550px

We will be toggling the expand class in order to set the height attribute to 550px within .45s. Note that I used the transition mixin to define the transition with a specific time parameter.

Final Result

Conclusion

Throughout this tutorial, we practiced how to use for loops within HTML and CSS through the Jade and Sass templating engines. On top of that, we created CSS keyframe animations and attached them with different duration attributes to specific HTML elements. Then we toggled classes with jQuery to control those animations.