2006/07/08

Basic CSS handling

XUL applications will rarely lack CSS stylesheets. You will usually need them to style your windows, icons, etc. Pretty much anything the user will be looking at. An important advantage of this approach is that extensions become skinable. Theme developers can create themes that affect all browser appearance, including your extension. If your extension is popular enough, they might even override its specific styles, to make it blend in better with the theme.
But sometimes you'll need to handle CSS from your scripts, perhaps to have user-set styles. Doing this in Firefox is quite easy, because of its compliance with the DOM 2 Specification. The best way to learn about this is reading the DOM Level 2 Style Specification, from the W3. You'll find that most (if not all) objects decribed in this spec can be found in the XUL Planet specifications as well. They allow you to very easily manipulate stylesheets from XUL or any web page. It's the same for both, except that different stylesheets apply for each.
But I'm not the type to post a link and leave you hanging, even though those specifications are extremely helpful. One extension I was working required some style handling, so I'll show some of the stuff I had to do and the little details you need to keep in mind.
Your starting point is the following object:
document.styleSheets
This is a StyleSheetList object (StyleSheetList in the W3). This object is basically an Array of the stylesheet that apply to your page. In my case, I only needed a specific stylesheet I inluded in my extension, so my code looks something like this:
var cssRules;
for (i = 0; i < document.styleSheets.length; i++) {
if (sheets.item(i).href == "chrome://myextension/skin/myextension.css") {
cssRules = document.styleSheets.item(i).cssRules;
break;
}
}
Now the variable cssRules contains all the CSS rules that I had set in that specific file in my extension. I used the href property (from interface StyleSheet) to identify the file, and the cssRules property (from interface CSSStyleSheet) to obtain the rules.
Then I needed to work with some specific selectors (#main-page or .column, for example), so I extracted them from the rules in the following way:
for (i = 0; i < cssRules.length; i++) {
cssRule = cssRules.item(i);

if (cssRule.type == cssRule.STYLE_RULE) {
switch(cssRule.selectorText) {
case "*|#main-page":
case "#main-page":
pageRuleSet = cssRule;
break;
/* ... */
}
}
}
The cssRules object is a list of CSSRule objects, which can have different subtypes. I was only interested in CSSStyleRule objects, which are your typical style declarations, such as:
#main-page {
background-color: black;
margin: 2em;
}
As you can see, I used a switch statement to discern between the different selectors. The case statements are doubled because of some odd quirk I found out during development: the selectors have their normal text set when the page is loading for the first time, but then they would have a "*|" prepended afterwards. Since this script is run on page load and reload, they would both have to catch both types of selectors. I really don't know what that prefix means.
Anyway, this code gives us a set of objects of type CSSStyleRule, which we can store somewhere and use afterwards. Getting and setting CSS properties is very easy now:
bgColor = pageRuleSet.style.getPropertyValue("background-color");
pageRuleSet.style.setProperty("background-color", "black", "");
The third parameter in the setProperty method of interface CSSStyleDeclaration corresponds to the priority of the value. It can be either an empty string or "important". If you want your style to absolutely, positively apply all the time, then you should use "important". Otherwise, it's better to play nice and not use it. The one case where it's necessary to use "important" is when overriding styles for text link selectors in XUL. The applied styles won't work otherwise.
Well, that's all I have for today. I think this is a pretty decent introduction to CSS handling, both in XUL and regular web pages. I will complement this post in the future with another post on how to create a simple color selector.

Labels: , , ,


Comments: Post a Comment



<< Home

This page is powered by Blogger. Isn't yours?