Auto Positioning for Absolute Elements

Guest Author: "Big John" Gallant
positioniseverything.net

Return to vision.to

This article assumes that you understand the basics of absolute positioning and also the nature of "the flow." If you are hazy on these topics, please review the previous article discussing the  subject. You will also need a basic understanding of CSS syntax and at least a nodding familiarity with the use of the :hover pseudoclass.

AP Review

Usually absolutely positioned (AP) elements have some definite size and are positioned within a page according to to some length offest from two sides of a positioned ancestor element. Thus an AP logo image might receive left and top property values of "0" to place it in the upper left corner of a relatively positioned wrapper div.

This handling method is very common and useful, but sometimes it would be nice to let the normal flow control where that AP element is placed. The trouble is, AP elements don't care what the flow is doing if you give it those left and top length values. However, another handling method does exist that takes flowed elements into account when placing AP elements. We'll get to that in a moment, but first let's set up a test case we can play around with.

A good test case is a CSS "tooltip" or small labeling element that appears close to a hovered bit of text. The title attribute can easily produce such tooltips on any element when moused over, but those browser-controlled tooltips can't be styled via CSS and have other annoying limitations as well. CSS tooltips merely imitate real tooltips and so you're limited only by the potientials of CSS itself.

Making the Test Case

We start by placing a link around a small phrase within a larger text block, then insert a span inside, next to but not surrounding that key phrase text. The inner span gets position: absolute; and a large negative left value that keeps it off-screen until needed. Here's what the code might look like:

<p> Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Suspendisse leo mauris. <a href="#">link text<span>Tooltip text</span></a> interdum nec, tempus vel, dignissim sit amet, felis. Vestibulum egestas viverra nisl, dictum et, dignissim sed, eleifend et, dolor. </p>   a span {   position: absolute;   left: -999em;   }

This pulls the hidden element far off to the left of the window, so showing the AP element is simply a matter of changing the negative value to some other value during hover of the link, putting the inner span into the visible window. But what left value should we change it to so that it appears next to that bit of linked text? Well, usually its made to be zero or some small positive value, causing the tooltip to partially cover its parent link when the link gets hovered, but we're going to do it differently this time.

Okay, I know what you're thinking, "So, where's the positioning on the parent link?" While it's true that the AP span normally considers only positioned ancestors when calculating its own location, a special case does exist that doesn't require such positioned ancestor arrangements. (ancestors = surrounding elements)

I call this method auto positioning, and to do it, you don't use any length value, zero or otherwise. Instead, you simply avoid applying length values to any of the four side properties of that inner AP span (left, top< right, bottom), letting them default to the "auto" value. In such a case involving absolute elements, the specs say:

"...the term 'static position' (of an element) refers, roughly, to the position an element would have had in the normal flow."
Visual Formatting Model:
Absolutely positioned, non-replaced elements

So if all four sides of an AP element are auto, then this AP element is pasted onto the spot where it would go had it been non-AP, while remaining on its own layer. Perfect! All we need to do is create a hover rule that switches our negative left value to auto and the tooltip span will appear somewhere close to the linked text, controlled only by the flow and not by any positioned ancestor.
http://www.w3.org/TR/CSS21/visudet.html#static-position

Things to Keep In Mind

Typically in such cases as the tooltip method the link would be positioned as "relative" to provide a base for the AP span, but the situation I'm describing is just for the sake of an example showing auto positioning. There does happen to be one problem with positioning the link though, and that is the layering issue. While relative elements do remain within the flow, they are also considered to be on a unique layer, and sometimes this can cause difficulties on a page with many other positioned elements such as layered popups.

Imagine having an AP popup appear and look just fine, except for that pesky relative link that insists on sitting in front of the popup! Sure, z-indexing can fix it, but for complex positioning arrangements that sort of thing gets old fast. In that page it could be simpler just to let auto positioning do the job and not have to mess around controlling all your relative element's z-index numbers, particularly if you're changing z-index during hover, oy...

When hiding the inner span or other elements that will be made to appear later, the best choices are to use a large negative left or top value (use top when using left leads to difficulties). If you send the AP element to the right or bottom, you will then trigger browser scrollbars that allow scrolling access to that distant (and supposedly hidden) element; not good. Another common hiding method uses display: none;, later toggling to display: block; or display: inline;. This does work, but prevents screen readers and search engines from reading that hidden text.

Working with Static Positioning

It's time to actually test this stuff out. Keep in mind that the demo below is just for testing the method. I don't claim this particular arrangement is a real-world case, but it will help to demonstrate what can be done with auto positioning and AP elements.

Vestibulum lacus tellus, adipiscing in, volutpat sit amet, dictum ac, mauris. Duis euismod sapien quis tellus. Vivamus aliquam, lorem a accumsan consequat, dolor est iaculis est, nec pulvinar magna ipsum at lacus. Duis aliquam. Sed mattis. Morbi ipsum ipsum, euismod ut, scelerisque quis, faucibus et, tortor. Sed aliquam erat vel justo. Etiam lacinia, massa a ultrices pellentesque, Link text Tooltip text dolor ante sagittis nibh, eget interdum ante lectus nec est. Fusce rutrum faucibus mauris. Aliquam cursus nisl at diam. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Suspendisse leo mauris, dictum et, dignissim sed, eleifend et, dolor.

<p> Vestibulum lacus tellus, adipiscing in, volutpat sit amet, dictum ac. Duis euismod sapien quis tellus. Vivamus aliquam, lorem a accumsan consequat, dolor est iaculis est, nec pulvinar magna ipsum at lacus. Duis aliquam. Sed mattis. Morbi ipsum ipsum, euismod ut, scelerisque quis, faucibus et, tortor. Sed aliquam erat vel justo. Etiam lacinia, massa a ultrices pellentesque, <a href="#" class="linkparent1">Link text<span class="inner1">Tooltip text</span></a> dolor ante sagittis nibh, eget interdum ante lectus nec est. Fusce rutrum faucibus mauris. Aliquam cursus nisl at diam. Lorem ipsum dolor sit amet. </p>   .linkparent1 { color: #a00; } .linkparent1:hover span { left: auto; } /* this hover on the link changes the nested span's left value to auto */ .linkparent1 span { position: absolute; left: -999em; border: 1px solid white; background: #446; color: white; font-weight: bold; padding: 2px 4px; text-decoration: none; } /* tooltip may be custom styled as desired */ .linkparent1:hover { background: url(bgfix.gif); } /* Applies 1x1 transparent bgfix.gif on hover - IE hover bug fix */

Try hovering the link text and you will see the tooltip pop up directly to the right of the link text, just where it should if it were a flowed element. Notice how the AP span does not actually participate in the flow, but just covers the normal text when it appears. Only its placement is affected by the flow.

Remember that the parent doesn't have any positioning. We are using only the static position to locate our AP element, thus it doesn't matter if there are positioned ancestors or not! Only the flow is important in this situation when determining placement of that tooltip. However, if either top or left were given a length value, positioning of some ancestor would be necessary to locate the tooltip using that ancestor as a base.

This leads to a question: Can we mix auto and length positioning on one AP element? The answer is, yes we can. Just be aware that an auto value doesn't require a positioned ancestor and generally ignores them, while any length value applied to one of the side values will make the AP element look to a positioned ancestor for placement information. If left is set to auto while top is set to 10px, the AP element will be horizontally placed according to the flow while vertically offset 10px from the top edge of its nearest positioned ancestor.

IE bugs

See that last rule applying a simple transparent 1x1 gif to the link on hover? This is necessary for IE7 and lower because of a bug that prevents a hover on a parent from changing styles on a nested child element. For some unknown reason, simply changing certain properties on the parent during the hover makes IE behave correctly. Background changes are one of the properties that can fix the bug. Applying a transparent gif as the fix creates no visible side-effects, making it the preferred choice for the fix. In fact, just calling a non-existent gif will do the trick, but don't do that, because then some poor sys-admin will be flooded with error logs for all those calls to a gif that isn't available.

Another IE problem is that IE7 and below seem to think that any AP element controlled by auto positioning is an inline element, even when you specifically assign the display property a value of "block"! In the demo above, the span is inline and so IE's rendering agrees with other browsers, but let's try making the span a block element and see what happens:

Vestibulum lacus tellus, adipiscing in, volutpat sit amet, dictum ac, mauris. Duis euismod sapien quis tellus. Vivamus aliquam, lorem a accumsan consequat, dolor est iaculis est, nec pulvinar magna ipsum at lacus. Duis aliquam. Sed mattis. Morbi ipsum ipsum, euismod ut, scelerisque quis, faucibus et, tortor. Sed aliquam erat vel justo. Etiam lacinia, massa a ultrices pellentesque, Link text Tooltip text dolor ante sagittis nibh, eget interdum ante lectus nec est. Fusce rutrum faucibus mauris. Aliquam cursus nisl at diam. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Suspendisse leo mauris, dictum et, dignissim sed, eleifend et, dolor.

<p> Vestibulum lacus tellus, adipiscing in, volutpat sit amet, dictum ac. Duis euismod sapien quis tellus. Vivamus aliquam, lorem a accumsan consequat, dolor est iaculis est, nec pulvinar magna ipsum at lacus. Duis aliquam. Sed mattis. Morbi ipsum ipsum, euismod ut, scelerisque quis, faucibus et, tortor. Sed aliquam erat vel justo. Etiam lacinia, massa a ultrices pellentesque, <a href="#" class="linkparent2">Link text<span>Tooltip text</span></a> dolor ante sagittis nibh, eget interdum ante lectus nec est. Fusce rutrum faucibus mauris. Aliquam cursus nisl at diam. Lorem ipsum dolor sit amet. </p>   .linkparent2 { color: #a00; } .linkparent2:hover span { left: auto; } .linkparent2 span { position: absolute; left: -999em; border: 1px solid white; background: #446; color: white; font-weight: bold; padding: 2px 4px; text-decoration: none; display: block; } .linkparent2:hover { background: url(bgfix.gif); }

The two screenshots below illustrate the difference between IE and a more standard compliant browser:

Explorer 7
IE7 shows how it thinks the blocked span is still inline and keeps it on the same line.

Firefox 3
FF3 properly treats the blocked span as a block and drops it to a new line for auto placement.

The specs for block elements say that all simple block elements begin on a new line and as far to the left as possible, but clearly IE7 is just ignoring that dictum and continues to place the AP span right next to the previous text. Unfortunately there is no real fix for this, other than forcing a break in the flowed text itself to make IE look more like the other browsers. Okay, this is a pain, but in real pages this problem won't come up too often and when it does you will just have to do some kind of workaround (sigh).

Actual Uses for Static Position and AP Elements

A bit earlier I explained how you can mix auto and ancestor-based positioning for one AP element by confining one to horizontal and the other to vertical control. This knowledge leads us to a possible use for auto values on AP elements.

Imagine you have a column of text, and you create an empty space to one side where you hope to place little AP images that enhance the text. These AP images can easily be given some left or right value to locate them within a positioned div surrounding the text column and to one side of the text, but what about the vertical placement? Presumably these images should go along with certain bits of the text, but you can't control where those bits will appear vertically, because the browser has the final say when it comes to arranging text lines. What to do?

Yup, auto positioning comes to the rescue. Just insert your AP images so that they are just before or after the relevant text they are meant to illustrate, and let the top and bottom side values be auto while using some length value for either left or right (but not both). Shazzam! The vertical placement is controlled by the flow, and the horizontal placement by your length value. Sweet. I've created a live demo showing exactly this arrangement. Try increasing the text size and/or dragging the window narrower and wider to see how the AP images hug their desired text bits like magnets. The words just before the AP image tags are colored in red to clarify the situation.

One More Trick

This auto positioning is great, but it does lack precision. What if the auto placement isn't exactly where we would like it to be, what then? Any attempt to add lengths as side values will kill the auto positioning we're depending on. Luckily there is another way to move the auto-positioned AP elements around without touching the side properties, namely margins. In the next article I'll get into that subject heavily, but for now just copy the demo page and try adding negative or positive margins to the sides of the AP images. I guarantee you will get interesting results!

Until next time...