taming the browser with the yui dom component
DESCRIPTION
A quick introduction to the YUI Dom Component and some of its lesser known parts. This is not really *that* useful without the explanations but there will be a video later on.TRANSCRIPT
Using YUI Dom
to tame the Browser
Christian HeilmannYahoo! F2E Summit Asia 2007
Quick reminder
• Development according to web standards means first and foremost separation.
• Specifically separation of web development layers.
addClass batch generateId get getAncestorBy getAncestorByClassNamegetAncestorByTagName getChildrengetChildrenBy getClientHeightgetClientWidth getDocumentHeightgetDocumentScrollLeftgetDocumentScrollTop getDocumentWidthgetElementsBy getElementsByClassNamegetFirstChild getFirstChildBygetLastChild getLastChildBygetNextSibling getNextSiblingBygetPreviousSibling getPreviousSiblingBygetRegion getStyle getViewportHeightgetViewportWidth getX getXY getYhasClass inDocument insertAfterinsertBefore isAncestor removeClassreplaceClass setStyle setX setXY setY
Use cases for the DOM utility
• Using CSS Classes• Getting elements from the DOM • Using the browser dimensions• Using element dimensions• Styling elements
Using CSS Classes
• addClass()• removeClass()• hasClass()• replaceClass()• getElementsByClassName()
Why?
Why?
• CSS is the supercharged DOM Scripting.• CSS is much closer connected to the
HTML• Therefore it is more likely to change at the
same time.• I hate loops.
Why?
• CSS is the supercharged DOM Scripting.• CSS is much closer connected to the
HTML• Therefore it is more likely to change at the
same time.• I hate loops.
Why?
• CSS is the supercharged DOM Scripting.• CSS is much closer connected to the
HTML• Therefore it is more likely to change at the
same time.• I hate loops.
Why?
• CSS is the supercharged DOM Scripting.• CSS is much closer connected to the
HTML• Therefore it is more likely to change at the
same time.• I hate loops.
Example:
Hiding all “trigger” links in a main section when JS is available.
Example:
var main = document.getElementById('main');if(main){
var triggers = main.getElementsByTagName('a');for(var i=0,j=triggers.length;i<j;i++){
if(triggers[i].className === 'trigger'){triggers[i].style.display = 'none';
}}
}
Example:
var main = document.getElementById('main');if(main){
var triggers = main.getElementsByTagName('a');for(var i=0,j=triggers.length;i<j;i++){
if(triggers[i].className === 'trigger'){triggers[i].style.display = 'none';
} }
}
display:none is a bad plan!
Example:
var main = document.getElementById('main');if(main){
var triggers = main.getElementsByTagName('a');for(var i=0,j=triggers.length;i<j;i++){
if(triggers[i].className === 'trigger'){triggers[i].style.display = 'none';
} }
}
Off-left is better.
Example:
var main = document.getElementById('main');if(main){
var triggers = main.getElementsByTagName('a');for(var i=0,j=triggers.length;i<j;i++){
if(triggers[i].className === 'trigger'){triggers[i].style.position = 'absolute'; triggers[i].style.left = '-6000px';
} }
}
Magic JavaScript Pixy Solution
$('#main a.trigger').hide();
My fave:
document.body.className = 'js';
// or var b = document.body;var bc = b.className;b.className = bc ? bc + ' js' : 'js';
Getting elements from the DOM
• inDocument()• isAncestor()• getElementsByClassName• getElementsBy• get• batch
Using the browser dimensions
• getViewportWidth()• getViewportHeight()• getDocumentWidth()• getDocumentHeight()
Using element dimensions
• getX(), getY(), getXY()• setX(), setY(), setXY()• getRegion()
– Region union– Region intersect – Region contains
Using element dimensions
Using element dimensions
• Each of these methods can take an ID, a reference of an HTMLelement or an array of elements as the parameter.
• This allows you to easily access a lot of elements.
Using element dimensions
• The Dom utility does not care if the element is positioned absolute, relative or static.
• It also sorts out differences in render mode for you.
• However, each element needs to be part of the Dom and not hidden with display:none!
Using element dimensions
• The get and set methods of x and y are very straight forward.
• They return the left, the top or both values in pixels or an array with this data for each element you parsed in.
• You can also set the position in pixels with the setter methods.
Using element dimensions
var xy = YAHOO.util.Dom.getXY('hd');
// = [128, 0];YAHOO.util.Dom.setXY('hd',[128,-
10]);// shifts header 10 pixels up
Using element dimensions
• By using the getRegion() method you can read out the screen estate the element occupies.
• This is incredibly useful for positioning elements or avoiding overlap.
• The return is an object with several properties.
Using element dimensions
var h = YAHOO.util.Dom.getRegion('hd');
// h = // {0:128// 1:0,// top:0,// right:878, // bottom:79, // left:128}
Using element dimensions
• top, left, right, bottom are the pixel locations on the page.
• There are shortcuts for left and top named 0 and 1 to allow for compatibility with setX,setY and setXY.
Using element dimensions
• Using these properties you can also calculate the dimensions of the element.
• Simply subtract left from right for the width.• And top from bottom for the height.
Using element dimensions
• The Region() component does a lot more for you though.
• By calculating the region occupied by two elements, you can find out:– if one element contains the other – how big the area containing both of them is
and– if and where they intersect
Using element dimensions
YD = YAHOO.util.Dom;reg1 = YD.getRegion('r1');reg2 = YD.getRegion('r2');contains = reg1.contains(reg2);
Region #1 Region #2
Using element dimensions
YD = YAHOO.util.Dom;reg1 = YD.getRegion('r1');reg2 = YD.getRegion('r2');contains = reg1.contains(reg2);
false
Region #1 Region #2
Using element dimensions
YD = YAHOO.util.Dom;reg1 = YD.getRegion('r1');reg2 = YD.getRegion('r2');contains = reg1.contains(reg2);
Region #1
Region #2
Using element dimensions
YD = YAHOO.util.Dom;reg1 = YD.getRegion('r1');reg2 = YD.getRegion('r2');contains = reg1.contains(reg2);
true
Region #1
Region #2
Using element dimensions
YD = YAHOO.util.Dom;reg1 = YD.getRegion('r1');reg2 = YD.getRegion('r2');is = reg1.intersect(reg2);
Region #1
Region #2
Using element dimensions
YD = YAHOO.util.Dom;reg1 = YD.getRegion('r1');reg2 = YD.getRegion('r2');is = reg1.intersect(reg2);
Region #1
Region #2
Using element dimensions
YD = YAHOO.util.Dom;reg1 = YD.getRegion('r1');reg2 = YD.getRegion('r2');is = reg1.union(reg2);
Region #1
Region #2
Region #1
Region #2
Using element dimensions
YD = YAHOO.util.Dom;reg1 = YD.getRegion('r1');reg2 = YD.getRegion('r2');is = reg1.union(reg2);
Region #1
Region #2
Region #1
Region #2
Styling elements
• getStyle()• setStyle()
Styling Elements
• You might wonder why you’d need these two methods as seemingly element.style.property = valuewould do the same.
• The two methods however work around several browser problems and differences between computedStyle and currentStyle.
Styling Elements
• The other benefit is that you can use the CSS selector names instead of the camelCased JavaScript ones.
• Furthermore you can use the opacityproperty without needing to branch for different browsers.
CSS normalization
obj.style.marginTop = '10px';
vs.
YAHOO.util.Dom.setStyle(obj, 'margin-top','10px');
CSS normalization
• Furthermore, opacity is not a nightmare any longer:
YAHOO.util.Dom.setStyle(obj, 'opacity','.2');
CSS normalization
• And last but not least, float can be used:
YAHOO.util.Dom.setStyle(obj, 'float','left');
Thanks!