RobG wrote:
<snip>
// For browsers that support getComputedStyle (Mozilla et al)
if (window.getComputedStyle) {
c = document.defaultView.getComputedStyle(a,
'').getPropertyValue('color');
<snip>
There is a logical inconstancy in feature testing for -
window.getComputedStyle - and then using
document.defaultView.getComputedStyle. It is not uncommon and seems to
have its origins in implementations decisions that are true in
Mozilla/Gecko and Opera 7+, but not necessarily true in other
environments.
The W3C DOM Views specification says that the - DocumentView -
interface will be implemented by the document object, and will have a -
defaultView - property that is a reference to an object implementing the
AbstractView - interface. As the - AbstractView - interface only has one
property defined in DOM Views and that property is - document -,
referring to the document object, it may be convenient for an
implementation to regard the global object as suitably implementing
the - AbstractView - interface (as it already has a - document -
property) but the W3C specification does not require that. And, for
example, IceBrowser 5 fully implements the W3C DOM Views specification
but its - document.defaultView - property does not refer to the global
object (merely an object that implements the required interface, as
called for by the spec).
As the W3C DOM Style specification states that it is the object
implementing the - AbstractView - interface that will implement the -
getComputedStyle - method (where supported) the only W3C DOM conforming
method of accessing that method is through the - defalutView - property
of the document. Assuming that - AbstractView - equals - window - would
be writing to proprietary implementations _not_ the specification and
will cause problems with at least some DOM standard browsers.
But probably more important is to strictly adhere to the feature
detecting principal that a feature detecting test should have (as near
as practical) a one-to-one relationship to the feature that is to be
used. So if the feature in question is the - getComputedStyle - method
of the - AbstractView - interface referred to by the - defaultView -
property of the document, then that should be the subject of the test,
not a method of the window object. (Or, assuming that there is a reason
for abandoning support for DOM standard browsers and just following a
couple of known implementations, if the test is for the method of the
window then it is the method of the window object that the code should
be employing).
While we are on the subject of computed styles; the - getPropertyValue
- method of the - CSSStyleDeclaration - implementing object that is
returned by a call to - getComputedStyle - has proved problematic on
recent Konqueror (and so probably also Safari) versions. Because,
instead of returning just the value assigned (as a string), it returns
the equivalent of the full style declaration. So, given -
border-top-width:2px; -, while other browsers would return just '2px'
from - getPropertyValue -, Konqueror (and so probably Safari) returns "
border-top-width:2px;". This renders the common practice of passing the
returned string through - parseInt/Float - ineffective as it means that
NaN will invariable be returned instead of a useful value.
This is not as much of a problem as a superficial examination might
suggest because the W3C DOM Style specification allows for the
extraction of style information in a very exact form, and Konqueror
supports the required interfaces. Instead of using - getPropertyValue -
you can use - getPropertyCSSValue - to acquire a reference to an object
implementing the - CSSValue - interface. An interface that provides
methods that give precise value information in a standard form.
Dimensions, for example, may be extracted using the - getFloatValue -
method, and will be of numeric type (no need for string to number
conversion).
This can be particularly useful when the value of interest is a color as
the - RGBColor - interface is standard while color values returned
form - getPropertyValue - may take any of a number of valid CSS forms
depending on the browser.
The problem with - getPropertyCSSValue - is that it is not universally
implemented. Opera 7, for example, does not implement it, leaving no
choice but to fall back to - getPropertyValue. But I have found that
preferring - getPropertyCSSValue - and then falling back to -
getPropertyValue - gives the widest support available and avoids issues
with Konqueror/Safari.
It is probably unfair to encourage you into using the CSSValue interface
without a working demonstration so the following is some test code that
I wrote for computed styles in web browsers. It shows what is available
from the computed style objects on various browsers. The instructions
are in the text:-
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html lang="en"><head><title></title>
<script type="text/javascript">
var InitializeMe = (function(){
var global = this;
var base = null;
var safe = false;
var listenerType = (global.addEventListener && 2)||
(global.attachEvent && 3)|| 0;
function getStackFunc(next, funcRef, arg1,arg2,arg3,arg4){
function l(ev){
funcRef((ev?ev:global.event), arg1,arg2,arg3,arg4);
if(next)next = next(ev);
return (funcRef = null);
};
l.addItem = function(d){
if(next){
next.addItem(d);
}else{
next = d;
}
};
return l;
};
return (function(funcRef, arg1,arg2,arg3,arg4){
if(base){
base.addItem(getStackFunc(null, funcRef, arg1,arg2,arg3,arg4));
}else{
base = getStackFunc(null, funcRef, arg1,arg2,arg3,arg4);
}
if(!safe){
switch(listenerType){
case 2:
global.addEventListener("load", base, false);
safe = true;
break;
case 3:
global.attachEvent("onload", base);
safe = true;
break;
default:
if(global.onload != base){
if(global.onload){
base.addItem(getStackFunc(null, global.onload));
}
global.onload = base;
}
break;
}
}
});
})();
function doMouseDown(ev){
var target, indent = '\n';
var text = '';
ev = ev||global.event;
if(ev.shiftKey){
target = ev.target||ev.srcElement;
if(target){
text += getComputedCSSInfo(target);
if(typeof target.offsetWidth == 'number'){
text += indent + 'target.offsetWidth == '+target.offsetWidth;
text += indent + 'target.offsetHeight == '+target.offsetHeight;
text += indent + 'target.offsetLeft == '+target.offsetLeft;
text += indent + 'target.offsetTop == '+target.offsetTop;
}
if(typeof target.clientWidth == 'number'){
text += indent + 'target.clientWidth == '+target.clientWidth;
text += indent + 'target.clientHeight == '+target.clientHeight;
text += indent + 'target.clientLeft == '+target.clientLeft;
text += indent + 'target.clientTop == '+target.clientTop;
}
if(typeof target.scrollWidth == 'number'){
text += indent + 'target.scrollWidth == '+target.scrollWidth;
text += indent + 'target.scrollHeight == '+target.scrollHeight;
text += indent + 'target.scrollLeft == '+target.scrollLeft;
text += indent + 'target.scrollTop == '+target.scrollTop;
}
}else{
text += 'No target';
}
frmEl.t.value = text;
return false;
}
}
InitializeMe(function(){
frmEl = document.forms.f.elements;
document.onmousedown = doMouseDown;
});
var frmEl;
var global = this;
function getComputedCSSInfo(element){
var indent = '\n';
var temp,cs,defaultView,text = '';
if(element){
if(element.tagName){
text += '<'+element.tagName+'>\n';
}else if(element.nodeName){
text += 'Node Name == ['+element.nodeName+']\n';
}
if(element.nodeType){
text += 'Node Type == '+nodeType_names[element.nodeType]+'\n';
}
if(element.id){
text += 'ID == \"'+element.id+'\"\n';
}
if(element.className){
text += 'className == \"'+element.className+'\"\n';
}
if(
(defaultView = document.defaultView)&&
(defaultView.getComputedStyle) &&
(cs = defaultView.getComputedStyle(element, null))
){
for(var c = 0;c < CSSProprety_names.length;c++){
temp = cs.getPropertyValue(CSSProprety_names[c]);
if(typeof temp != 'undefined'){
text += indent + 'String value from - getPropertyValue(\''+
CSSProprety_names[c]+'\') == \"'+temp+'\"';
}
temp = cs[CSSStyleProperties_names[c]];
if(typeof temp != 'undefined'){
text += indent +
(typeof temp) +
' value from - computedStyleObject.'+
CSSStyleProperties_names[c]+' == \"'+temp+'\"';
}
if( cs.getPropertyCSSValue){
temp = cs.getPropertyCSSValue(CSSProprety_names[c]);
if(temp){
text += indent +
'CSSValue object from - getPropertyCSSValue(\''+
CSSProprety_names[c]+'\') == ';
text += CSSValueReport(temp, (indent+'\t'));
}
}
if(typeof temp != 'undefined'){text += indent;}
}
}else if(element.currentStyle){
for(var c = 0;c < CSSStyleProperties_names.length;c++){
temp = element.currentStyle[CSSStyleProperties_names[c]];
if(typeof temp != 'undefined'){
text += indent +
'String value from - element.currentStyle.'+
CSSStyleProperties_names[c]+' == \"'+temp+'\"';
text += indent;
}
}
}
}
return text;
}
function CSSValueReport(cssValue, indent){
var type = cssValue.cssValueType;
var st = indent+'CSSValue Type == '+type+' -> '+
(CSSValueType_names[type]||'not a specified type');
switch(type){
case 0: //CSS_INHERIT
st += indent+'The value is inherited : data == '+
cssValue.cssText;
break;
case 1: //CSS_PRIMITIVE_VALUE
st += CSSPrimativeReport(cssValue, (indent+'\t'));
break;
case 2: //CSS_VALUE_LIST
for(var c = 0;c < cssValue.length;c++){
st += indent+'Item == '+c;
st += CSSValueReport(cssValue.item(c), (indent+'\t'));
}
break;
case 3: //CSS_CUSTOM
st += indent+'The value is a custom value : data == '+
cssValue.cssText;
break;
default:
break;
}
return st;
}
function CSSPrimativeReport(cssValue, indent){
var temp,type = cssValue.primitiveType;
var st = indent+'CSSPrimitiveValue Type == '+type+' -> '+
(CSSPrimativeType_names[type]||'not a specified type');
switch(type){
case 0: //CSS_UNKNOWN
st += indent+
'Value is not a recognized CSS2 value: data == '+
cssValue.cssText;
break;
case 18: //CSS_DIMENSION
case 1: //CSS_NUMBER
case 2: //CSS_PERCENTAGE
case 3: //CSS_EMS
case 4: //CSS_EXS
case 5: //CSS_PX
case 6: //CSS_CM
case 7: //CSS_MM
case 8: //CSS_IN
case 9: //CSS_PT
case 10: //CSS_PC
st += indent+'Float value is == '+
cssValue.getFloatValue(type);
st += tryLengthConversion(cssValue, (indent+'\t'));
break;
case 11: //CSS_DEG
case 12: //CSS_RAD
case 13: //CSS_GRAD
case 14: //CSS_MS
case 15: //CSS_S
case 16: //CSS_HZ
case 17: //CSS_KHZ
st += indent+'Float value is == '+
cssValue.getFloatValue(type);
st += tryOtherConversion(cssValue, (indent+'\t'));
break;
case 19: //CSS_STRING
case 20: //CSS_URI
case 21: //CSS_IDENT
case 22: //CSS_ATTR
st += indent+'String value is == \"'+
cssValue.getStringValue()+'\"';
break;
case 23: //CSS_COUNTER
temp = cssValue.getCounterValue();
st += indent+'Counter.identifier == '+temp.identifier;
st += indent+'Counter.listStyle == '+temp.listStyle;
st += indent+'Counter.separator == '+temp.separator;
break;
case 24: //CSS_RECT
temp = cssValue.getRectValue();
st += indent+'Rect.top == '+
CSSPrimativeReport(temp.top, (indent+'\t'));
st += indent+'Rect.left == '+
CSSPrimativeReport(temp.left, (indent+'\t'));
st += indent+'Rect.bottom == '+
CSSPrimativeReport(temp.bottom, (indent+'\t'));
st += indent+'Rect.rigth == '+
CSSPrimativeReport(temp.right, (indent+'\t'));
break;
case 25: //CSS_RGBCOLOR
temp = cssValue.getRGBColorValue();
st += indent+'RGBColor.red == '+
CSSPrimativeReport(temp.red, (indent+'\t'));
st += indent+'RGBColor.green == '+
CSSPrimativeReport(temp.green, (indent+'\t'));
st += indent+'RGBColor.blue == '+
CSSPrimativeReport(temp.blue, (indent+'\t'));
break;
default:
break;
}
return st;
}
function tryLengthConversion(cssValue, indent){
var temp,type = cssValue.primitiveType;
var st = indent+'Length Values -> ';
try{ //CSS_NUMBER
st += indent+'CSS_NUMBER value == '+cssValue.getFloatValue(1);
}catch(e){
st += indent+'Cannot Convert to CSS_NUMBER (exception)';
}
try{ //CSS_PERCENTAGE
st += indent+'CSS_PERCENTAGE value == '+
cssValue.getFloatValue(2);
}catch(e){
st += indent+'Cannot Convert to CSS_PERCENTAGE (exception)';
}
try{ //CSS_EMS
st += indent+'CSS_EMS value == '+ cssValue.getFloatValue(3);
}catch(e){
st += indent+'Cannot Convert to CSS_EMS (exception)';
}
try{ //CSS_EXS
st += indent+'CSS_EXS value == '+ cssValue.getFloatValue(4);
}catch(e){
st += indent+'Cannot Convert to CSS_EXS (exception)';
}
try{ //CSS_PX
st += indent+'CSS_PX value == '+ cssValue.getFloatValue(5);
}catch(e){
st += indent+'Cannot Convert to CSS_PX (exception)';
}
try{ //CSS_CM
st += indent+'CSS_CM value == '+ cssValue.getFloatValue(6);
}catch(e){
st += indent+'Cannot Convert to CSS_CM (exception)';
}
try{ //CSS_MM
st += indent+'CSS_MM value == '+ cssValue.getFloatValue(7);
}catch(e){
st += indent+'Cannot Convert to CSS_MM (exception)';
}
try{ //CSS_IN
st += indent+'CSS_IN value == '+ cssValue.getFloatValue(8);
}catch(e){
st += indent+'Cannot Convert to CSS_IN (exception)';
}
try{ //CSS_PT
st += indent+'CSS_PT value == '+ cssValue.getFloatValue(9);
}catch(e){
st += indent+'Cannot Convert to CSS_PT (exception)';
}
try{ //CSS_PC
st += indent+'CSS_PC value == '+ cssValue.getFloatValue(10);
}catch(e){
st += indent+'Cannot Convert to CSS_PC (exception)';
}
return st;
}
function tryOtherConversion(cssValue, indent){
var temp,type = cssValue.primitiveType;
var st = indent+'Values -> ';
try{ //CSS_DEG
st += indent+'CSS_DEG value == '+ cssValue.getFloatValue(11);
}catch(e){
st += indent+'Cannot Convert to CSS_DEG (exception)';
}
try{ //CSS_RAD
st += indent+'CSS_RAD value == '+ cssValue.getFloatValue(12);
}catch(e){
st += indent+'Cannot Convert to CSS_RAD (exception)';
}
try{ //CSS_GRAD
st += indent+'CSS_GRAD value == '+ cssValue.getFloatValue(13);
}catch(e){
st += indent+'Cannot Convert to CSS_GRAD (exception)';
}
try{ //CSS_MS
st += indent+'CSS_MS value == '+ cssValue.getFloatValue(14);
}catch(e){
st += indent+'Cannot Convert to CSS_MS (exception)';
}
try{ //CSS_S
st += indent+'CSS_S value == '+ cssValue.getFloatValue(15);
}catch(e){
st += indent+'Cannot Convert to CSS_S (exception)';
}
try{ //CSS_HZ
st += indent+'CSS_HZ value == '+ cssValue.getFloatValue(16);
}catch(e){
st += indent+'Cannot Convert to CSS_HZ (exception)';
}
try{ //CSS_KHZ
st += indent+'CSS_KHZ value == '+ cssValue.getFloatValue(17);
}catch(e){
st += indent+'Cannot Convert to CSS_KHZ (exception)';
}
return st;
}
var CSSValueType_names = ['CSS_INHERIT','CSS_PRIMITIVE_VALUE',
'CSS_VALUE_LIST','CSS_CUSTOM'];
var CSSPrimativeType_names = [
'CSS_UNKNOWN','CSS_NUMBER',
'CSS_PERCENTAGE','CSS_EMS','CSS_EXS','CSS_PX','CSS _CM','CSS_MM',
'CSS_IN','CSS_PT','CSS_PC','CSS_DEG','CSS_RAD','CS S_GRAD',
'CSS_MS','CSS_S','CSS_HZ','CSS_KHZ','CSS_DIMENSION ','CSS_STRING',
'CSS_URI','CSS_IDENT','CSS_ATTR','CSS_COUNTER','CS S_RECT',
'CSS_RGBCOLOR'];
var CSSProprety_names = [
'azimuth','background','background-attachment','background-color',
'background-image','background-position','background-repeat',
'border','border-collapse','border-color','border-spacing',
'border-style','border-top','border-right','border-bottom',
'border-left','border-top-color','border-right-color',
'border-bottom-color','border-left-color','border-top-style',
'border-right-style','border-bottom-style','border-left-style',
'border-top-width','border-right-width','border-bottom-width',
'border-left-width','border-width','bottom','caption-side',
'clear','clip','color','content','counter-increment',
'counter-reset','cue','cue-after','cue-before','cursor',
'direction','display','elevation','empty-cells','float','font',
'font-family','font-size','font-size-adjust','font-stretch',
'font-style','font-variant','font-weight','height','left',
'letter-spacing','line-height','list-style','list-style-image',
'list-style-position','list-style-type','margin','margin-top',
'margin-right','margin-bottom','margin-left','marker-offset',
'marks','max-height','max-width','min-height','min-width',
'orphans','outline','outline-color','outline-style',
'outline-width','overflow','padding','padding-top',
'padding-right','padding-bottom','padding-left','page',
'page-break-after','page-break-before','page-break-inside',
'pause','pause-after','pause-before','pitch','pitch-range',
'play-during','position','quotes','richness','right','si ze',
'speak','speak-header','speak-numeral','speak-punctuation',
'speech-rate','stress','table-layout','text-align',
'text-decoration','text-indent','text-shadow','text-transform',
'top','unicode-bidi','vertical-align','visibility','voice-family',
'volume','white-space','widows','width','word-spacing','z-index'
];
var CSSStyleProperties_names = [
'azimuth','background','backgroundAttachment','bac kgroundColor',
'backgroundImage','backgroundPosition','background Repeat','border',
'borderCollapse','borderColor','borderSpacing','bo rderStyle',
'borderTop','borderRight','borderBottom','borderLe ft',
'borderTopColor','borderRightColor','borderBottomC olor',
'borderLeftColor','borderTopStyle','borderRightSty le',
'borderBottomStyle','borderLeftStyle','borderTopWi dth',
'borderRightWidth','borderBottomWidth','borderLeft Width',
'borderWidth','bottom','captionSide','clear','clip ',
'color','content','counterIncrement','counterReset ',
'cue','cueAfter','cueBefore','cursor','direction', 'display',
'elevation','emptyCells','cssFloat','font','fontFa mily',
'fontSize','fontSizeAdjust','fontStretch','fontSty le','fontVariant',
'fontWeight','height','left','letterSpacing','line Height',
'listStyle','listStyleImage','listStylePosition',' listStyleType',
'margin','marginTop','marginRight','marginBottom', 'marginLeft',
'markerOffset','marks','maxHeight','maxWidth','min Height',
'minWidth','orphans','outline','outlineColor','out lineStyle',
'outlineWidth','overflow','padding','paddingTop',' paddingRight',
'paddingBottom','paddingLeft','page','pageBreakAft er',
'pageBreakBefore','pageBreakInside','pause','pause After',
'pauseBefore','pitch','pitchRange','playDuring','p osition',
'quotes','richness','right','size','speak','speakH eader',
'speakNumeral','speakPunctuation','speechRate','st ress',
'tableLayout','textAlign','textDecoration','textIn dent',
'textShadow','textTransform','top','unicodeBidi',' verticalAlign',
'visibility','voiceFamily','volume','whiteSpace',' widows',
'width','wordSpacing','zIndex'
];
var nodeType_names = ['','ELEMENT_NODE','ATTRIBUTE_NODE','TEXT_NODE',
'CDATA_SECTION_NODE','ENTITY_REFERENCE_NODE','ENTI TY_NODE',
'PROCESSING_INSTRUCTION_NODE','COMMENT_NODE','DOCU MENT_NODE',
'DOCUMENT_TYPE_NODE','DOCUMENT_FRAGMENT_NODE','NOT ATION_NODE'
];
</script>
</head>
<body>
<p>
Place some HTML mark-up here and then click on elements while holding
the shift key down. Do not remove or alter the following form/textarea
as they are used for output.
</p>
<form action="" name="f">
<div>
<textarea cols="95"rows="44" name="t"></textarea>
</div>
</form>
</div>
</body>
</html>
Richard.