Animated Drop Down Menu With CSS3 (and no JavaScript)

Some thing quick, simple and fun this time.   A drop down menu, built solely with HTML and CSS, that is functional back to IE7, and animated for browsers that support CSS3 transitions. See the end-product, here.  Let’s get going…

First, the HTML structure.


<menu id="mainmenu">
  <ul>
    <li>
      <a href="#">Main 1</a>
      <ul>
        <li><a href="#">Sub Menu 1-1</a></li>
        <li><a href="#">Sub Menu 1-2this a long one goes for a while</a></li>
        <li><a href="#">Sub Menu 1-3</a></li>
      </ul>
    </li>
    <li>
      <a href="#">Main 2</a>
      <ul>
        <li><a href="#">Sub Menu 2-1</a></li>
        <li><a href="#">Sub Menu 2-2</a></li>
        <li><a href="#">Sub Menu 2-3</a></li>
        <li><a href="#">Sub Menu 2-4</a></li>
        <li><a href="#">Sub Menu 2-5</a></li>
        <li><a href="#">Sub Menu 2-6</a></li>
        <li><a href="#">Sub Menu 2-7</a></li>
      </ul>
    </li>
    <li>
      <a href="#">Main 3 this one goes for a while and does not wrap</a>
      <ul>
        <li><a href="#">Sub Menu 3-1</a></li>
        <li><a href="#">Sub Menu 3-2</a></li>
        <li><a href="#">Sub Menu 3-3</a></li>
        <li><a href="#">Sub Menu 3-4</a></li>
      </ul>
    </li>
    <li>
      <a href="#">Main 4</a>
      <ul>
        <li><a href="#">Sub Menu 4-1</a></li>
        <li><a href="#">Sub Menu 4-2</a></li>
        <li><a href="#">Sub Menu 4-3</a></li>
        <li><a href="#">Sub Menu 4-4</a></li>
      </ul>
    </li>
  </ul>
</menu>

A menu tag to provide semantic context, with a top-level unordered list to provide structure for the top level of the menu, and nested unordered lists to provide structure for the drop-down (or sub) menus.

Now, let’s do the layout with some basic CSS.

menu ul {
  padding: 0;
  margin: 0;
  list-style-type: none;
}

#mainmenu {
  width: 55em;
}
#mainmenu > ul > li {
  float: left;
  width: 25%;
}

#mainmenu a {
  display: block;
  padding: 0.5em;
  background-color: black;
  text-decoration: none;
  color: white;
  font-family: arial;
  text-overflow: ellipsis;
  overflow: hidden;
  white-space: nowrap;
}

Here we eliminate the default margins and padding, and bullets, for the unordered lists that make up our menu.  Then we float the list items for the top level menu to the left.  We also set a width for the menu, and divide this width equally (25%) among the four sub-menus. At this point we should have the items lining up correctly, with top level items going from left to right, and their corresponding sub-menu items rendering beneath.

We’re also going to do our aesthetic styling on the hyperlinks, as this will allow for the link/visited/hover/active behavior to take up the entire space of the list items in he menu.  To do so, simply specify the hyperlink (“a”) elements to be display blocks, and set any padding/margin on them.  We also set the default background color, font face and text color here, as well as setting the text-overflow to ellipsis in case the text is longer than our width.

We can now hide the sub-menus and get ourselves into our default state simply by adding this CSS:


#mainmenu > ul > li > ul {
  height: 0;
  overflow: hidden;
}

We just set the height of our sub-menus (he nested unordered lists) to 0, and hide any overflow so it’s not visible.  (We could use “display:none” here and also have it function, but this won’t work in conjunction with the animated effect we will add shortly).

So, to get our menu functional so the corresponding sub-menu displays when you hover over a main menu item, it’s simply a matter of setting the height to it’s appropriate height:


#top > ul > li:hover > ul {
  height: auto;
}

#mainmenu > ul > li:hover a {
  background-color: dimgray;
}

#mainmenu ul li a:hover {
  background-color: gray;
}

We also set the background color to change to indicate the hover over menu item and sub-menu item states.  At this point we have a fully functional drop down menu that works on browsers back to IE7.  And with no JavaScript!

Finally, we can animate the “dropping down” of the menu with a simple CSS3 transition.  We are going to do this on the “max-height” property of the nested unordered lists by setting them to have a max-height in the hover state that is greater than any possible height for our sub-menus.  In the default/non-hover state it will have a max-height of 0.  And we’ll set a transition for the max-height property to create the animated effect:


#mainmenu > ul > li > ul {
  height: 0;
  overflow: hidden;
  max-height: 0; /*start state of animation/transition*/
  transition: max-height 0.5s ease-in;
}

#mainmenu > ul > li:hover > ul {
  height: auto;
  max-height: 10em; /*end state of animation/transition*/
}

So the question may come up as to why we didn’t simply apply the transition to the sub-menus’ height attribute.  The quick answer is it doesn’t work, at least not if we set the height to “auto”.  Even if it were to work, and you may be able to get it to work if you set the heights of the menu items to a specific value, it may still not provide the ideal behavior.  By animating to the same “max-height” for each sub-menu, you ensure they sub-menus move at the same speed regardless of height differences.

And why not remove height altogether since we’re relying on max-height for the animation? Just a matter of preference for how the menu works when you mouse off the main menu item.  If we remove height, then you also see the menu animating to a closed/hidden state, which to me looks awkward, especially when another sub-menu is animating open at the same time.  Try it, and you may see what I mean.

And that’s it, an animated drop down menu with no JavaScript.  What I haven’t done is test this on mobile devices, though for that we may want to restructure the menu with a media query.  A possible future addendum for this article.

Questions?  Thoughts?  Feedback?

Advertisement

Responsive Analog Clock with CSS3 and JavaScript

My current place of employment is growing quite rapidly, and as such is doing quite a bit of hiring.  This means I, and others, end up doing quite a bit of interviewing.  One of the questions one of my coworkers asks in interviews involves how analog clocks work.  A few months back, I was thinking about this while doing some reading about CSS3, and naturally the thought of building an analog clock with CSS3 came to mind.

I say naturally as it has evidently come to mind for quite a few people as a useful academic exercise to flex their CSS3 muscles on.  A quick Google search for “css3 analog clock” comes back with a hearty handful of such renderings.  One in particular I like is “CSS3 Analogue Clock without using Images” by Matt Walker, as it renders the clock face solely with HTML5 and CSS3; ie, he uses no images.  It takes an approach similar to how I did, using common digits rather than Roman numerals, and rotating them appropriately with CSS3 transforms.  I particularly like how Matt went beyond the simple clock face and built up the entire clock body with CSS.  Pretty cool stuff!

Aesthetically speaking, my clock is not nearly so fancy.  One of the challenges I did present to myself when building this clock, however, was to make it responsive.  That is,  to use relative measures and have it (re)size itself appropriately to the width of the viewport.  What I’d like to discuss here is the technique I used to make it responsive.  If you want to test its responsiveness, resize your browser.  Or if using a mobile device, rotate it.  The other thing I did differently was utilize requestAnimationFrame to have the second-hand scroll smoothly, as opposed to doing one second ticks/jumps.  I won’t get into that, here (but do feel free to check out the code).

Basically, responsive design involves building an HTML UI utilizing relative CSS measures and appropriate breakpoints, usually defined with media queries, to make the UI resize elements, show/hide elements, and basically structure itself appropriately based on the width of the viewport.  But I’m assuming you’re aware of all that.  If not, Ethan Marcotte’s seminal article on Responsive Web Design can provide you with more details on how it generally works.  (If you check it out, be sure to resize your browser while at the start of the article and watch what happens to the lead image).  Or if you want the nitty-gritty details on responsive design, including handling images and tables, Aquent Gymnasium offers an outstanding free course on the topic.

So let’s get going.  The responsive analog clock can be viewed here: http://phhht.com/putz/clock.html

If you try resizing your browser to a width under 480px you should see the size of the clock shrink in a responsive manner relative to the width of the viewport.  You should also notice it has a maximum width of about 480px when increasing the width of the viewport.

There’s nothing radical with how I implemented it.  Every HTML element that makes up the clock has its size defined in ems, such that the size of the child elements are relative to the size of their parent elements up to the one top level div.  I can then reset the size of the clock by simply setting a single CSS property on the top level div–the font-size–and this changes the size of each child element proportionately.  Some code may make this clearer.

The HTML for the clock is really basic:

<div id="clock">
    <div id="hour"></div>
    <div id="minute"></div>
    <div id="second"></div>
    <div id="center"></div>
</div>

Our top level element is #clock, with four immediate children nested whose purposes are self evident.  I think we can simply focus on #clock and #center to come to understand the technique used.

In the CSS, I set the base font size for the body to 16px (which is generally the default you would get, anyway), and then define the CSS for our elements sizing them using em as our measurement.

html, body {
    font-size: 16px;
}

#clock {
    width: 30em;
    height: 30em;
    border-radius: 50%;
    border: solid 2px black;
    margin: auto;
    position: relative;
}

#clock #center {
    height:2em;
    width: 2em;
    border-radius:50%;
    top:14em;
    left:14em;
}

For #clock, the CSS makes our div round with a diameter of 30em (by setting border-radius to 50%, and the width and height to 30em).  It is important to note that #clock inherits the font-size of 16px from the body, as this means 1em for #clock is, by default, 16px.  As far as the ems for the child elements, we only care that em is a relative measure to em for #clock.  For instance, #center represents the dot at the center of the clock face.  We give #center a diameter of 2em, so we can center it by positioning its “upper left corner” relative to #clock‘s “upper left corner”  14em from the left and 14em from the top.

So what we have at this point is a circle with a diameter of 480px (30em x 16px) that has a black dot in its middle whose diameter is 32px (2em x 16px).  If we make our viewport width less than 480px at this point, our circle and dot sizes don’t change correspondingly.

So let’s say we tried setting the font-size for #clock to 10px.  What we should find is the diameter of our circle is now 300px (30em x 10px), and the dot now has a diameter of 20px (2em x 10px), and is still centered in our circle.  Since #clock is our top level element, by setting font-size to 10px, we have defined the size of an em to 10px for all elements that make up the clock (so long as we don’t specify the font-size of any child elements to a physical measure).  And note that since we defined how we positioned our dot (#center) in ems as well, it remains in the center when we change the font-size of #center.  So changing the size of our clock is as simple as changing the font-size of our top-level element for the clock.

At this point, it should be becoming apparent how we’ll make the clock responsive.  The most obvious way would be to define a media query for a viewport width of 480px and greater that sets the font-size of #clock to 16px, and define other breakpoints at lower viewport widths (less than the width) with correspondingly lower font-sizes for #clock.  And that should work, though you’ll only have the width (diameter) of the clock maximized when the viewport width matches exactly our media queries.

Alternatively, I took an approach of resetting the font-size of #clock with a handler for the window resize event:

function setSize() {
    var b = $("html, body"),
        w = b.width(),
        x = Math.floor(w / 30) - 1,
        px = (x > 15 ? 16 : x) + "px";

    $("#clock").css({"font-size": px });
}

$(document).ready(function () {
    setSize();
    $(window).on("resize", setSize);
});

So now when we resize the browser window to below 480px, we see the size of our clock resizing proportionately for all widths, much like you’d see an image responsively resize when you set the max-width of it.

Now you may be thinking I’ve only demonstrated resizing a circle and a dot proportionately.  Well, the technique demonstrated here will work for all elements that make up the clock so long as you are sure to size and position them with ems.  (Setting the rotation angle with CSS transforms does not need to change as the angles involved don’t change as the size does).  But given that, If you are interested in seeing how I got my analog clock fully built and functioning, the un-minified CSS and JavaScript are here and here.

So there you have it: a technique you can use to build a responsive analog clock with CSS and JavaScript.  Comments?  Thoughts?   Love?  Rage?  Please share.