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.

Tuesday, July 27, 2010

Object Oriented PHP

Work’s not got much web dev going on at the moment, so more on the hobby sites...

I discovered a few months ago, while I was converting one of my sites to be database driven that PHP has objects.  This was news to me.  (Okay, not entirely. I’ve been using the DOMDocument object for years.  But the extensiveness of the object library, and the ability to create and extend classes was new.)  I’ve always thought of PHP as fairly procedural language.  But being able to extend the mysqli objects has been really useful.  Also the discovery of the function_exists and class_exists functions was really nice.


if(!class_exists('readDB')
  include 'readDB.php';


is one of the greatest pieces of code that exists.  [Edit: I've since learned about include_once which solves this problem in one line...]  Not having to worry about accidentally including a file twice, or not at all is particularly wonderful.
Also, I’m a fan of exceptions.

On the aforementioned rowing team site, it occurred to me yesterday that I could probably create an Ad container object, and then extend the DOMDocument object specifically to process the Ad editing form (I did convert them over to XML), and even output the required HTML.  But I haven’t sat down to do it yet.  It’s too hot in my un-air-conditioned house to think about it.  But it’s supposed to be cooler Thursday, so I’ll probably write about how that’s going Friday.

Wednesday, May 12, 2010

Coolest Things about my Latest Site

I’ve been working on a new site for the Rowing Club recently.  This is the first site I’ve designed with Chrome as my default browser, and also my first foray into HTML 5.  It’s been going pretty well so far, but I have discovered that support for HMTL 5 isn’t great yet. <header>, <footer>, and <nav> don’t have proper support yet (except in Chrome alpha, much to my chagrin).

I’ve been playing with rgba colors too, and getting some cool effects for the headers and menus.

But the coolest stuff I’ve been doing for this site has definitely been on the back end.  I’ve got the ads populating from a text file (although I think I might switch that over to XML), the news feed populating from an RSS feed, and the calendar and menus populating from XML files.

Also, that calendar is all kinds of AJAXy goodness.  It switches to the next month with a call to the server to regenerate the calendar dates and all its links.  That allows me to generate the calendar with PHP, and that, in turn has helped me see why AJAX is so awesome.  It goes really well with unobtrusive Javascript.  With Javascript turned off, I can call a page that calls the same PHP, so that we don’t lose any functionality.  Accessibility for free!

Next on the list is making forms to create these XML files, so that my rowers can update the website without me needing to do it.

Oh, and of course, a link.  This is currently served off of my computer, so if the link is broken, it’s because my box is off.  8–noon and 6–10pm Eastern are the best times to take a peek, but you can probably view it at other times.

It’s a bit low on content at the moment, but once the forms are finished, I’ll start filling it in, and then give it a real address.