opacity

D

Darko

Hi,

I'm trying to get and set an element's opacity, but I'm stuck with,
what a hell of surprise, Internet Explorer. As for getting the
element's opacity, I have the following (not working) lines of code:

if ( targetObject.filters && targetObject.filters.length > 0 )
opacity =
targetObject.filters.item("DXImageTransform.Microsoft.Alpha").Opacity;

Setting it, I tried:

if ( targetObject.filters && targetObject.filters.length > 0 )
targetObject.setAttribute( "style", "filter: alpha(opacity=" +
opacity + ")" );

None work. I have digged these out from some MSDN article, but they
aren't working, at least they don't work in to me available IE 6.0. Do
you have better (i.e. working) ways of yours?

Thanks

Darko
 
S

Stevo

Darko said:
I'm trying to get and set an element's opacity, but I'm stuck with,
what a hell of surprise, Internet Explorer. As for getting the
element's opacity, I have the following (not working) lines of code:

I don't know what was wrong there, but I see you think that opacity is
only available for IE. There's an equivalent feature in Mozilla browsers
using custom CSS properties. You'll have to sniff for the browsers and
branch your code to handle it (totally) differently, but it's definitely
possible. Not that I've ever used it, but I have seen itt.
 
V

VK

As for getting the
element's opacity, I have the following (not working) lines of code:

if ( targetObject.filters && targetObject.filters.length > 0 )
opacity =
targetObject.filters.item("DXImageTransform.Microsoft.Alpha").Opacity;

Setting it, I tried:

if ( targetObject.filters && targetObject.filters.length > 0 )
targetObject.setAttribute( "style", "filter: alpha(opacity=" +
opacity + ")" );

None work. I have digged these out from some MSDN article

Do you still remember which one?
but they
aren't working, at least they don't work in to me available IE 6.0.

Of course they don't: setAttribute method has nothing to do with it.
Do you have better (i.e. working) ways of yours?

Not mine, but tested working:

http://www.quirksmode.org/js/opacity.html
 
T

Thomas 'PointedEars' Lahn

VK said:
Do you still remember which one?

Probably
http://msdn2.microsoft.com/en-us/library/ms532847.aspx#Scripting_Filters or
a previous version.
Of course they don't: setAttribute method has nothing to do with it.

To be precise, setAttribute() does not seem to work there *for IE*.

However, it does not make sense in passing ranges from 0 to 10 and then
computing the required value twice. With the division for `opacity', there
is even a rounding error involved, needlessly. It makes more sense have
`value' range from 0 to 1 (thereby to pass the percentage x% as 0.0x to the
function); the computation will have to be done only once (for `filter'),
and the used values will be as exact as the layout engine allows it:

function setOpacity(value)
{
testObj.style.opacity = value;
testObj.style.filter = 'alpha(opacity=' + value * 100 + ')';
}


PointedEars
 
D

dhtmlkitchen

Hi,

I'm trying to get and set an element's opacity, but I'm stuck with,
what a hell of surprise, Internet Explorer. As for getting the
element's opacity, I have the following (not working) lines of code:

if ( targetObject.filters && targetObject.filters.length > 0 )
opacity =
targetObject.filters.item("DXImageTransform.Microsoft.Alpha").Opacity;

Setting it, I tried:

if ( targetObject.filters && targetObject.filters.length > 0 )
targetObject.setAttribute( "style", "filter: alpha(opacity=" +
opacity + ")" );

None work. I have digged these out from some MSDN article, but they
aren't working, at least they don't work in to me available IE 6.0. Do
you have better (i.e. working) ways of yours?

Does the element have a layout? In IE terms, it's gotta have position
or height/width for proprietary hasLayout to be be true.

DXImageTransform can work for background images, too, but doesn't let
you set any other background-properties (like background-position).

Regarding other comments on this thread: Opacity is CSS3, not a moz-
specific css. it works in Mozilla, Webkit and Opera.

Garrett
 
D

Darko

I don't know what was wrong there, but I see you think that opacity is
only available for IE. There's an equivalent feature in Mozilla browsers
using custom CSS properties. You'll have to sniff for the browsers and
branch your code to handle it (totally) differently, but it's definitely
possible. Not that I've ever used it, but I have seen itt.

No, I don't think that. I use "opacity" regularly for other browsers,
but
it doesn't work with IE. So I googled out that IE needs this filter
thing,
which they claim works by accessing .filters subobject, but it seems
as if it
does not. So I gave up and did as it was only possible, using
..style.filter = ..., which I like less than the proposed solution from
MSDN
(which doesn't work). Never mind.
 
D

Darko

Hi,

I'm trying to get and set an element's opacity, but I'm stuck with,
what a hell of surprise, Internet Explorer. As for getting the
element's opacity, I have the following (not working) lines of code:

if ( targetObject.filters && targetObject.filters.length > 0 )
opacity =
targetObject.filters.item("DXImageTransform.Microsoft.Alpha").Opacity;

Setting it, I tried:

if ( targetObject.filters && targetObject.filters.length > 0 )
targetObject.setAttribute( "style", "filter: alpha(opacity=" +
opacity + ")" );

None work. I have digged these out from some MSDN article, but they
aren't working, at least they don't work in to me available IE 6.0. Do
you have better (i.e. working) ways of yours?

Thanks

Darko

As for opacity, now that I gave in and had it .style.filter = "...",
it finally
works well with IE, too. Another problem though - Konqueror. It seems
to ignore:
opacity
-moz-opacity
-khtml-opacity
filter

Wtf. does it need? Does Konqueror actually support element's opacity?
I wouldn't mind
the bloody Konqueror not working properly with my site, but as I
understand Safari uses
the same KHTML engine, so I reckon if Konqueror doesn't work (as it
doesn't), then Safari
won't neither. Am I right? Or Safari uses a KHTML branch that actually
supports the standard?

Thanks
 
T

Thomas 'PointedEars' Lahn

Does the element have a layout? In IE terms, it's gotta have position
or height/width for proprietary hasLayout to be be true.

The issue is not that the element has "no layout" which you could
have figured out by now. And nobody mentioned `hasLayout' (whatever
that might be) until now.
DXImageTransform can work for background images, too,

I have to see that before I believe it.
but doesn't let you set any other background-properties (like
background-position).

You are probably describing the following PNGA workaround for IE 6:

#portal-logo {
background: none;
filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true,
sizingMethod=scale src='bannertop_right.png');
}

In which case the background image is *disabled* in order to apply the
filter. The result is not a real background image.

Please learn to quote.


PointedEars
 
P

Peter Michaux

David Mark posted his code for setting opacity

<URL http://groups.google.com/group/comp..._frm/thread/792457773ca7cf01/4763865f827f7605>

and with his subsequent corrections I believe he intended to post the
following


var global = this;
var setOpacity = (function() {
var i, l, html;
var doc = global.document;
var opacityStyles = ['opacity', 'MozOpacity', 'KhtmlOpacity'];

if (doc) {
html = (doc.all[0].tagName == '!')?doc.all[1]:doc.all[0];
if (!html && doc.all && doc.all[0]) {
html = (doc.all[0].tagName == '!')?doc.all[0]:doc.all[1];
}
}
if (html && html.style) {
if (typeof html.style.filter != 'undefined') {
return function(el, o) {
var f;
if (el.filters) {
if (el.currentStyle && !el.currentStyle.hasLayout) {
el.style.zoom = 1;
}
f = el.filters.alpha;
if (typeof(f) != 'undefined') {
if (o == 1) {
f.enabled = false;
}
else {
f.enabled = true;
f.opacity = o * 100;
}
}
else {
if (el.style && typeof(el.style.filter) != 'undefined') {
el.style.filter += "alpha(opacity=" + (o * 100) + ")";
}
}
}
};
}
i = 0;
l = opacityStyles.length;
while (i < l) {
if (typeof(html.style[opacityStyles]) == 'string') {
return (function(s) {
return function(el, o) {
el.style = o;
};
})(opacityStyles);
}
i++;
}
}

})();


I don't know what is trying to be accomplished with this part which
doesn't work in Firefox as document.all is not available. Is this a
way to get the document.documentElement object?

if (doc) {
html = (doc.all[0].tagName == '!')?doc.all[1]:doc.all[0];
if (!html && doc.all && doc.all[0]) {
html = (doc.all[0].tagName == '!')?doc.all[0]:doc.all[1];
}
}


--------------------------------------------

The code I have been using is the following

function setOpacity(el, val) {

// If "val" is very small then when converted to a string
// may will use scientific notation. This is not allowed in CSS.
// For example, in Firefox 1.5
// (0.0000001).toString() --> "1e-7"
if (val<0.00001) {
val = 0;
}

var s = el.style;

if (typeof s.filter == 'string') {

s.filter = s.filter.replace(/alpha\([^\)]*\)/gi,'') +
((val < 1) ? 'alpha(opacity='+val*100+')' : '');

// alpha opacity only applies if the element "has layout".
// IE4 has alpha but does not have currentStyle
if (!el.currentStyle ||
//IE 5+ can determine if element "has layout"
!el.currentStyle.hasLayout) {
// setting zoom is one of the ways to insure
// an element "has layout"
el.style.zoom = 1;
}
} else {
// if (early release edition of Firefox && val === 1) {
// // This trick is from Scriptaculous
// // Some version of Firefox (before 1.5?) flickers
// // when animating opacity up to a value of 1.
// // If this trick is to be used the test will probably be
// // expensive and should only be preformed the first time.
// //
// // Apparently using this trick increases the weight of
// // the DOM, for rendering speed?
//
// val = 0.999999;
// }

// Mac/Firefox-1.5, Mac/Opera-9, Mac/Safari-2,
// Win/NetscapeNavigator-8.0, KDE4/Konqueror
s.opacity = val;
// Win/NetscapeNavigator 6.0/7.0/8.0, Mac/Firefox-1.5
s.MozOpacity = val;
// -khtml-opacity does not apply to any version of Konqueror
// according to the
// folks on irc.freenode.net#kde. I set up some tests and
// one person ran them on
// development versions of KDE 4 and this is not supported
// Konqueror for KDE 4
// will be the first Konqueror version to support opacity
// settings.
// These KDE folks also told me that it was Safari 1.1 that
// supported the
// property below. I don't have anything less then 1.3
// anymore and have only tested
// on 2.0 so far. This does not work with Safari 2.0
s.KhtmlOpacity = val; // TODO some net sources have KHTMLOpacity
// YUI had this and I don't think it would work since
// their -moz-opacity didn't work
//s['-khtml-opacity'] = val;
}
}


Peter
 
D

dmark

David Mark posted his code for settingopacity

<URLhttp://groups.google.com/group/comp.lang.javascript/browse_frm/thread...>

and with his subsequent corrections I believe he intended to post the
following

var global = this;
var setOpacity = (function() {
var i, l, html;
var doc = global.document;
var opacityStyles = ['opacity', 'MozOpacity', 'KhtmlOpacity'];

if (doc) {
html = (doc.all[0].tagName == '!')?doc.all[1]:doc.all[0];
if (!html && doc.all && doc.all[0]) {
html = (doc.all[0].tagName == '!')?doc.all[0]:doc.all[1];
}
}
if (html && html.style) {
if (typeof html.style.filter != 'undefined') {
return function(el, o) {
var f;
if (el.filters) {
if (el.currentStyle && !el.currentStyle.hasLayout) {
el.style.zoom = 1;
}
f = el.filters.alpha;
if (typeof(f) != 'undefined') {
if (o == 1) {
f.enabled = false;
}
else {
f.enabled = true;
f.opacity= o * 100;
}
}
else {
if (el.style && typeof(el.style.filter) != 'undefined') {
el.style.filter += "alpha(opacity=" + (o * 100) + ")";
}
}
}
};
}
i = 0;
l = opacityStyles.length;
while (i < l) {
if (typeof(html.style[opacityStyles]) == 'string') {
return (function(s) {
return function(el, o) {
el.style = o;
};
})(opacityStyles);
}
i++;
}
}

})();

I don't know what is trying to be accomplished with this part which
doesn't work in Firefox as document.all is not available. Is this a
way to get the document.documentElement object?


There appears to be a missing line from this transcription:

html = (doc.getElementsByTagName)?doc.getElementsByTagName('html')
[0]:doc.documentElement;


And since I posted that, I updated the function to deal with an IE5
DirectX incompatibility. I just updated it again to deal with the
float to string issue you mention in your version, as well as to force
the layout fix for IE4. I haven't tested the updated version.

setOpacity = (function(el) {
var i, l;
var reOpacity = new RegExp('alpha\\(opacity=[^\\)]+\\)', 'i');
var opacityStyles = ['opacity', 'MozOpacity', 'KhtmlOpacity'];
if (typeof el.style.filter == 'string') {
return function(el, o) {
var f;
if (el.filters) {
if (!el.currentStyle || !el.currentStyle.hasLayout)
{ el.style.zoom = 1; }
f = el.filters.alpha;
if (typeof(f) != 'undefined') {
f.enabled = o != 1;
f.opacity = o * 100;
}
else {
if (el.style.filter.indexOf('alpha(opacity=') == -1) {
el.style.filter = 'alpha(opacity=' + (o * 100) + ')';
}
else {
el.style.filter = el.style.filter.replace(reOpacity,
"alpha(opacity=" + (o * 100) + ")");
}
}
}
};
}
i = 0;
l = opacityStyles.length;
while (i < l) {
if (typeof(el.style[opacityStyles]) == 'string') {
return (function(s) { return function(el, o) { el.style = (o < .
00001)?0:eek:; }; })(opacityStyles);
}
i++;
}
})(html);

The html variable passed to the one-off function is defined by a
dependant function, which calls other dependant functions, etc., so I
won't post that, but in a nutshell: try the documentElement, then try
getElementsByTagName if it is a feature of the document object, then
try doc.all.tags('html'). Otherwise, you are out of luck as there is
nothing to test with and you shouldn't run the above code at all.
if (doc) {
html = (doc.all[0].tagName == '!')?doc.all[1]:doc.all[0];
if (!html && doc.all && doc.all[0]) {
html = (doc.all[0].tagName == '!')?doc.all[0]:doc.all[1];
}

This was a silly way to get around doc.all returning the docType
declaration. I had forgotten all about the tags method of the all
object.
}

--------------------------------------------

The code I have been using is the following

function setOpacity(el, val) {

// If "val" is very small then when converted to a string
// may will use scientific notation. This is not allowed in CSS.
// For example, in Firefox 1.5
// (0.0000001).toString() --> "1e-7"
if (val<0.00001) {
val = 0;
}

var s = el.style;

if (typeof s.filter == 'string') {

s.filter = s.filter.replace(/alpha\([^\)]*\)/gi,'') +
((val < 1) ? 'alpha(opacity='+val*100+')' : '');

// alphaopacityonly applies if the element "has layout".
// IE4 has alpha but does not have currentStyle
if (!el.currentStyle ||
//IE 5+ can determine if element "has layout"
!el.currentStyle.hasLayout) {
// setting zoom is one of the ways to insure
// an element "has layout"

It's the best way I know to do it.
el.style.zoom = 1;
}
} else {
// if (early release edition of Firefox && val === 1) {
// // This trick is from Scriptaculous
// // Some version of Firefox (before 1.5?) flickers

I've seen this recently. It drove me to distraction while I was
working on a special effects module. I don't think it was an early
release though. I am pretty sure it was the latest major release.
// // when animatingopacityup to a value of 1.
// // If this trick is to be used the test will probably be
// // expensive and should only be preformed the first time.
// //
// // Apparently using this trick increases the weight of
// // the DOM, for rendering speed?

I am not sure what that means, but as I recall, setting .999999
instead of 1 makes no visible difference, other than to eliminate the
annoying flicker.
//
// val = 0.999999;
// }

// Mac/Firefox-1.5, Mac/Opera-9, Mac/Safari-2,
// Win/NetscapeNavigator-8.0, KDE4/Konqueror
s.opacity= val;
// Win/NetscapeNavigator 6.0/7.0/8.0, Mac/Firefox-1.5
s.MozOpacity = val;
// -khtml-opacitydoes not apply to any version of Konqueror
// according to the
// folks on irc.freenode.net#kde. I set up some tests and
// one person ran them on
// development versions of KDE 4 and this is not supported
// Konqueror for KDE 4
// will be the first Konqueror version to supportopacity
// settings.
// These KDE folks also told me that it was Safari 1.1 that
// supported the
// property below. I don't have anything less then 1.3
// anymore and have only tested
// on 2.0 so far. This does not work with Safari 2.0
s.KhtmlOpacity = val; // TODO some net sources have KHTMLOpacity

I can't help verify the original opacity code was written five or six
years ago and I can't remember if I ever tested it with Safari back
then. I have tested recently with Windows Safari, but I am pretty
sure it used the standard opacity style. That being said,
KHTMLOpacity just looks wrong to me.
// YUI had this and I don't think it would work since
// their -moz-opacitydidn't work
//s['-khtml-opacity'] = val;

Clearly YUI is wrong in both cases.
 
P

Peter Michaux

[snip]

And since I posted that, I updated the function to deal with an IE5
DirectX incompatibility.

What is that and what part of your code relates to this problem?

[code below slightly reformatted to avoid wrapping]
I just updated it again to deal with the
float to string issue you mention in your version, as well as to force
the layout fix for IE4. I haven't tested the updated version.

setOpacity = (function(el) {

var i,l;
var reOpacity = new RegExp('alpha\\(opacity=[^\\)]+\\)', 'i');
var opacityStyles = ['opacity', 'MozOpacity', 'KhtmlOpacity'];

if (typeof el.style.filter == 'string') {

return function(el, o) {

var f;

if (el.filters) {
if (!el.currentStyle || !el.currentStyle.hasLayout) {
el.style.zoom = 1;
}

f = el.filters.alpha;

if (typeof(f) != 'undefined') {
f.enabled = o != 1;
f.opacity = o * 100;
}
else {
if (el.style.filter.indexOf('alpha(opacity=') == -1) {
el.style.filter = 'alpha(opacity=' + (o * 100) + ')';
}
else {
el.style.filter = el.style.filter.replace(reOpacity,
"alpha(opacity=" + (o * 100) + ")");
}
}

What is the benefit of the above if-else with the first f.enabled/
f.opacity branch? It is quite a bit of code bulk. Do you know of a
browser with el.filters that will not work with the else branch above?

Instead of the above 13 lines, in my version, I just write the
following

s.filter = s.filter.replace(/alpha\([^\)]*\)/gi,'') +
((val < 1) ? 'alpha(opacity='+val*100+')' : '');

}
};

}

i = 0;

l = opacityStyles.length;

while (i < l) {
if (typeof(el.style[opacityStyles]) == 'string') {
return (function(s) {
return function(el, o) {
el.style = (o < .00001)?0:eek:;
};
})(opacityStyles);
}
i++;
}

})(html);

The html variable passed to the one-off function is defined by a
dependant function, which calls other dependant functions, etc., so I
won't post that, but in a nutshell: try the documentElement, then try
getElementsByTagName if it is a feature of the document object, then
try doc.all.tags('html'). Otherwise, you are out of luck as there is
nothing to test with and you shouldn't run the above code at all.


I can see that checking for document.documentElement and then falling
back to document.all.tags('html')[0] is beneficial as IE4 can set
opacity but doesn't have document.documentElement; however, what
browser is enabled by adding a check with getElementsByTagName into
the mix? I tested a bunch of browsers around the correct vintage and
didn't find one where adding the getElementsByTagName check helps. I
can see having the getElementsByTagName check for completeness but do
you happen to know of a browser where this check is the one that works
and document.documentElement and document.all.tags('html')[0] both
don't work?

Opera 5.02
document.documentElement // undefined
document.getElementsByTagName // undefined
document.all.tags('html').length // 0
document.all.tags('body').length // 1

Opera 6.0
document.documentElement // undefined
document.getElementsByTagName('html').length // 0
document.getElementsByTagName('body').length // 1
document.all.tags('html').length // 0
document.all.tags('body').length // 1

Opera 7.02
document.documentElement // [object HTMLHtmlElement]
document.getElementsByTagName('html').length // 1
document.getElementsByTagName('body').length // 1
document.all.tags('html').length // 0
document.all.tags('body').length // 1

Opera 8.0
document.documentElement // [object HTMLHtmlElement]
document.getElementsByTagName('html').length // 1
document.getElementsByTagName('body').length // 1
document.all.tags('html').length // 1
document.all.tags('body').length // 1

IE 4
document.documentElement // undefined
document.getElementsByTagName // undefined
document.all.tags('html').length // 1

IE 5.0
document.documentElement // [Object]
document.getElementsByTagName('html').length // 1
document.all.tags('html').length // 1

NN4.0 & NN4.08 & NN4.5
document.documentElement // undefined
document.getElementsByTagName // undefined
document.all // undefined

NN6.0
document.documentElement // [object HTMLHtmlElement]
document.getElementsByTagName('html').length // 1
document.all // undefined


if (doc) {
html = (doc.all[0].tagName == '!')?doc.all[1]:doc.all[0];
if (!html && doc.all && doc.all[0]) {
html = (doc.all[0].tagName == '!')?doc.all[0]:doc.all[1];
}

This was a silly way to get around doc.all returning the docType
declaration. I had forgotten all about the tags method of the all
object.

I didn't even know about it.


[snip]
I've seen this recently. It drove me to distraction while I was
working on a special effects module. I don't think it was an early
release though. I am pretty sure it was the latest major release.

I've never managed to make it flicker on any version.

I am not sure what that means, but as I recall, setting .999999
instead of 1 makes no visible difference, other than to eliminate the
annoying flicker.

Someone told me or I read that by setting several elements with
opacity makes the DOM "heavier". I can only assume they mean it takes
longer to render or that it takes more RAM or something like that. The
idea of limiting this 0.99999 trick to only the versions of FF that
need it was to avoid adding this "weight" to browsers that don't need
the trick. The importance given to this "weight" issue sounded a
little like flaky to me.

I can't help verify the original opacity code was written five or six
years ago and I can't remember if I ever tested it with Safari back
then. I have tested recently with Windows Safari, but I am pretty
sure it used the standard opacity style. That being said,
KHTMLOpacity just looks wrong to me.


I have personally tested opacity on Safari 1.0 and Safari 1.2+. Safari
1.0 does not support any opacity setting, as far as I could tell.
Safari 1.2 and up supports the standard CSS "opacity" and no option
related to any string with "khtml" in any case. By process of
elimination,Safari 1.1 must be the browser that had this khtml opacity
business. I cannot find a built copy of this version and have not been
able to test it.

I chatted with the folks on IRC freenode#webkit (users proton and
bdash, in particular) and they had some helpful information...

On the following page you can see which webkit build goes with which
svn repository tag goes with which version of Safari

http://developer.apple.com/internet/safari/uamatrix.html

Safari 1.1 has the "Safari-100" build and the approriate bit of code
is a function called "jsNameToProp"

<URL: http://trac.webkit.org/projects/webkit/browser/tags/Safari-100/WebCore/khtml/ecma/kjs_css.cpp#L34>

static QString jsNameToProp( const Identifier &p )
{
QString prop = p.qstring();
int i = prop.length();
while( --i ) {
char c = prop.latin1();
if ( c < 'A' || c > 'Z' )
continue;
prop.insert( i, '-' );
}

return prop.lower();
}

A '-' character will be inserted before any capital letter and then
the whole string is lowercased. So "KhtmlOpacity" will be converted to
"-khtml-opacity". This is the desired output.

------------------

The confusion comes later in Safari-110 when "jsNameToProp" is
replaced with "cssPropertyName". The new "cssPropertyName" function
will convert both "KhtmlOpacity" and "khtmlOpacity" to "-khtml-
opacity"

<URL: http://trac.webkit.org/projects/webkit/browser/tags/Safari-110/WebCore/khtml/ecma/kjs_css.cpp#L34>

static QString cssPropertyName(const Identifier &p, bool
*hadPixelOrPosPrefix = 0)
{
QString prop = p.qstring();

int i = prop.length();
while (--i) {
char c = prop.latin1();
if (c >= 'A' && c <= 'Z')
prop.insert(i, '-');
}

prop = prop.lower();

if (hadPixelOrPosPrefix)
*hadPixelOrPosPrefix = false;

if (prop.startsWith("css-")) {
prop = prop.mid(4);
} else if (prop.startsWith("pixel-")) {
prop = prop.mid(6);
if (hadPixelOrPosPrefix)
*hadPixelOrPosPrefix = true;
} else if (prop.startsWith("pos-")) {
prop = prop.mid(4);
if (hadPixelOrPosPrefix)
*hadPixelOrPosPrefix = true;
} else if (prop.startsWith("khtml-")) {
prop.insert(0, '-');
}

return prop;
}


In conclusion (without testing), the most backwards compatible option
is to use "KhtmlOpacity" and I really think open source software is
cool.

[snip]

On the Quirksmode site it states that opacity cannot be set on tbody
and tr elements in many browsers. So just because the setOpacity
function is defined in a particular browser based on analysis of the
<html> element, it doesn't mean that setting opacity on any element
will "just work".

Cross browser opacity setting is just so much fun! :-S

Peter
 
D

David Mark

[snip]

And since I posted that, I updated the function to deal with an IE5
DirectX incompatibility.

What is that and what part of your code relates to this problem?

[code below slightly reformatted to avoid wrapping]


el.style.filter += 'alpha(opacity=' + (o * 100) + ')';

This was incorrectly posted as:

el.style.filter = 'alpha(opacity=' + (o * 100) + ')';

If you don't check first, IE5 will tack that on over and over as that
browser never creates the el.filters.alpha property. The regex was
added to update the filter property in IE5.
I just updated it again to deal with the
float to string issue you mention in your version, as well as to force
the layout fix for IE4. I haven't tested the updated version.
setOpacity = (function(el) {
var i,l;
var reOpacity = new RegExp('alpha\\(opacity=[^\\)]+\\)', 'i');
var opacityStyles = ['opacity', 'MozOpacity', 'KhtmlOpacity'];
if (typeof el.style.filter == 'string') {
return function(el, o) {
if (el.filters) {
if (!el.currentStyle || !el.currentStyle.hasLayout) {
el.style.zoom = 1;
}
f = el.filters.alpha;
if (typeof(f) != 'undefined') {
f.enabled = o != 1;
f.opacity = o * 100;
}
else {
if (el.style.filter.indexOf('alpha(opacity=') == -1) {
el.style.filter = 'alpha(opacity=' + (o * 100) + ')';
}
else {
el.style.filter = el.style.filter.replace(reOpacity,
"alpha(opacity=" + (o * 100) + ")");
}
}

What is the benefit of the above if-else with the first f.enabled/
f.opacity branch? It is quite a bit of code bulk. Do you know of a
browser with el.filters that will not work with the else branch above?

The first branch is cleaner and faster. You don't want to get into
string concatenation and/or regex manipulation unless it is necessary
(the first time for each element in IE6/7 and every time in IE5.)
That being said, it looks like the else branch could be tightened up a
bit in terms of size. No need to figure the opacity filter string in
two different places.
Instead of the above 13 lines, in my version, I just write the
following

s.filter = s.filter.replace(/alpha\([^\)]*\)/gi,'') +
((val < 1) ? 'alpha(opacity='+val*100+')' : '');

Smaller in size, but slower in IE6/7. I think this is as small as it
gets without compromising performance:

f = el.filters.alpha;
if (f) {
f.enabled = o != 1; // IE screws up some fonts when filter is left
enabled
f.opacity = o * 100; // This has got to be faster than string
concatenation
}
else { // IE6/7 never get here unless an opacity has never been set
s = 'alpha(opacity=' + (o * 100) + ')';
if (reOpacity.test(el.style.filter)) { // IE5 every time
el.style.filter = el.style.filter.replace(reOpacity, s);
}
else { // IE6/7 once
el.style.filter += s;
}
}

}
};

i = 0;
l = opacityStyles.length;
while (i < l) {
if (typeof(el.style[opacityStyles]) == 'string') {
return (function(s) {
return function(el, o) {
el.style = (o < .00001)?0:eek:;
};
})(opacityStyles);
}
i++;
}
})(html);

The html variable passed to the one-off function is defined by a
dependant function, which calls other dependant functions, etc., so I
won't post that, but in a nutshell: try the documentElement, then try
getElementsByTagName if it is a feature of the document object, then
try doc.all.tags('html'). Otherwise, you are out of luck as there is
nothing to test with and you shouldn't run the above code at all.


I can see that checking for document.documentElement and then falling
back to document.all.tags('html')[0] is beneficial as IE4 can set
opacity but doesn't have document.documentElement; however, what
browser is enabled by adding a check with getElementsByTagName into
the mix? I tested a bunch of browsers around the correct vintage and
didn't find one where adding the getElementsByTagName check helps. I
can see having the getElementsByTagName check for completeness but do
you happen to know of a browser where this check is the one that works
and document.documentElement and document.all.tags('html')[0] both
don't work?


It would have to be a browser without document.documentElement and
with gEBTN. No idea is such an animal exists.
Opera 5.02
document.documentElement // undefined
document.getElementsByTagName // undefined
document.all.tags('html').length // 0

That's odd.
document.all.tags('body').length // 1

Opera 6.0
document.documentElement // undefined
document.getElementsByTagName('html').length // 0

So is that.
document.getElementsByTagName('body').length // 1
document.all.tags('html').length // 0

And that. I realize Opera 5/6 were lousy browsers, but how could they
dispute the existence of at least one HTML element? Do these support
opacity? If so, and you really want to support them, then defer the
feature test until the body element is parsed and pass it to the one-
off. I do that for some things that don't need to be used until the
document is ready.
document.all.tags('body').length // 1

Opera 7.02
document.documentElement // [object HTMLHtmlElement]
document.getElementsByTagName('html').length // 1
document.getElementsByTagName('body').length // 1
document.all.tags('html').length // 0
Stupid.

document.all.tags('body').length // 1

Opera 8.0
document.documentElement // [object HTMLHtmlElement]
document.getElementsByTagName('html').length // 1
document.getElementsByTagName('body').length // 1
document.all.tags('html').length // 1
document.all.tags('body').length // 1

IE 4
document.documentElement // undefined
document.getElementsByTagName // undefined
document.all.tags('html').length // 1

That's really the case I was thinking of when I added the document.all
check.
IE 5.0
document.documentElement // [Object]
document.getElementsByTagName('html').length // 1
document.all.tags('html').length // 1

NN4.0 & NN4.08 & NN4.5
document.documentElement // undefined
document.getElementsByTagName // undefined
document.all // undefined

Never mind these.
NN6.0
document.documentElement // [object HTMLHtmlElement]
document.getElementsByTagName('html').length // 1
document.all // undefined
if (doc) {
html = (doc.all[0].tagName == '!')?doc.all[1]:doc.all[0];
if (!html && doc.all && doc.all[0]) {
html = (doc.all[0].tagName == '!')?doc.all[0]:doc.all[1];
}
This was a silly way to get around doc.all returning the docType
declaration. I had forgotten all about the tags method of the all
object.

I didn't even know about it.

[snip]
I've seen this recently. It drove me to distraction while I was
working on a special effects module. I don't think it was an early
release though. I am pretty sure it was the latest major release.

I've never managed to make it flicker on any version.

It only seems to happen when animating the opacity with a timer and
only when starting from 1. Start from .99999 or whatever and it goes
away. I eventually changed the timing of something and got it worked
out of my effects module without resorting to the .99999 hack.
Someone told me or I read that by setting several elements with
opacity makes the DOM "heavier". I can only assume they mean it takes
longer to render or that it takes more RAM or something like that. The
idea of limiting this 0.99999 trick to only the versions of FF that
need it was to avoid adding this "weight" to browsers that don't need
the trick. The importance given to this "weight" issue sounded a
little like flaky to me.

I think it does take a little more work to render a semi-transparent
element, but the idea of using .999999 in lieu of 1 is silly.
I can't help verify the original opacity code was written five or six
years ago and I can't remember if I ever tested it with Safari back
then. I have tested recently with Windows Safari, but I am pretty
sure it used the standard opacity style. That being said,
KHTMLOpacity just looks wrong to me.

I have personally tested opacity on Safari 1.0 and Safari 1.2+. Safari
1.0 does not support any opacity setting, as far as I could tell.
Safari 1.2 and up supports the standard CSS "opacity" and no option
related to any string with "khtml" in any case. By process of
elimination,Safari 1.1 must be the browser that had this khtml opacity
business. I cannot find a built copy of this version and have not been
able to test it.

I chatted with the folks on IRC freenode#webkit (users proton and
bdash, in particular) and they had some helpful information...

On the following page you can see which webkit build goes with which
svn repository tag goes with which version of Safari

http://developer.apple.com/internet/safari/uamatrix.html

Safari 1.1 has the "Safari-100" build and the approriate bit of code
is a function called "jsNameToProp"

<URL:http://trac.webkit.org/projects/webkit/browser/tags/Safari-100/WebCor...>

static QString jsNameToProp( const Identifier &p )
{
QString prop = p.qstring();
int i = prop.length();
while( --i ) {
char c = prop.latin1();
if ( c < 'A' || c > 'Z' )
continue;
prop.insert( i, '-' );
}

return prop.lower();

}

A '-' character will be inserted before any capital letter and then
the whole string is lowercased. So "KhtmlOpacity" will be converted to
"-khtml-opacity". This is the desired output.


I thought that was the right one.
------------------

The confusion comes later in Safari-110 when "jsNameToProp" is
replaced with "cssPropertyName". The new "cssPropertyName" function
will convert both "KhtmlOpacity" and "khtmlOpacity" to "-khtml-
opacity"

<URL:http://trac.webkit.org/projects/webkit/browser/tags/Safari-110/WebCor...>

static QString cssPropertyName(const Identifier &p, bool
*hadPixelOrPosPrefix = 0)
{
QString prop = p.qstring();
[snip]

In conclusion (without testing), the most backwards compatible option
is to use "KhtmlOpacity" and I really think open source software is
cool.
[snip]


On the Quirksmode site it states that opacity cannot be set on tbody
and tr elements in many browsers. So just because the setOpacity
function is defined in a particular browser based on analysis of the
<html> element, it doesn't mean that setting opacity on any element
will "just work".

For the most part it does. Doing it for table rows or groups of table
rows would seem an odd thing to do anyway. Add a disclaimer about
table rows at the top and you are done. Feel free to add it to your
repository.
Cross browser opacity setting is just so much fun! :-S

It's a picnic compared to some things.
 
D

David Mark

[snip]

A couple other notes.

The original stand-alone version tested for the existence of the style
object. The recently posted version comes from a module that checks
that elsewhere. So that check should be added.

And seeing that Opera 5/6 refuse to find the html element using gEBTN
or the all object, I updated my code to use the previously posted
check of all[0] and all[1] if the html variable cannot be set any
other way. That branch will only run for Opera 5/6 or antiquated
mobile browsers and is only a couple of extra lines. It is a moot
point for this example if Opera 5/6 do not support opacity, but the
function that finds the html element is crucial for lots of other
feature tests (at least if they are to be run in the head of the
document.)

If this is to be added to your repository, it would be a good
foundation for it and other style-related code to have functions that
find the html element for a given document and determine if the host
is capable of CSS manipulation by testing for the presence of the
element's style object.
 
P

Peter Michaux

On Dec 4, 12:17 am, (e-mail address removed) wrote:
[snip]
I've never managed to make it flicker on any version.

It only seems to happen when animating the opacity with a timer and
only when starting from 1. Start from .99999 or whatever and it goes
away. I eventually changed the timing of something and got it worked
out of my effects module without resorting to the .99999 hack.
Someone told me or I read that by setting several elements with
opacity makes the DOM "heavier". I can only assume they mean it takes
longer to render or that it takes more RAM or something like that. The
idea of limiting this 0.99999 trick to only the versions of FF that
need it was to avoid adding this "weight" to browsers that don't need
the trick. The importance given to this "weight" issue sounded a
little like flaky to me.

I think it does take a little more work to render a semi-transparent
element, but the idea of using .999999 in lieu of 1 is silly.

I believe the flicker issue included animating from an opacity below 1
up to 1 in which case the animation needed to stop before 1. I can't
say this is silly.

[snip]
For the most part it does. Doing it for table rows or groups of table
rows would seem an odd thing to do anyway. Add a disclaimer about
table rows at the top and you are done. Feel free to add it to your
repository.

I'm starting a branch for opacity. I think it will serve as a good
first DHTML example.

Peter
 
P

Peter Michaux

[snip]

A couple other notes.

The original stand-alone version tested for the existence of the style
object. The recently posted version comes from a module that checks
that elsewhere. So that check should be added.

And seeing that Opera 5/6 refuse to find the html element using gEBTN
or the all object, I updated my code to use the previously posted
check of all[0] and all[1] if the html variable cannot be set any
other way. That branch will only run for Opera 5/6 or antiquated
mobile browsers and is only a couple of extra lines. It is a moot
point for this example if Opera 5/6 do not support opacity, but the
function that finds the html element is crucial for lots of other
feature tests (at least if they are to be run in the head of the
document.)

If this is to be added to your repository, it would be a good
foundation for it and other style-related code to have functions that
find the html element for a given document and determine if the host
is capable of CSS manipulation by testing for the presence of the
element's style object.

Would you mind posting your function that finds the html element?

Peter
 
D

David Mark

A couple other notes.
The original stand-alone version tested for the existence of the style
object. The recently posted version comes from a module that checks
that elsewhere. So that check should be added.
And seeing that Opera 5/6 refuse to find the html element using gEBTN
or the all object, I updated my code to use the previously posted
check of all[0] and all[1] if the html variable cannot be set any
other way. That branch will only run for Opera 5/6 or antiquated
mobile browsers and is only a couple of extra lines. It is a moot
point for this example if Opera 5/6 do not support opacity, but the
function that finds the html element is crucial for lots of other
feature tests (at least if they are to be run in the head of the
document.)
If this is to be added to your repository, it would be a good
foundation for it and other style-related code to have functions that
find the html element for a given document and determine if the host
is capable of CSS manipulation by testing for the presence of the
element's style object.

Would you mind posting your function that finds the html element?

Peter- Hide quoted text -

- Show quoted text -

Okay. I just updated it this morning and haven't had time to test it
thoroughly.

var doc = this.document;

var isRealObject = function(o) {
return !!(o && typeof(o) == 'object');
};

var htmlElement = function(docNode) {
var html;
docNode = docNode || doc;
html = isRealObject(docNode.documentElement)?docNode.documentElement:
(documentElementsByTagName)?documentElementsByTagName('html', docNode)
[0]:null);
if (!html && docNode.all && docNode.all[0]) {
html = docNode.all[(docNode.all[0].tagName == '!')?1:0] || null;
if (html && html.tagName.toLowerCase() != 'html') { html = null; }
}
return html;
};

The missing documentElementsByTagName function is a wrapper for gEBTN
that only exists if the document object features such a method. It
exists to smooth out problems with the "*" parameter, as well as using
the all object for agents that don't feature gEBTN. It isn't really
needed now that the additional clause has been added to handle Opera
5/6, so you should just change it to doc.getElementsByTagName. And if
you are wondering why these are created with variable assignments, it
is because they create object methods in the original code.
 
P

Peter Michaux

[snip]
A couple other notes.
The original stand-alone version tested for the existence of the style
object. The recently posted version comes from a module that checks
that elsewhere. So that check should be added.
And seeing that Opera 5/6 refuse to find the html element using gEBTN
or the all object, I updated my code to use the previously posted
check of all[0] and all[1] if the html variable cannot be set any
other way. That branch will only run for Opera 5/6 or antiquated
mobile browsers and is only a couple of extra lines. It is a moot
point for this example if Opera 5/6 do not support opacity, but the
function that finds the html element is crucial for lots of other
feature tests (at least if they are to be run in the head of the
document.)
If this is to be added to your repository, it would be a good
foundation for it and other style-related code to have functions that
find the html element for a given document and determine if the host
is capable of CSS manipulation by testing for the presence of the
element's style object.
Would you mind posting your function that finds the html element?


Okay. I just updated it this morning and haven't had time to test it
thoroughly.

var doc = this.document;

var isRealObject = function(o) {
return !!(o && typeof(o) == 'object');

};

var htmlElement = function(docNode) {
var html;
docNode = docNode || doc;
html = isRealObject(docNode.documentElement)

If docNode.documentElement is defined, will it ever be any type other
than 'object'? It seems like checking this is unnecessary if there has
never been a known problem.
?docNode.documentElement:
(documentElementsByTagName)?documentElementsByTagName('html', docNode)

If documentElementsByTagName may be undefined then the above ternary
conditional will error in browsers where it is undefined. I think it
should be

(typeof documentElementsByTagName != 'undefined')?
documentElementsByTagName('html', docNode)


[0]:null);
if (!html && docNode.all && docNode.all[0]) {
html = docNode.all[(docNode.all[0].tagName == '!')?1:0] || null;
if (html && html.tagName.toLowerCase() != 'html') { html = null; }
}
return html;

};

The missing documentElementsByTagName function is a wrapper for gEBTN
that only exists if the document object features such a method. It
exists to smooth out problems with the "*" parameter, as well as using
the all object for agents that don't feature gEBTN. It isn't really
needed now that the additional clause has been added to handle Opera
5/6, so you should just change it to doc.getElementsByTagName.

When I looked at document.documentElement, document.all.tags and
document.getElementsByTagName, I stated that in IE4
document.all.tags('html').length is 1. That is only true after
window.onload fires. Before window.onload the length is 0. Since
feature testing is preferably done in the head right when the script
loads, the document.all.tags check isn't really enabling any
particular browsers, as far as I know. This goes along with your "It
isn't really needed now...."

Of the browsers I checked that can set opacity, only IE4 and Opera 6-
don't have document.documentElement. I don't mind degrading those
browsers to not use opacity setting. This would make the setOpacity
and all other functions requiring an element for feature testing not
dependent on an htmlElement function like you've outlined. In my eyes,
that is a nice reduction in code size. Code always might contain bugs
and needs testing as we have seen even here (not meant as criticism
but as an argument to reduce code size where reasonable). I think that
only checking for document.documentElement is a reasonable place to
draw the line in browser history given the approximate distribution of
browser version in use today. Any non-trivial CSS that may need the
fallbacks in the htmlElement function for a feature tests likely won't
work in IE4 anyway. Sound reasonable?

As a reference for this threshold, I don't wrap document.all and
document.getElementById together in a function. I just check for
document.getElementById.

[snip]

Peter
 
D

David Mark

[snip]
A couple other notes.
The original stand-alone version tested for the existence of the style
object. The recently posted version comes from a module that checks
that elsewhere. So that check should be added.
And seeing that Opera 5/6 refuse to find the html element using gEBTN
or the all object, I updated my code to use the previously posted
check of all[0] and all[1] if the html variable cannot be set any
other way. That branch will only run for Opera 5/6 or antiquated
mobile browsers and is only a couple of extra lines. It is a moot
point for this example if Opera 5/6 do not support opacity, but the
function that finds the html element is crucial for lots of other
feature tests (at least if they are to be run in the head of the
document.)
If this is to be added to your repository, it would be a good
foundation for it and other style-related code to have functions that
find the html element for a given document and determine if the host
is capable of CSS manipulation by testing for the presence of the
element's style object.
Would you mind posting your function that finds the html element?
Okay. I just updated it this morning and haven't had time to test it
thoroughly.
var doc = this.document;
var isRealObject = function(o) {
return !!(o && typeof(o) == 'object');

var htmlElement = function(docNode) {
var html;
docNode = docNode || doc;
html = isRealObject(docNode.documentElement)

If docNode.documentElement is defined, will it ever be any type other
than 'object'? It seems like checking this is unnecessary if there has
never been a known problem.

There is the possibility, however remote, that it could be a null
object.
If documentElementsByTagName may be undefined then the above ternary
conditional will error in browsers where it is undefined. I think it
should be

(typeof documentElementsByTagName != 'undefined')?
documentElementsByTagName('html', docNode)

If you mean that documentElementsByTagName has never been declared,
that is impossible in the context this code came from (it is a
declared variable.) It may have an undefined value, but that won't
throw an error.

[0]:null);
if (!html && docNode.all && docNode.all[0]) {
html = docNode.all[(docNode.all[0].tagName == '!')?1:0] || null;
if (html && html.tagName.toLowerCase() != 'html') { html = null; }
}
return html;

The missing documentElementsByTagName function is a wrapper for gEBTN
that only exists if the document object features such a method. It
exists to smooth out problems with the "*" parameter, as well as using
the all object for agents that don't feature gEBTN. It isn't really
needed now that the additional clause has been added to handle Opera
5/6, so you should just change it to doc.getElementsByTagName.

When I looked at document.documentElement, document.all.tags and
document.getElementsByTagName, I stated that in IE4
document.all.tags('html').length is 1. That is only true after
window.onload fires. Before window.onload the length is 0. Since
feature testing is preferably done in the head right when the script
loads, the document.all.tags check isn't really enabling any
particular browsers, as far as I know. This goes along with your "It
isn't really needed now...."

Were all of those results determined after onload? If so, I would
like to see what they look like when run in the head. Regardless, I
assume that document.all[0] is defined before the onload event fires,
so the added test should be sufficient.
Of the browsers I checked that can set opacity, only IE4 and Opera 6-
don't have document.documentElement. I don't mind degrading those
browsers to not use opacity setting. This would make the setOpacity
and all other functions requiring an element for feature testing not
dependent on an htmlElement function like you've outlined. In my eyes,

Opacity yes, but all other style-related functions? That seems
extreme. Also, there is no reason why such functions can't run after
the body has been parsed (e.g. in a real or simulated DOMContentLoaded
listener.) I do that for several functions that have to create
elements and append them to the body to detect quirks like Opera's
botched offsetLeft/Top reporting. It seems like setOpacity is
something that wouldn't be needed until the document is ready, else
how would you reliably find the element you want to fade?
that is a nice reduction in code size. Code always might contain bugs
and needs testing as we have seen even here (not meant as criticism
but as an argument to reduce code size where reasonable). I think that

Well, it turned out that it wasn't a bug, but I get your point.
only checking for document.documentElement is a reasonable place to
draw the line in browser history given the approximate distribution of
browser version in use today. Any non-trivial CSS that may need the
fallbacks in the htmlElement function for a feature tests likely won't
work in IE4 anyway. Sound reasonable?

Sort of. How would a script determine if CSS is even available when
running in IE4, Opera 6, etc.? One of the first flags I set is based
on the presence of a style object. If it doesn't exist then lots of
unneeded feature testing is skipped and style-related functions are
not created. Next I check the types of the display, visibility and
position properties of the object (typically strings, but not always)
and those three results determine which style-related modules should
be initialized. They are also referenced by applications to determine
if it is possible to hide dynamically replaced content during the page
load (i.e. if a style rule is added before the body is parsed, will it
be possible to overrule it with an inline style once the content is
replaced after parsing.) Can you confirm if IE4 can get the HTML
element via document.all[0] (or document.all[1]?) If not, can it get
any element during page load?
As a reference for this threshold, I don't wrap document.all and
document.getElementById together in a function. I just check for
document.getElementById.

I still allow for the use of document.all when gEBI isn't present, but
I did remove support for document.layers a few years back.
 
P

Peter Michaux

[snip]
A couple other notes.
The original stand-alone version tested for the existence of the style
object. The recently posted version comes from a module that checks
that elsewhere. So that check should be added.
And seeing that Opera 5/6 refuse to find the html element using gEBTN
or the all object, I updated my code to use the previously posted
check of all[0] and all[1] if the html variable cannot be set any
other way. That branch will only run for Opera 5/6 or antiquated
mobile browsers and is only a couple of extra lines. It is a moot
point for this example if Opera 5/6 do not support opacity, but the
function that finds the html element is crucial for lots of other
feature tests (at least if they are to be run in the head of the
document.)
If this is to be added to your repository, it would be a good
foundation for it and other style-related code to have functions that
find the html element for a given document and determine if the host
is capable of CSS manipulation by testing for the presence of the
element's style object.
Would you mind posting your function that finds the html element?
Okay. I just updated it this morning and haven't had time to test it
thoroughly.
var doc = this.document;
var isRealObject = function(o) {
return !!(o && typeof(o) == 'object');
};
var htmlElement = function(docNode) {
var html;
docNode = docNode || doc;
html = isRealObject(docNode.documentElement)
If docNode.documentElement is defined, will it ever be any type other
than 'object'? It seems like checking this is unnecessary if there has
never been a known problem.

There is the possibility, however remote, that it could be a null
object.

I asked about this sort of testing on c.l.js a when I was first
venturing into feature testing. I thought I'd have to test everything.
If document.getElementsById is present then I'd have to check if it
was callable before calling it. There is a chance it may not be
callable; however, since this situation has never been observed, the
general feeling was to trust is it callable until it is observed to be
not callable in at least one browser. Feature testing even when no
problems has ever been observed could balloon the feature tests to
hugely paranoid proportions.

That said, I understand you may have had the isRealObject function
around for another situation and it was just handy to use in this
case.

[snip]
[0]:null);
if (!html && docNode.all && docNode.all[0]) {
html = docNode.all[(docNode.all[0].tagName == '!')?1:0] || null;
if (html && html.tagName.toLowerCase() != 'html') { html = null; }
}
return html;
};
The missing documentElementsByTagName function is a wrapper for gEBTN
that only exists if the document object features such a method. It
exists to smooth out problems with the "*" parameter, as well as using
the all object for agents that don't feature gEBTN. It isn't really
needed now that the additional clause has been added to handle Opera
5/6, so you should just change it to doc.getElementsByTagName.
When I looked at document.documentElement, document.all.tags and
document.getElementsByTagName, I stated that in IE4
document.all.tags('html').length is 1. That is only true after
window.onload fires. Before window.onload the length is 0. Since
feature testing is preferably done in the head right when the script
loads, the document.all.tags check isn't really enabling any
particular browsers, as far as I know. This goes along with your "It
isn't really needed now...."

Were all of those results determined after onload?
Yes


If so, I would
like to see what they look like when run in the head. Regardless, I
assume that document.all[0] is defined before the onload event fires,
so the added test should be sufficient.

The added test seems to be fine in IE4 at least with the HTML page I
tested.

Opacity yes, but all other style-related functions? That seems
extreme.

Can you think of an example of a browser without
document.documentElement where style-related functions would work if
the document.all fallback is used for testing? Do the entire scripts
associated with these style-related functions work in these browsers?

Also, there is no reason why such functions can't run after
the body has been parsed (e.g. in a real or simulated DOMContentLoaded
listener.) I do that for several functions that have to create
elements and append them to the body to detect quirks like Opera's
botched offsetLeft/Top reporting. It seems like setOpacity is
something that wouldn't be needed until the document is ready, else
how would you reliably find the element you want to fade?

Since document.all[0] or document.all[1] seems to work in the head
this point may be moot.

[snip]

Sort of. How would a script determine if CSS is even available when
running in IE4, Opera 6, etc.? One of the first flags I set is based
on the presence of a style object. If it doesn't exist then lots of
unneeded feature testing is skipped and style-related functions are
not created. Next I check the types of the display, visibility and
position properties of the object (typically strings, but not always)
and those three results determine which style-related modules should
be initialized.

This is exactly the direction in which I'd like to go with this code
repository.

They are also referenced by applications to determine
if it is possible to hide dynamically replaced content during the page
load (i.e. if a style rule is added before the body is parsed, will it
be possible to overrule it with an inline style once the content is
replaced after parsing.) Can you confirm if IE4 can get the HTML
element via document.all[0] (or document.all[1]?)

It can.

If not, can it get
any element during page load?


I still allow for the use of document.all when gEBI isn't present,

How many of your pages have enabled JavaScript functionality because
of these archaic checks and how many actual visitors benefit? If there
are pages that do become enabled with these checks that would not
become enabled with the modern checks only, it still may be better
overall (faster download times, less code to maintain) to just slide
these down the degradation path given how few users benefit. They
still do get a perfectly working HTML page, after all.

I think setting the feature threshold at document.getElementById and
document.documentElement is ok today. If there is outrage over this
then the code repository could allow for the the document.all
fallbacks. I cringe a little when I type that thought. I strongly vote
we go "modern" (NN6 November 2000, IE5.5 July 2000).
but I did remove support for document.layers a few years back.

Peter
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top