See section 9D of the book.
Opera 8 and lower don't support the styleSheets[]
array.
On this page I try to change the background colour of a PRE, not by accessing the element directly but by changing the entire style sheet of the page. Unfortunately browser incompatibilities are so severe that this script isn't really usable in practice yet.
Please note the difference between traditional DHTML and this example script. While in DHTML you change the styles of one specific HTML element on the page (usually identified by an ID), this example changes the style sheet of the entire document.
See also the W3C DOM - CSS compatibility table.
A page contains one or more style sheets which in turn contain one or more rules which contain the actual style declarations. These are the styles in this page:
<link rel="stylesheet" href="../quirksmode.css"> <style> <!-- @import url("test.css"); p,h2,h3 { padding-right: 10px; } pre.test + * { margin-right: 20%; } pre.test { background-color: #ffffff; } --> </style>
The purpose of our test script will be to change the white background colour of the pre.test
to its normal value #EEF0F5
.
All linked and embedded style sheets are available through the document.styleSheets
array.
quirksmode.css
, the general style sheet for the entire site, is
document.styleSheets[0]
. The special style block I added to this page is
document.styleSheets[1]
. We're going to do our tests on this special block of styles.
cssRules
is supported by Explorer Mac, Mozilla, Safari, and Opera.
rules
is supported by Explorer (Win and Mac), and Safari.
A rule is one set of style declarations for one or more elements. There are two ways to access these rules. W3C insists on the cssRules
array while
Microsoft has decided on the rules
array. Both arrays work with index numbers, the first
rule is (css)Rules[0]
, the second one [1]
etc.
Workaround:
var theRules = new Array(); if (document.styleSheets[1].cssRules) theRules = document.styleSheets[1].cssRules else if (document.styleSheets[1].rules) theRules = document.styleSheets[1].rules
Now theRules
contains all style rules.
This is the style sheet:
@import url("test.css"); p,h2,h3 { padding-right: 10px; } pre.test + * { margin-right: 20%; } pre.test { background-color: #ffffff; }
Now at first you'd say that the special
test style sheet has four rules: @import
, then p,h2,h3
, then
pre.test + *
and finally pre.test
.
Unfortunately that is not always the case. Here are the selectors of the rules according to your browser:
undefined
P
PRE.test[CLASS~="test"] + *
PRE.test[CLASS~="test"]
P
H2
H3
PRE.test + *
PRE.test
P
H2
H3
PRE.test *
(note the absence of the +
)PRE.test
undefined
p, h2, h3
pre.test + *
pre.test
A fine mess.
p,h2,h3
rule is not one rule but three separate
ones, while Safari sees it as a rule for P
only. As far as I understand the
spec both variations are incorrect behaviour."The selector consists of everything up to (but not including) the first left curly brace ({).".
pre.test *
,
which has a completely different meaning. Serious, very serious.pre.test
is reasonably well supported, except that Safari adds unnecessary
selection syntax.So to access the pre.test
rule Safari and Mozilla 1.75 need cssRules[3]
, Explorer rules[4]
and older Mozilla's cssRules[5]
. Lovely, isn't it?
So we encounter serious problems when trying to access the rule by index number. What I'd rather do is access them by keys, where the selector is the key. Something like:
document.styleSheets[1].cssRules['PRE.test']
so that I can access the rule of the PRE regardless of where in the style sheet it is. It does not seem to have occurred to either W3C or the browser vendors that web developers have a need for such a way of accessing rules. All documentation is completely silent on this point.
This failure means that it's nearly impossible to access the rule you want.
Let's pretend we have accessed the desired rule. Now we change one of its style declarations. The general syntax for this is
rule.style.color = '#0000cc';
The W3C approved way is
rule.style.setProperty('color','#00cc00',null);
Since it is vastly simpler I prefer the style.color
syntax above setProperty()
.
Try changing the background colour of the PRE's below.
Test PRE
To avoid the rules problems noted above I use the fact that the pre.test
rule is the last
rule in the stylesheet. It's an ugly kludge, but it's the only way to get a proper cross-browser test case.
function changeIt() { if (!document.styleSheets) return; var theRules = new Array(); if (document.styleSheets[1].cssRules) theRules = document.styleSheets[1].cssRules else if (document.styleSheets[1].rules) theRules = document.styleSheets[1].rules else return; theRules[theRules.length-1].style.backgroundColor = '#EEF0F5'; }