Clearing Absolutes Again
Update
A revised script that addresses the issues brought up in the comments of this post is available for discussion in Absolute Clearance.
Prompted by renewed conversation about clearing absolutely positioned elements by Eric Meyer and Mike Davidson, and a concern voiced by Simon Willison in the comments of my original post I’ve developed a revised approach to the issue.
Shortcomings of the Original Script
Previously the script I wrote required containing elements to have a specific class to indicate that they should “clear” the absolutely positioned elements inside them. On top of that, once the script ran, any resizing of text via browser controls caused the layout to either overlap in the case of enlarging the text, or spread apart when the text size was reduced. Neither limitations would be acceptable in a production environment, the first for semantic reasons and the second for accessibility/usability concerns.
Exploration
In developing this alternate approach I explored a number of options. To eliminate the inline classing of target elements I imagined setting a fictional CSS property, -si-flow: inline
together with position: absolute
to indicate a cleared absolute. Unfortunately Safari dashed that idea as it’s scripting engine remains blissfully ignorant of all but inline or scripted styles (I would love for someone to prove this statement wrong).
Look Ma, No Classes!
What developed instead was a logic that determines the positioning of child elements based on their parent element’s height. If all elements inside a parent element are absolutely positioned then the parent collapses resulting in an offsetHeight
of 0
. If one or more of the elements are absolutely positioned, then the parent element’s offsetHeight
will be less than the sum of the offsetHeight
of its children. Any element for which either case is true should be cleared by the script.
A Second Round of Exploration
Problem number one solved (for now). Solution number two proved a little more challenging to imagine but came together rather quickly after that. My first attempt assumed that there was no way to determine if the user had resized the text via a browser menu and instead focussed on capturing keypresses equating to the key commands that achieve the same effect. It was incomplete but a fair start I reasoned. That effort proved fruitless as the JavaScript engine in most browsers seemed to be ignorant of any keypresses that result in a predefined browser action.
The solution came to me while working on another problem and I stumble across the fact that the onresize
even can be triggered on “windows and objects.” Excitedly I slapped the event on an image set it’s width and height in ems and resized the text in my browser. No luck. It turns out the event only fires on the window and document objects. So what to do?
Everybody Loves iFrames
The solution to the second problem is to dynamically create an invisible iframe, set its dimensions in ems and then load into it a small document (which is admittedly malformed to conserve bandwidth) that calls the SI_clearAbsolutes()
function onresize
. Now whenever the user resizes the text, the proportions of the hidden iframe change relative to the text size and an onresize
event fires and redraws the page. Here are two examples of the revised script in action: a single instance and nested instances.
Problem Solved?
The only remaining concern is the dependence on scripting for layout. That is easily accommodated by setting a default height for elements that contain cleared absolutely positioned elements that is in excess of their potential offsetHeight
. There may be extra scrolling for those without JavaScript or with it disabled but that is more desirable than the alternative overlapping of positioned content.
011 Comments
You wiley bastard.
Yeah. What Jason said.
For some reason this approach disables the Back button. I’m using Firefox and it let’s me click the back button I just don’t go anywhere. By this I mean all means of Back. Alt-Left Arrow, right click, Go menu, etc…
I can however, pull down the Back menu and choose from there.
Baby got back?
Shaun,
You don’t need to use an IFRAME. I have been using a very similar concept with just an absolutely positioned DIV that has top set to a negative number.
Hmm, good call Michael. I didn’t consider that. But it’s not actually breaking the back button. What’s happening is that the iframe document is taking a spot in the history. You can double click the back button to get back. That’s still not acceptable. Back to the drawing board, I guess.
Care to elaborate Dimitri? In my experimentation, no other element fires an
onresize
event consistently across browser.You could play with the javascript history object and remove the last entry…
Basically, I just set up an interval check for a width (or height) of a SPAN which contains single monospace character.
Take a look at this code: glazkov.com/Resources/Code/TestFontSize … ector.html
Now, a more interesting question would be how to fire an “onresize” event on an HTMLElement in Gecko? I can do it very easily with MSIE, but Mozilla gives me a lot of grief…
If we could somehow accomplish this, it would be very easy to decouple font size change detector into its own little script.
Ah, I see Dimitri. I’d rather not have a script running in the background the entire time someone is viewing a page. It’s not economical and could have a negative impact on other scripts that might run over the course of a page view. Especially for those with slower machines. I chose this approach so that
SI_clearAbsolutes()
only runs once when required.I guess both methods offer some advantages and disadvantages…