Showing posts with label css. Show all posts
Showing posts with label css. Show all posts

Sunday, January 6, 2013

Pure CSS Dropdown Menus (with Transitions) (Part 2: Drawers)

I promised two years ago CSS3 drawers.  Back when I did this originally, I was bleeding edge—no one had done this yet with just CSS that I had seen.

Since then, I've been scooped.   But that's what happens when it takes you two and half years to post some code. ☺

Here's the demo, and the code is below. (HTML is the same as the previous post.  Also like the previous post, I'm lazy so this only works in Webkit.)
body {
    margin: 0;
}
.nav {
    margin: 0;
    padding: 0;
    background-color: rgb(101,101,101);
    color: white;
}
.nav li {
    display: inline-block;
    font-weight: bold;
}
.nav li.parent {
    position: relative;
}
.nav li.parent,
.nav a {
    padding: .5em 1em;
    color: white;
}
.nav li.parent:hover {
    background-color: rgb(80,80,80);
}
.nav a:hover {
    background-color: rgba(0,0,0,.2);
}
.nav a {
    display: block;
}
.nav li.parent ul {
    position: absolute;
    top: -500%; /* must be at least as tall the submenu itself */
    left: 0;
    z-index: -1; /* sets the submenu behind the main menu */
    margin: 0;
    padding: 0;
    overflow: hidden;
    background-color: rgb(101,101,101);
    -webkit-transition: top 0.25s linear;
}
.nav li.parent:hover ul {
    top: 100%;
}
.nav li.parent ul li {
    width: 100%;
}

Something worth noting here is that, unlike the previous examples, this one does not use translucent colors.  That's because the submenu drops down from behind the top level.  If I used translucent colors, you can see it, which could be a cool effect in some fairly specific circumstances (maybe with the fancy new blur filter?), but not desirable in most situations.

This is definitely the way to go in terms of menu animation.  It's smooth, it stems naturally from the main menu, and it's a well-known paradigm.


Tuesday, August 24, 2010

Pure CSS Dropdown Menus (with Transitions) (Part 1: Fade)

This blog post stems from a comment I left on onwebdev a couple of weeks ago.

If you don’t feel like reading it, basically, I argued that CSS transitions (part of the CSS3 spec) could be used in place of Javascript to create purely presentational behaviors like sliding or fading dropdowns.  I spent yesterday and today figuring out just how to implement those things.

Let’s start with a plain, standard CSS dropdown menu:

<ul class="nav"> <li><a href="#">Link 1</a></li> <li class="parent"> Submenu 1 <ul> <li><a href="#">Item 1</a></li> <li><a href="#">Item 2</a></li> </ul> </li> </ul>

And the CSS:

body { margin: 0; } .nav { margin: 0; padding: 0; background-color: rgba(0,0,0,.6); color: white; } .nav li { display: inline-block; font-weight: bold; } .nav li.parent { position: relative; } .nav li.parent, .nav a { padding: .5em 1em; color: white; } .nav li.parent:hover, .nav a:hover { background-color: rgba(0,0,0,.2); } .nav a { display: block; } .nav li.parent ul { display: none; position: absolute; top: 100%; left: 0; margin: 0; padding: 0; overflow: hidden; background-color: rgba(64,64,64,.98); } .nav li.parent:hover ul { display: block; } .nav li.parent ul li { width: 100%; }

This is the basic dropdown you’ve all seen before (Demo).  Hover over a menu item, and it changes color, and a dropdown appears, instantly.  Stop hovering, and the dropdown disappears, just as instantly.  But what if we don’t want it to appear instantly?  What if we want it to appear with a gradual fade?

It’s a little bit more CSS—CSS Transitions, to be exact (And I’m feeling lazy, so we’ll do Webkit only).  First, we have to change how we’re making our submenus appear and disapper, since display can’t be transitioned.

Instead, we’ll set a height of 0, and an opacity of 0 for the hidden state, and a height of auto and an opacity of 1 for the shown state.

.nav li.parent ul { position: absolute; top: 100%; left: 0; margin: 0; padding: 0; overflow: hidden; background-color: rgba(64,64,64,.98); height: 0; opacity: 0; -webkit-transition: opacity .25s ease-in; } .nav li.parent:hover ul { height: auto; opacity: 1; }

Without the -webkit-transition line, this acts exactly like our original dropdown.  The magic comes with the transition property (Demo).

This transitions just the opacity, so the heights take effect immediately.  The upside of this is that when you hover over where the menu is going to be, it doesn’t appear.  The downside is that it disappears immediately (because the height is 0).  If you leave the height off, you get a nice fade out, but the submenu is always there, just invisible, so you can still hover over it by accident.

I haven’t yet come up with a perfect solution to this, but while trying, I found something pretty cool (Demo).  We can have two transitions combined, at least on the way out.  Here’s the code:

-webkit-transition: all .25s ease-in; nav li.parent:hover ul { height: auto; min-height: 2em; opacity: 1; }

“All” makes anything transition that can, whether it’s specified or not.  That’s useful in this case.  We get the same fade in behavior as before, but additionally, we fade out and scroll up to disappear.  Here’s how the scroll works.

Transitions apply to height, but not with values of auto.  So when we unhover, the height immediately becomes 0.  But we’re still in transition, so the min-height of 2em from the hover takes effect.  And then, since our finishing state has an implicit min-height of 0, the min-height changes gradually to 0, causing the submenu to wipe up.

Next (probably not tomorrow, but maybe Thursday): Part 2: Drawers.