Thursday, June 26th, 2008

YUI Autogrid: Correctly resize the grids

Category: CSS, Yahoo!

>Our own Christian Heilmann has created a new JavaScript library Autogrid that marries YUI Grids, the base CSS library, to allow for smart resizing:

I love YUI Grids. I know my CSS and I know how to work around diff erent problems of browsers, but I am also very much bored about having to fix and test and create these workarounds over and over again. While YUI Grids might not be perfect for all cases of web development out there, I am happy to take a pragmatic approach and just create sites that can be done with them (now you also know why I am not a designer).

One problem I keep having when I put some YUI Grids-based sites live is that people complain about me expecting a certain screen resolution or viewport size. YUI grids can either be 100% wide, which can be pretty silly on high resolutions, or optimized for resolutions of either 800×600 or 1024×768. When you optimize for 800 pixels people on higher resolutions will complain about the length of the page and when you go for 1024 people will say they have to scroll to see your side-bar on 800×600. You can’t win.

Or can you? CSS is not dynamic — it has a fixed state and you can only hope that the browser does the right thing with what you give it (well, there are conditional comments for IE, but technically they are HTML, and of course there are media queries in CSS3 and other goodies, but for the sake of the argument let’s say supporting IE6 is a base). JavaScript, on the other hand, is very dynamic and you can read out and check what is happening to the browser currently in use and react to it.

Putting this feature of JavaScript to good use you can create a YUI-Grids-based layout that remains flexible and changes according to needs. All you need to do is use some YUI Dom magic and change IDs and classes accordingly.

Christian has a demonstration page, and the full code:

javascript
< view plain text >
  1. YAHOO.example.autoGrid = function(){
  2.   var container = YAHOO.util.Dom.get('doc') ||
  3.                   YAHOO.util.Dom.get('doc2') ||
  4.                   YAHOO.util.Dom.get('doc4') ||
  5.                   YAHOO.util.Dom.get('doc3') ||
  6.                   YAHOO.util.Dom.get('doc-custom');
  7.   if(container){
  8.     var sidebar = null;
  9.     var classes = container.className;
  10.     if(classes.match(/yui-t[1-3]|yui-left/)){
  11.        var sidebar = 'left';
  12.     }
  13.     if(classes.match(/yui-t[4-6]|yui-right/)){
  14.        var sidebar = 'right';
  15.     }
  16.     function switchGrid(){
  17.       var currentWidth = YAHOO.util.Dom.getViewportWidth();
  18.       if(currentWidth > 950){
  19.         container.id = 'doc2';
  20.         if(sidebar){
  21.           container.className = sidebar === 'left' ? 'yui-t3' : 'yui-t6';
  22.         }
  23.       }
  24.       if(currentWidth < 950){
  25.         container.id = 'doc';
  26.         if(sidebar){
  27.           container.className = sidebar === 'left' ? 'yui-t2' : 'yui-t5';
  28.         }
  29.       }
  30.       if(currentWidth < 760){
  31.         container.id = 'doc3';
  32.         if(sidebar){
  33.           container.className = sidebar === 'left' ? 'yui-t1' : 'yui-t4';
  34.         }
  35.       }
  36.       if(currentWidth < 600){
  37.         container.id = 'doc3';
  38.         container.className = '';
  39.       }
  40.     };
  41.     switchGrid();
  42.     /*
  43.       Throttle by Nicholas Zakas to work around MSIE's resize nasties.
  44.       http://www.nczonline.net/blog/2007/11/30/the_throttle_function
  45.     */
  46.     function throttle(method, scope) {
  47.       clearTimeout(method._tId);
  48.         method._tId= setTimeout(function(){
  49.         method.call(scope);
  50.       }, 100);
  51.     };
  52.     YAHOO.util.Event.on(window,'resize',function(){
  53.       throttle(YAHOO.example.autoGrid.switch,window);
  54.     });
  55.  
  56.   };
  57.   return {
  58.     switch:switchGrid
  59.   };
  60. }();

We continue to see JavaScript libraries working with CSS to great effect.

Posted by Dion Almaer at 8:01 am
9 Comments

++---
2.9 rating from 27 votes

9 Comments »

Comments feed TrackBack URI

A problem with layouts that change size is that it’s hard to optimize the graphics for the pages. For example, if you assume an 800px wide browser you’ll create the graphics small enough to fit that size. Make the size of the layout wider and the image looks puny.

Optimize your images for a 1000px layout and then shrink its width and you get images that push out the side of your column (or other similar problems).

Comment by newz2000 — June 26, 2008

@newz2000 yes, that is a problem. You can do a lot with tiling background images horizontally though. And by not creating rounded corners with images but let IE have normal corners and use CSS :)

Comment by Chris Heilmann — June 26, 2008

We’ve been using this technique for a little while but using jQuery/YUI Grids. It works okay but is not without problems. Designing different sized images is a bit of a pain. We’re probably going to turn it off and stick to 1024 for the next release to allow us to concentrate on developing functionality without worrying about two different layouts.

Comment by mikenolan — June 26, 2008

if(classes.match(/yui-t[4-6]|yui-right/)){}

Can be replaced with:
if(Dom.hasClass(container, “yui-t[4-6]|yui-right”))
Where Dom is YAHOO.util.Dom.

Further down, I see:- container.className = sidebar === ‘left’ ? ‘yui-t3′ : ‘yui-t6′;
- and then:-
container.className = ”.
For general purpose javascript, it is a good idea to be polite about the className attribute by removing only the classes relevant to the script.

This will have the benefit of using the className cache built into YAHOO.util.Dom that Matt seems to have borrowed from me (sans credit).

This will also have the benefit of better accuracy,for className attribute rules (the “(?:^|\\s)” + token + “(?:\\s|$)”. The down side is that Dom.hasClass does not guarantee how it is implemented, so it could change and passing in a pattern would not work anymore. APE.dom.hasToken, on the other hand, uses a more generic approach. Method hasToken is guaranteed to search for a string token and that can contain RegExp syntax that will be cached (the original source for the caching concept that I wrote).

YAHOO.util.Dom -> lookup can be reduced to
var Dom = YAHOO.util.Dom, which will be further reduced with a compressor. It can shave milliseconds off time execution speed (barely), and can reduce download size (only slightly in this example).

It might be a good idea to add constants for the measurements. This can be passed in typical config style of YUI. A conig could have a docId prefix.

The scope argument ought to be renamed, as it deals with context, or thisArg for call. It is not an actual scope.

Comment by dhtmlkitchen — June 26, 2008

So it’s back to table based layouts for all of us. Ah, the flexibility of tables (layout-wise, not code-wise).

Comment by Jordan — June 26, 2008

@dhtmlkitchen all good points. The code is also Open Source, so feel free to change that.

The accuracy of the class checking can be surely much improved, however I took this pragmatic approach as this only is meant to work with YUI grids and I’d never use any other class on the main container element than the one defining the columns, just for readability.

As to constants, maybe, however I find the request to simulate a mediaqueries style syntax for this much more interesting.

Comment by Chris Heilmann — June 27, 2008

@dhtmlkitchen as to the performance differences: this code is executed once on initial rendering, so I’d opt for readabillity rather than trying to shave off milliseconds that nobody misses.

Comment by Chris Heilmann — June 27, 2008

@Jordan you are very much missing the point here. Whoever wishes the time of layout tables back should also get IE4 and Netscape 4.07 and 4.5 back. Get over it, tables for layout are a hack and still advocating them means you haven’t understood that HTML is structure and semantic meaning and not painting by numbers.

Comment by Chris Heilmann — June 27, 2008

@dhtmlkitchen
Garrett,

The caching approach we use to optimized dynamic regular expressions is the culmination of a discussion that took place on an internal mailing list.

If you feel that this or any other source code has not been correctly attributed, please contact us directly and we will take every step to ensure that proper credit is given when due.

Comment by MattSweeney — June 27, 2008

Leave a comment

You must be logged in to post a comment.