About the Author: Christian Heilmann is the author of Beginning JavaScript with DOM Scripting and Ajax. He has worked in web development for almost 9 years for several agencies and .coms and is currently a lead developer at Yahoo! in England. Christian is a frequent speaker on the conference circuit in the UK and Europe; you can find some of his writing here on YUIBlog as well as on his personal blog at http://wait-till-i.com.
Every so often we have to do things as web developers that don’t quite work along with our ideals. One of them is when we’re asked to implement layout requirements that expect content or font sizes to be set in stone and not change. While this requirement is inherently flawed — this is the web, not a fixed canvas — it still crops up over and over again.
One of these problems we came across recently was that an advertising campaign had a small banner in one column of the layout and a large banner in another column. This wouldn’t be a problem, but the ads required that the banners line up on the bottom for the “wow” effect to happen. The problem is clear to anyone who ever worked in a web environment with third-party-maintained content. The following illustration shows what the main issue is:
Illustration one: There is an unknown amount of content above the banner in the middle column which makes it impossible to align the banners. See the problem on the demo page.
The right-hand column has a control above the large banner that has a fixed height and consists of images, which is why there is no problem with this one. The problem is the content above the banner in the centre of the layout. Editorial constraints allow us to keep the variability of this content in check to some degree to protect our bottom-aligned boxes; however, there remains that tricky little problem that if visitors have a larger font size, the text content in that centre box grow longer, and shift happens:
Illustration two: Increasing the font size stops the banners from being aligned on the bottom.
The first thing we tried was to use CSS to align the banners by positioning the parent node containing both ads relatively and the large banner absolutely to the bottom of it. In order to avoid overlap, we added a padding as high as the banner to the module on the right. We also needed to set a specific width to the absolutely positioned banner. This solved the issue in the case of more content being added above the smaller banner or the font size being increased.
Illustration three: Using CSS, we can keep the font resizing in check. See the CSS solution.
We were almost there, cake got rolled in, champagne bottles were at the ready but then we realized that we have another problem. What if the font size is smaller? Or even worse, what if the small banner is not displayed at all? After all, both banners are included by a third-party script we have no control over.
The first problem of smaller fonts and the large banner ending up below the smaller one could be solved by positioning the small banner absolutely to the bottom and adding padding to the container element. However, this still would mean that this padding gets applied when there is no small banner and there’d be a gap between module and banner in the right column.
We put the cake and bubbly back into the fridge and looked around what else can be used. CSS was out as a real solution as you cannot have conditionals in this language (if this is true then…). The solution was using JavaScript and the YUI Dom Collection‘s Region methods.
This little gem in the YUI allows you to read out the position and size of an element on the screen at any moment in time regardless of its positioning. Region works the same for absolutely, relatively or statically positioned elements, all it expects is the element to be available and not hidden with display:none.
With this in mind, we were able to sort out our game plan:
This works around all the issues and is a pretty short script:
YAHOO.example.fixAdPosition = function(){
var ad_one = YAHOO.util.Dom.get('adblock1');
var ad_two = YAHOO.util.Dom.get('adblock2');
if(ad_one && ad_two){
var region_one = YAHOO.util.Dom.getRegion(ad_one);
var region_two = YAHOO.util.Dom.getRegion(ad_two);
var pad = document.createElement('div');
pad.innerHTML = ' ';
var height = Math.abs(region_one.bottom - region_two.bottom);
YAHOO.util.Dom.setStyle(pad,'height',height+'px');
var toPad = (region_one.bottom < region_two.bottom) ? ad_one : ad_two;
toPad.parentNode.insertBefore(pad,toPad);
}
}();
Illustration four: Using JS and YUI region, we can cover all problem cases. See the JavaScript solution.
This fixes the problem when the page is loading. We could have gone further and added a font-resizing sniffing mechanism to re-align the banners when the font gets resized (if you want to know about font resizing and how to monitor it, check out this A List Apart article and its comments).
September 4, 2007 at 8:24 pm
Hello Chris,
Very nice solution…
I have a couple of question for you:
1. Exactly when you apply the process? (onload/onDOMReady/onAvailable/etc)
2. You mention the CSS resized method, but what happen if a image within the banner, change the size? (usually the third-party-maintained content have images without width/height defined, causing an unexpected adjustment of the image’s size during the loading process)
Also I’ll like to know if you have some trick to solve this: Suppose you have an area with a third-party-maintained content within, it which apply certain behavior on mouse over, expanding the region (ex: accordion control). How we can monitor the body’s height, or the height of a certain div?
September 5, 2007 at 5:31 am
[...] Fixing Tricky Layouts with the YUI Dom Collection. [...]
September 5, 2007 at 5:54 am
Hi Chris,
Interesting solution to a common problem. However,in Firefox 2.0.0.6 the js-solution does not seem to work. Increasing/decreasing the font size will destroy the neat alignment. Same goes for IE6. With IE7, the js-solution works as described.
September 5, 2007 at 9:13 am
Why not change the layout if it’s almost impossible to implement? Why add layers upon layers of stuff that could go wrong?
This solution might be a technical achievement, but it’s very much against KISS.
September 5, 2007 at 12:54 pm
Michal, have you read any of the start text? KISS != Online Ads. Such is life. Oh I wished it were different.
September 5, 2007 at 10:56 pm
Erik, yes, but that is not a problem. The test case of resizing the font when you are on the page is not covered as we don’t re-align when the font size changes. It is also not a real world test as someone who *needs* a larger font size will have this one set *before* arriving on the page.
September 6, 2007 at 7:12 pm
Great article, I wasn’t aware of the YUI Region tools before. Keep posting articles like this, as they provide a good working example to enable learning these tools.
September 17, 2007 at 6:41 am
[...] questo post, viene proposta una soluzione che fa uso di Javascript, attraverso l’uso di [...]
October 1, 2007 at 1:06 am
[...] Shift Happens — Fixing Tricky Layouts with the YUI Dom Collection » Yahoo! User Interfac… [...]
October 9, 2007 at 11:10 am
[...] Fixing Tricky Layouts with the YUI Dom CollectionThe requirement is to make the ad in this content column align to the bottom of the secondary ad on the right, regardless of font size (Example). Christian Heilmann delivers two solutions – a CSS-based and a JavaScript-based method. [...]
October 9, 2007 at 12:32 pm
[...] Fixing Tricky Layouts with the YUI Dom CollectionThe requirement is to make the ad in this content column align to the bottom of the secondary ad on the right, regardless of font size (Example). Christian Heilmann delivers two solutions – a CSS-based and a JavaScript-based method. [...]
October 10, 2007 at 10:42 pm
[...] Fixing Tricky Layouts with the YUI Dom CollectionThe requirement is to make the ad in this content column align to the bottom of the secondary ad on the right, regardless of font size (Example). Christian Heilmann delivers two solutions – a CSS-based and a JavaScript-based method. [...]