Horizontal Lifestyle

Right. Let’s see if I can get this to work right. Fist you’ll need to load up a copy of IE for yourself and visit this page (if you’re not already using it).

Horizontal menus. You’ve seen them in Tank! but they weren’t quite right. So as part of this dropmenu system I’m working on, I’m including support for horizontal menus (to some extent anyways. can’t see why you’d want horizontal menus below the top level).

Compatible menus at that.

This led me on quite a journey these past two days.

First thing to realize is that those horizontal menu items have to float. They have to. Otherwise you can’t pull off a dropdown menu properly across all (or as many as possible) platforms. (Although I suppose display:table-cell might help with that a bit…) But anyways, if I’m floating, I’ll have to clear things at some point. Otherwise content that should appear below the menu will appear either on top of it or to the side of it.

Basic Markup

Here’s what the basic markup looks like:

<ul
  ><li><a href="">Menu Item 1</a></li
  ><li><a href="">Menu Item 1</a></li
  ><li><a href="">Menu Item 1</a></li
  ><li class="clear"></li
></ul>

A bit funny with how the closing tags are. PUrpose is to remove all whitespace between LI elements. Otherwise IE puts whitespace between the elements on screen. That may be desirable for you, but it isn’t for me.

The last LI is a clearing element. The idea here is that all the LI elements float left and the last one clears it all out. This keeps everything neatly contained witin the UL element and requires no wrapping DIV element.

A Cute Idea

Let me start with something I tried late in my experiments. An idea that seems quite cute and I think has some merit if given the right circumstances. I was having problems getting the clearing element to work properly in all browsers. And then I set the width on the UL element to 100% to trigger IE/Win’s hasLayout property. This had a curious side-effect in other browsers. Because the UL element was now 100% the width of the browser, there was no space on either side where text could wrap around (as is the normal procedure for a floating element that is around text). So the text dropped down below the horizontal list.

Now I would have thought that the margin on the P element that immediately followed the list was responsible for that. But even if that were the case, the text should still have started to the right of the right-most menu item. But for some reason it didn’t, even in FireFox, Safari and Opera.

So it may be there’s a case to contain all your floating elements within a block element and set its width to 100% you’ll find things forced down.

I don’t know. I didn’t investigate this completely because I quickly found that it created a horizontal scrollbar in IE/Mac and that was something I didn’t want to deal with. So I abandoned it.

The Art of Clearing

So, you see my HTML up above, yes? And you see that LI element with the class property set to clear. That is a clearing element. It has one purpose, to force itself below all previous floating elements. That way anything following the clearing element will also be below all previously floating elements.

But it’s ugly, from a purist’s standpoint. It’s redundant markup. It provides no meaning and serves no informational purpose.

So for the last few years people have been trying to come up with new and exciting ways to clear without redundant markup.

One of them is quite simple, fairly compatbile, and a joy for CSS developers. That is overflow:auto;. You set that rule to a block element containing floating elements and it’ll trigger the containing block element to size itself to contain it’s floating children. It’s very simple and very nice, especially when compared to the alternative.

But there is a problem with using this in my particular case. I’m creating dropdown menus. Elements are absolutely positioned and hidden, then set to appear when a mouse hovers over a given element. Because it’s absolutely positioned it’s removed from the flow of the document. This means it’s parent element has no clue nor any care how big it is or where it is located on screen. So when I apply overflow: auto; to my UL element … it works! That is until you mouse over an element that has a dropdown menu attached to it. Then the fun begins. You get scrollbars! Scrollbars for your UL element. Those dropdownmenus? They’re there.. but you can’t really see them unless you move the scroll bars. But if you move the scrollbars you take your mouse off the element containing the dropdown and so it disappears.

Not very usable.

Although it is a very fun way to annoy people.

So that’s out.

Tried and Trued

So that clearing element then. .clear { float:none; clear:left; } should do the trick and we’re on our way, right.

No. If it were, I’d have published the menu system by now and I wouldn’t be bothering you with this long and rather dull (unless you’re a CSS junkie… I’m sorry)

Here’s the thing. Netscape 7 and early editions of FireFox had this bug where they wouldn’t recognize an element that had no content. So an empty LI like in the example way up top wouldn’t clear. The way I get around this is by applying 1px of padding to the bottom of the element. Now Netscape 7 comes ’round and all is well. Throw in a -1px top margin to compensate for the 1px of space you’ve added to the layout with the padding and nobody is the wiser about our Netscape 7 clear hack.

That is.. unless you want to apply a border or in any other way utilize the parent UL element for visual styling. For example a border. Something like what you see just beneath the masthead in skidoo. That was done using a DIV containing the UL element, so all this 1px nonsense wouldn’t really matter.

With this 1px bit you’re adding 1px worth of space below your menu items. So the border on the bottom of the UL element is going to show to your users a 1px gap between it and the menu items.

And try as I might, use every trick in the book, I can’t hide that nasty little 1px reminder of my ugly, coarse Netscape 7 hack.

Getting Stingy With HTML

Oh sure, wrap it in a DIV, solve all our problems. But I’d rather not. The name of the game, folks, is thin markup. Don’t do more than is absolutely necessary. One of the nice, shiny promises that was touted when CSS was coming into mainstream was that webpages would no longer suffer from messy markup. All the redundant nonsense we adopted during the table-hazed 90s would be gone. A window in a smoky house opened by our friend, Mr. CSS.

(Sorry. Practicing for that theoretical book and all.)

But that was all rubbish.

With IE 5 and Nescape 6 we started going DIV crazy. Why wrap it in 1 DIV when you can wrap it in 4 and put a round corner image in the background of each?!

Welcome the new style, same as the old style.

I’m as much guilty as the next man or woman. Still am, really. Hard habit to kick.

But I’m trying. And with all future work I’d like to be a bit more tight and thin with my markup. So just wrapping this up in a DIV just won’t do. I’ve got a perfectly good block element in that UL element. I don’t need a DIV. I just need to figure out how to use it.

And so…

Here’s the result.

I’m having PIE.

The :after pseudoclass has proven to be very reliable in all modern browsers (save IE). And where IE fails I can easily compensate by triggering the UL element to have layout.

For horizontal menus I can do it many ways, be it floating the UL itself (in which case I will need a clearing element, thus redundant markup) or I set the width to 100%. But IE/Mac hates 100% width! Yep, so I use a backslash hack to apply display: inline-block and that gets IE/Mac all warm and fuzzy.

Vertical menus already have a set width (be it static like 6ems or dynamic like 100%, so I don’t really need to worry here) so they already have hasLayout triggered.

So then, how are those menus coming?

Pretty well. I think I’m close. I’ve got them working in every major platform. I’ve even got IE/Mac 5.0 working. I think most of the big issues are just about ironed out. It’s the little things now that I’m on.

For example, it seems that you need to list your classes (if you assign multiple classes to one element) in order of precedence. Otherwise IE/Mac gets a bit confused.

Also I still have some minor rendering bug in IE. It draws the borders on the UL element of the dropdown menus when the menu shouldn’t be on screen at all. It only does this after I’ve viewed that menu at least once and will go away if that menu isn’t showing before I leave focus of the parent menu. It’s quite odd and could be resolved by simply not drawing borders on the parent UL at all. But then I have to use negative margins on the LI elements to overlap borders and things can get a bit muddy there… well you start to see what I mean. The little details.

I also want to add some additional functionality that lets you set where and how menus pop and drop based on the class you assign. So a right aligned horizontal menu might have dropdown menus that drop to the left, not the right, of the menu item; like what you see in Tank!.

But things look good.

I wanted to include a bit about a really odd behavior in IE I found but I’ll save that for a later post.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s