hasLayout, Will Travel

What is the hasLayout hack?

IE has some problems. It doesn’t rendering some objects correctly, especially when floats are involved. Before I knew about the nature of this problem I would set position:relative; on the bugged objects and that sually fixed things.

Research by others has turned up this page about the hasLayout property, which is an attribute assigned to objects in a web page.

It appears that by triggering this property to be set to true resolves many rendering issues with IE.

position:relative; is one way to trigger this property. But there are instances where you can’t use this property on certain objects in your layout. Another approach is to set the width or height property. I would use a height:100% to fix a text-jog bug in IE that occurs when you have a float and non-floating element next to each other. One trick that I was shown that I now use quite often is to set the height to 0.01%. IE will automatically grow the element to whatever height is needed to contain it’s children, effectively making this bit of CSS meaningless, except that it triggers the hasLayout property. Now with this approach, you also have to keep that CSS from being applied any anything other than IE. So we use an IE-only CSS selector to keep it within IE. We can then take it one step further with a comment hack to keep IE/Mac from applying the CSS as well. The result is what is probably the most common, easiest approach to the hasLayout hack that is out there:

* html .hasLayoutHack
{
    /* \*/ height: 0.01%; /* hasLayout Hack */
}

There you go.

Why 0.01%? Why not 1%? That’s because if this value is larger than the contents of the object this is applied to, it will take the defined height, meaning it’ll be taller than intended. I’ve come across this before when being used on a very very very long webpage.

What about using 1px instead of a percent value?

An excelent question, for which I have no answer. I think it was just a force of habit. Using 1px should work fine. In fact, unless you find a bug using pixels, I’d say go right ahead and use 1px. And if I remember why I stick with percents on this hack, or if there’s no real reason for this, I’ll be sure to leet everyone know.

Advertisements

Back Drop

Here’s a bit of an oddity with IE I’ve found.

If you take a look at the CSS drop-down menu demo you’ll see I’ve added a second top-level item. This item’s submenus have no background color. (Actually, the color is set to transparent to counter a higher-level CSS background-color definition.)

Now try using those menus with IE. The first top-level item and its menus will work fine. Now try the second top-level menu item. Try hovering over the third/bottom “level three” link. You probably won’t get your mouse over it before the menu disappears. Those with really fast hands might be able to pull it off.

So it would seem that the simple act of adding a background color can drastically change how an element is handled by IE. This isn’t a hasLayout* hack issue, this is something different.

My guess is that IE allows mouse events to be passed to any object(s) below a transparent object. So when you mouse over any area of those list items that isn’t a border or text will trigger IE to pass the mouse’s position and any rollover events to any objects below the menu. By having these events pass to another object, I believe a mouse-out event is triggered on the menu, thus losing the :hover state and making the menus collapse.

This is a bit frustrating, but once you’re aware of the bug, you can easily work around it.

Other Drop-Down Menu Issues

You’ll note in the various layouts that I use a horizontal menu based on unordered lists, I make the list elements inline elements rather than block or list-item. I take this approach, rather than using floats, so that the list functions as expected (or as best as can be) in IE 4 and IE 5.0, where floating the list-items don’t work as well.

The downside to this is that drop-down menus off those elements don’t work so well. Opera simply doesn’t display them as if the :hover state is ignored. IE seems to set the drop-downs as having a z-index of -9 million, as they appear under the text of the main content/column, rendering them unusable.

So I’ll have to play around with that a bit and see what alternatives there are. I’ve wanted to take the time to re-invent my list-based menus anyways, and this looks to be as good a time as any.

Say It Isn't So

Looks like P.I.E. just went subscription based. This means to read the articles you’ve got to pay.

This is more than a little disappointing as their write-up on debugging IE (aka Holly Hacks) is no longer there and apparently only available via subscription.

I got nothing else to say, except I’m really really bummed by this. I’m going to look into writing up my own page on the hack formerly known as holly. I’m also going to give it a new name. But right now I’m working on skidoo too: redux, which is basically a small reorg/rewrite of the CSS for skidoo too that will, hopefully, include basic drop-down menu support, as well as some general holly hacks that will, hopefully, prevent some of the problems people who have used the layout have encountered in the past.

Drops and Fits

I’ve updated the drop-down menu demo a little to get it at least semi-usable in IE 5.0. I also fixed a bug with some rendering artifacts in IE 5.5/6, a little z-index goes a long way.

It definately doesn’t work on a Mac. Hah. Nor does my event attach function in the ruthsarian_utilities.js that exists out there, somewhere. So I’ll have to work on Macs for a bit.

This is the “fits” part

I received an e-mail asking if there was a way to keep the menus in place when a user enables the high-contrast accessibility feature under windows.

Well I turned on the feature, opened up the layout, and sure enough both the left and right-hand columns are pushed beyond the edges of the viewport. But imagine my surprise when I see that the gargoyles layout keeps its columns in line.

What?

The gargoyles layout is based on skidoo too so I expected them to behave in the same way.

But they don’t.

So I’ll tear apart the gargoyles layout and find out why the left menu doesn’t slip outside the window with high-contrast enabled. My guess is that the added block element surrounding each vertical nav (vnav) list is probably the cause, but maybe not.

It doesn’t make sense, either. The high-contrast option defaults to a larger font size as well. This larger font size (not the color change) is what’s causing the problem. Thing is, both the column width and the border width (used to generate each column’s background color) are defined in EMs. So they should both scale equally, but for some reason, they don’t.

I’m thinking it’s time to start applying some of the hacks I put together for the gargoyles layout into the skidoo too layout. The gargoyles layout is, by far, better at managing hacks, but I think I can do better. What I really want to do, first and foremost, is to almost create an entirely separate stylesheet of JUST hacks. So you can see what SHOULD work and what DOES work. But… we’ll see.

Updated Skidoo Too

I’ve updated the CSS and HTML of the skidoo too layout. I received an e-mail from Louise earlier this month who brought to my attention some rendering issues with skidoo too under Netscape 6.2.

After a bit of debugging, I’ve found some fixes.

The first problem was that the footer was not being rendered below the three columns. Rather it was being rendered below the right column. The fix for this was to add a clearing element at the end of the #SOWrap element. Without it, #SOWrap had 0 height because the two elements it contains are both floats. Once you float an element, its height has no bearing on the dimensions of its parent element(s). By inserting a clear inside #SOWrap, that element is forced to recognize the height of its floating children.

Another problem in Netscape 6.2 was that the left-menus would not render correctly on mouse hover. The culprit here (for some reason or other) was setting position:relative on #SOWrap. Removing that fixed the problem, however I need this bit of CSS to fix a text-jog bug in IE. So what I’ve done is changed the CSS selector from #SOWrap to * html #SOWrap which IE will still recognize, while Netscape/Mozilla/All Other Browsers ignore.

What does #SOWrap do anyways?

Good question. Skidoo too is a source-ordered layout. Meaning that the main column, where content unique to the individual page will reside, is placed as close to the beginning in the HTML source as possible. The reasoning behind doing this is that some search engines appear to index only the first 5kb of a webpage. So if your first 5k are navigation elements, chances are the unique content for that page isn’t going to get indexed, and the page won’t show up properly in search results.

Now taking the negative-margin approach to a 3-column layout that we see in skidoo / skidoo too, we can’t put the content column first in the source. Why? Because all three columns are floats. If the main column comes first in the HTML source and is floated left, that means any subsequent, left-floated elements will be stacked to the right (or below if there’s not enough horizontal space) of the main column.

Now we could float the content column to the right, which would allow the left-column to be put to the left-side of the content column. That’s what we want. But then we run into problems with the right-column, which would then be stacked to the left (or below) the content column. Not what we want.

So the solution is to wrap the content column and the left column into a new block element (#SOWrap). Then we can float the content column right, the left-column left, but float the containing #SOWrap element left, allowing the right-column to appear to its right, and thus the right of both the left and content column.

The left and content columns float inside #SOWrap so that their floats will not effect anything outside #SOWrap allowing to float: right the right column without having it stuck to the left of the content column.

Confused yet?

It’s a confusing thing, trying to figure out how floats stack in relation to each other. It might be worth your time to spend a couple hours just playing around with float elements. Don’t do anything complex, just some colored blocks that you float to different sides, and mix up the order in which the blocks appear in the HTML source. You’ll get the hang of things pretty quickly. What’s confusing to read and visualize will become very easy to understand when you see it in action.

Addendum To Drop-Menus

Just a heads-up that those drop-menus I posted recently do not work entirely under IE 5.0. I think it’s just a matter of playing with how the sub-lists are positioned, which I’ll work on and provide an update.

Also, there are some rendering issues with IE and the borders of list items being displayed over sub-menus for some odd reason. I’ve got no idea why this happens and will have to play around some.

FOUC

I’ve been mucking around with CSS for a few years now, but for some odd reason I’d never come across the term FOUC before a couple months ago when someone e-mailed me about it.

FOUC is basically that flash of white (maybe you’ll see the text too) when loading a CSS-styled webpage. It’s the unstyled content that gets displayed after the browser has downloaded the HTML but before it’s finished downloading/applying the CSS.

I got another e-mail about FOUCs today and I figured I’d share the link I was given to everyone. It’s very informative and worth at least a skim.

The address is http://www.bluerobot.com/web/css/fouc.asp.

Basically the quick fix is to stick a STYLE or SCRIPT block somewhere in the HEAD element of your page.

I’m going to try and duplicate and/or expand on some of the e-mails I get here in the blog since I’d guess for everyone 1 question I get, there’s 10 that have the same question but don’t e-mail me.

CSS-Based Drop-Down Menus

ul,
#navdrop li:hover > ul,
#dropsavvy li:hover > ul
{
display: list-item;
margin-top: -0.5em;
}
#dropnav li.sfhover ul ul,
#dropnav li.sfhover ul ul ul,
#dropsavvy li.sfhover ul ul,
#dropsavvy li.sfhover ul ul ul
{
display: none;
}
#dropnav li.sfhover ul,
#dropnav li li.sfhover ul,
#dropnav li li li.sfhover ul
{
left: 0;
display: list-item;
margin-top: 0.75em;
}
#dropsavvy li.sfhover ul,
#dropsavvy li li.sfhover ul,
#dropsavvy li li li.sfhover ul
{
left: 0;
display: list-item;
margin-top: -0.5em;
}
#dropsavvy li a
{
display: block;
width: auto;
text-decoration: underline;
}
* html #dropsavvy li a
{
height: 0.01%;
}
–>

<!–
sfHover = function( objID )
{
var sfEls = document.getElementById( objID ).getElementsByTagName( “LI” );
for (var i=0; i

CSS-based drop-down menus aren’t anything new. Suckerfish got
the ball rolling. Soon after we got Son of Suckerfish
which is the basis for a lot of the content in this post. I’ll be going off on my own attempts at drop-down menus and try
to share a little bit of insight gathered from the experience. Caveat: I’m throwing embedded stylesheets into this
post to generate the drop-downs. Typically you don’t put STYLE blocks into the body of a webpage. But, hey, it’s
not like this version of MT has been extremely tight on its compliance with w3 standards. :) So here we go.

The concept is simple enough. You create a nested list (ordered or unordered, it doesn’t matter, though unordered is my preferred
choice) and hide all sub-lists so that only the top level is displayed. When a user mouseovers a list item, the sublist it contains
is displayed on screen. When the user mouseouts the sublist disappears.

This is achieved in CSS by making use of the :hover pseudo-class. Let’s say we have a list with the id
attribute set to nav. Take a look at the following CSS:


#nav ul { display: none; }
#nav li:hover ul { display: list-item; }

So the top-level list (#nav) has all it’s sub-lists (UL) hidden (display:none). When a
list-item (LI) is in a hover state (the mouse is over the item) the sub-list of that list-item is then displayed
(display:list-item).

I use list-item rather than block for the display attribute because that’s what the
default value is for lists, and we should try to stick with these standard values as much as possible.

I won’t bother with an example of the above CSS. It doesn’t look great, doesn’t work in IE, and seems to generate artifacts in
FireFox. Basically what happens is you get a list with all top-level items displayed. If you mouse over one of the items, all
lists contained within that list element are displayed. So if you’ve got a nested list 4-levels deep, you’ll see all 4 levels
appear when you mouse over the top-level element.

The two key problems here are that it doesn’t work in IE, and mousing over an element reveals all sub-lists. What we
want is for the drop-downs to work in IE and when you mouse over an element, to only get the next level down to display, and
keep any lists 2-levels below hidden.

We can take care of the second part first, under FireFox and Opera and basically all other modern browsers but IE, by making
use of a combinator that allows us to specify only immediate children of a given element. This combinator is ‘>’.

Making the appropriate edits to the previous CSS we get the following:


#nav ul { display: none; }
#nav li:hover > ul { display: list-item; }

Not a big change at all, but it makes all the difference in the world. With the added combinator (that’s the w3’s term, not
mine) only the immediate (next level down) sub-lists get displayed. This means you won’t see lists 4-levels deep when you
mouse-over a top-level element. You’ll only see the next-level down.

Nice and simple, isn’t it? Just add some “window dressing” and you get this:

#dropnav, #dropnav ul
{
margin: 0;
padding: 0;
list-style: none;
width: 10em;
}
#dropnav li ul
{
position: absolute;
display: none;
margin: 0 0 0 65%;
}
#dropnav li:hover > ul
{
display: list-item;
margin-top: -0.5em;
}

Which generates something that looks like this (sans the color, borders, and … okay so
it doesn’t look like this, but it functions like this:

  • Level One

    • Level Two

      • Level Three
      • Level Three
      • Level Three
    • Level Two

      • Level Three
      • Level Three
      • Level Three

Looks pretty cool, eh? Oh, wait, what’s that? You’re using IE and when you mouseover nothing happens? Tis true, IE has two
issues (well, more like a million, but 2 that we care about for this article) that prevent this from working. First
is that it doesn’t support the :hover pseudo-class on anything other than anchors. Meaning it doesn’t understand
li:hover and ignores the selector. Furthemore, IE doesn’t support the > combinator. This will cause problems
that we’ll address later. First let’s see what can be done about this :hover business.

Simple. We fake it. How? Javascript. Now there are other methods where you wrap the sub-lists inside an anchor tag, but
that creates a really nasty mess. Besides, the HTML spec doesn’t allow nested anchor tags, which is what you’ll have if
you got more than 1 level deep. So that’s out. We could just hide the sublists for IE users and make sure that
alternate navigation methods exist for IE users when they click on the top-level item. (That is, assuming you’re using
drop-downs for navigational elements on you website. That’s the typical use, but maybe you will have an alternative.) This
method is nice in that you don’t have to resort to Javascript and you can have really tight CSS. But chances are you want IE
support. So we return back to Javascript.

I won’t get into the dirty with Javascript, but you can check out the
Son of Suckerfish webpage where I shamelessly
stole the Javascript from. I made only a slight modification in that the element id is passed as a function
argument rather than hard-coding it. This allows for 1 function to support multiple drop-downs on a single page.
You can view the source of this page if you care enough about the Javascript, but I’m trying to keep short
and already very long post.

What the Javascript does is simply set a function to trigger whenever there is a mouse over an LI element.
That function changes the class attribute for that element to include the class sfHover. On mouseout,
another event triggers to remove this from the class attribute. (Remember, class attribute can hold more than 1 class, each
class name being separated by a space.) So now we can fake li:hover by using li.sfHover for IE.

Now comes the really tedious part. IE doesn’t support the > combinator. So how can we keep only the immediate
sub-list displayed and all deeper sublists hidden when the user mouseovers an element?

#nav li.sfhover ul ul, #nav li.sfhover ul ul ul { display: none; } #nav li.sfhover ul, #nav li li.sfhover ul, #nav li li li.sfhover ul, { display: list-item; }

I’ll let that soak in for a second.

By nesting ul and li elements we can target specific levels to block any lists below it
from displaying when they are being hovered. What’s tedious about this is you have to keep adding these selectors
in for every level of depth you add to your drop-down menu. This example covers three-levels.
Now I don’t like this for two reasons. One, as stated
previously, it’s tedious. The other is that I don’t feel we should have to worry about how deep a list goes. Any
solution should be scalable to N-depth without the need for changing the CSS. Maybe there’s a solution with
Javascript, which I might try to work out myself, but for now this is what we got. I don’t like it at all, which is why I’d
seriously think about just ignoring IE users. (But I suppose we can’t really do that, can we?)

But when all is said and done, you wind up with something like this:

  • Level One

    • Level Two

      • Level Three
      • Level Three
      • Level Three
    • Level Two

      • Level Three
      • Level Three
      • Level Three

Now even IE users can use the drop-down menu. Very nifty.

There are, of course, a couple of silly little IE bugs that I had to workaround
to get the drop-downs working well under IE6, mostly holly
hack
stuff, but it’s all working nicely.

Except…

What’s missing? No links. No anchor tags in the examples that I’ve shown up to now. I’ve
done that on purpose so it was one less thing to focus on/worry about while getting the basics
down. Now, to really finish this off, we need to add links.

Nothing big here. Just wrap the text in each list item with an anchor tag, point it
at the URL you want it to link to, and you’re pretty much good to go. However, you
probably want the link to fill up the entire space the list item takes up; have the
whole box, rather than just the text, be clickable. Well we can do that, but we need
to make the anchors block items first. A simple display: block will
take care of that. Block items will, by default, take up as much horizontal space
as is available, so defining a width on the anchor elements isn’t needed. I’ve
specifically set to underline the link text just so you know what is and what
isn’t a link among all the demos here; you will want to probably take that part
out if/when you use this.

So without further adieu, here is the finished, 3-level deep, CSS-based, drop-down
menu.

Woo. Hoo.

Okay. So now you want to get your hands dirty and try this yourself. But you don’t
want to sift through the spaghetti markup MT generates (which you see by viewing the
source of this page). Well then, I’ve put together a little page which has the final
demo fo the drop-down list along with all relevant CSS and Javascript to get
your own going. You can access
CSS-based drop-down
demo page here
.

So now this example is geared torwards displaying the top-level (always visible)
items in a vertical fashion. You could do run them horizontally, if you wish, by
having top-level items with display: block; and float: left;
set to them. And then maybe tweak the margin values for UL elements
below the top-level so they pop-up where you want them to. I’ll leave that as an
exercise for you all.

Good luck.