Skinning XUL Files by Hand

What Is a Skin?

The skin of a XUL file is its look or overall style. In XUL, skins are created with Cascading Style Sheets and images. To skin a XUL file means to change the overall look of that file by changing its style information. In the very near future, it will be possible to skin XUL files dynamically and completely -- by pressing a button, selecting a skin from a menu, or by accepting a skin from over the web. When this day comes, skins defined in a global skin file will be applied to a whole application -- like the Mozilla browser -- so that all the various windows and parts will look consistent. In the meantime, however, skinning a file requires some manual interaction. This article can help you get started understanding skins and creating skins for XUL. It presumes you have at least basic understanding of XUL and the Application Object Model that XUL describes. Following the instructions here, you are going to create a skin for a XUL file and apply it by specifying classes for all of the interested elements. The skin will reside in a single CSS file, appropriately named drxul.css. As you will see, CSS provides a lot of flexibility for defining styles to individual elements, to classes of elements, to pseudo-classes, and to anonymous classes.

By the way, in contrast to the term skin, "chrome" refers to the skin and the content and whatever localization and platform-specific files are necessary for a particular part of the application or window. The skin is just the style or appearance of an interface, where the chrome is the style, content, and structure. The chrome is everything in the front end of an application.

Much of what makes XUL look (and act!) the way it does comes from the CSS for each XUL element. CSS2, for example, gives you control over the absolute positioning of any element within its parent element. Also, most of the behavior that buttons exhibit comes from styles and an event model based on JavaScript that dynamically switches between these styles. Mozilla's current global skin defines this basic behavior for several classes of button. A button is styled by the global skin when its class attribute is set to a class which is defined in the global skin. For example, when a button is defined as follows:

<button class="plain" label="Push Me" />

Then the following very simple style definition applies to that button.

button.plain { border: 0px !important; }

The global skin, in which styles for these several button classes and dozens of other elements are defined, is described in the following section. If you want to use the classes already defined in Mozilla's global skin to style your elements, you may do so. But you may also want to define new classes of buttons particular to your XUL file, in which case the style information will be wholly defined within your custom CSS file.

Reading the Global Skin

It's very important to familiarize yourself with the basic style definitions in the global skin before you set out creating your own stylesheet. CSS can quickly become complicated. The ability to apply styles to elements of a type, to specifically identified elements, and to classes of elements creates the potential for redundancies or conflicts in the style information. To avoid this, the makers of the CSS specification have created some rules of precedence that look at how many different rules have been defined for an element, where the style definitions appear (i.e., externally in a CSS file or inline), where the elements themselves appear, and other esoteric variables. If you create a style in your custom stylesheet for a button with a particular id, for example, some of the more basic style information for buttons in the global skin may take precedence over your new style and cause it not to be applied. Make sure you are aware of the way that the global skin defines the skin and which elements, in general, it is addressing.

Since the purpose of the global skin is to create a look for the entire application or chrome that can be changed dynamically, you should not create style information in a custom CSS file that controverts the global skin unless you really mean to. If your XUL file is to be a part of a larger application that can be skinned, like Mozilla, you probably want your XUL file to pick up the global changes when the application is dynamically reskinned. To keep your XUL looking consistent and to avoid breaking skins altogether (when your styles have some dependency on a part of the global skin that changes, such as an image), use the style rules in the global skin by importing it into your stylesheet with the following instruction:

@import url("chrome://global/skin/");

Refer to the document Writing Skinnable XUL and CSS for guidelines on how to make your skins friendly to the global skin, to XUL, and to Mozilla.

Stylesheet Syntax

To familiarize yourself with the global skin, open up the text file called global.css in the chrome/classic.jar!/skin/classic/global directory of the Mozilla application. In a cascading stylesheet, the style definitions have the following basic form:

element {
  style-attribute1: value;
  style-attribute2: value;
  style-attribute3: value;
}

For example, the following definition -- were it not in serious conflict with the many menu style definitions in the global skin -- makes all XUL menus appear with a one pixel border, a light blue background, and 10 point fonts:

menu {
  border: 1px;
  background-color: lightblue;
  font-size: 10pt;
}

In addition to these basic element style rules, CSS also provides for the application of style information to classes of elements, and element IDs. The following table shows the basic format for these two common types of style definitions:

Class ID
element.class { attribute: value; } element#id { attribute: value; }
menu.baseline {
  border: 0px;
  font-size: 9pt;
}
menu#edit {
  color: red;
}

Other Style Subgroups

Contextualsubgroups -- elements appearing within other elements, such as italicized text anywhere within a <p> element or a <div> -- can be grouped in CSS, but this is an extremely inefficient way to style XUL, and is frowned upon in the Mozilla development community (again, refer to the skinning guidelines in Writing Skinnable XUL and CSS for more info); CSS2 also provides some new ways to group elements for styling, which we summarize briefly here, because they appear in Mozilla with some frequency, but reserve for another article:

Pseudo-class Parent-Child
element:pseudo-class { attribute: value; } parent > child { attribute: value; }
button:hover {
  border: 1px;
}
menu#file > menuitem {
  font-weight: bold;
}
Pseudo-classes reflect states of the element: when the mouse moves over a button, for example, the appropriate pseudo-class stylesheet rules are applied. The parent-child relationship is more economical than the aforementioned contextual subgrouping, which searches the entire subtree of an element for the subelement.

Finally, Mozilla provides some special extensions to the Cascading Style Sheets specification that allow even more control over the way that XUL is skinned within the browser.

On to the actual global.css file: After some comments, the CSS file contains basic style information for the <window> and <dialog> elements. After these, the global skin defines styles for some of the XUL widgets: statusbar, statusbarpanel and so on. Most widgets have their styles defined in separate CSS files in the same directory that the global.css file.

Note that much of the style attributes in these rules have to do with borders, font information, color, margin, native appearance. In general, these are the types of styles that should be defined only in the global skin of an application, since these are the styles that give an application a certain overall look, or skin.

Note that for any one class of element, there may be several pseudo-classes andattribute selector styles defined. When you declare a button in your XUL to be of a particular class, you take advantage of all of the styles defined for the various states of that button. For this reason, it can be very efficient to use button classes that appear in the global skin and to make new classes only when necessary.

Browse through the global skin to familiarize yourself with what's there. In the next few sections, you will be importing this style information into a custom stylesheet and extending it with new style rules for your XUL.

Loading Stylesheets in XUL

For your custom skin, let's assume you want to skin the XUL file, xulnote_sample1.xul. To work with this XUL file, save it locally and rename itsample1.xul.

Though applying inline styles is a perfectly legal move in XUL and a good idea in some rare cases, in general you should try to keep the XUL skin separate from the actual XUL structure. This independence of function and form is a great advantage of XUL, and it should not be overlooked.

A CSS file is a regular text file with the extension .css. It is applied to a XUL file by means of the processing instruction at the very top of the XUL file. When XUL files are situated within a XUL package or chrome, the processing instruction for a stylesheet reflects the hierarchy of the package. We will discuss this special url type in a later article. When the XUL file is a stand-alone, as in this example, where the stylesheet is external and sitting in the same directory, the processing instruction at the top of the file is as follows:

<?xml-stylesheet href="sample.css" type="text/css"?>

A XUL file may actually have any number of stylesheet processing instructions: one for each stylesheet that the XUL wants to load. In general, though, it's better form toimport the global skin into your stylesheet, create your new styles rules, and then load only the new stylesheet to get all styles in both the global skin and in your own stylesheet.

Creating a New Stylesheet

Unlike a XUL file, a CSS file does not need any particular structure or preamble information at the top. CSS can define styles for elements in a hierarchy, but it is not itself hierarchical, as you saw in the global skin. Instead, a CSS file is usually simply a list of style definitions that are applied to their respective elements and classes by the rendering engine.

Here is a very short (but complete!) cascading stylesheet that might be referenced and used by a XUL file:

toolbar.nav-bar {
  background-image: url("chrome://navigator/skin/navbar-bg.gif");
  padding: 0px;
  padding-bottom: 2px;
}

box#navbar {
  background-color: lightblue;
}

A:link {
  color: #FA8072;
}

This stylesheet exhibits three of the different types of style definitions described above. Each type uses a different grouping of elements. In the first definition, the selector "toolbar.nav-bar" is used to define style information for all XUL toolbars of the class "nav-bar." Unlike an ID -- which is also often used as a selector but must be unique -- a class attribute can be used on multiple XUL elements you want to pick up the specified style information. A toolbar elements defined as:

<toolbar class="nav-bar" id="nav3">
  <toolbarbutton label="Click me" />
  <toolbarbutton label="Don't click me" />
  ...
</toolbar>

will be styled with the CSS rules that appear in the block after the toolbar.nav-bar selector in the CSS example above. Similarly, the next item uses the ID selector to apply style information to a single XUL element. Since id attribute must be unique in a document, there can only be a single element with the ID "navbar", and it will pick up the style information in the block.

The third type of selector, thepseudo-class, is one you may have seen in the in-line style definitions for hyperlinks which commonly appear in HTML documents. The pseudo-class is connected to an element (or not: you can also define styles that apply to any element in the state specified by a pseudo-class) with the ":" character. In this third type of style definition, the "A" element picks up the style information defined in the block only when it is, as a link, active. This last type is new to CSS2.

To start creating the XUL skin:

  1. add the stylesheet processing instruction to the top of your XUL file.
    <?xml-stylesheet href="sample.css" type="text/css"?>
  2. create a new text file called sample.css.
  3. add the following lines to the file:
    @import url(chrome://global/skin/);
    
    box#bbox { background-color: lightgrey; }
    
    button#rd {
      background-color: red;
      color: white;
    }
    
  4. save it in the same directory as your XUL file.

When you reload the xul file you have been working on, the box element you have used to create the navigation area in the XUL file appear as follows:

No Stylesheet

Just the Global Skin

Sample.CSS Importing Global Skin

The skinned browser is not much to look at right now -- and you may note that this basic skin has transgressed upon some of the skinning guidelines because it overrides color information, but you can get a sense of what the possibilities are with the combination of the XUL structure and the style rules of CSS.

Thinking Skins

Sometimes you can become so involved in the details of XUL and Mozilla's other XP tools that you can lose sight of what the purpose and impact of these technologies are. The combination of XUL and CSS provides so much flexibility that it can seem daunting.

The purpose of this split between XUL and its skins -- and between the global skin and whatever custom styles you might create -- is to enable the dynamic skinning of applications such as the Mozilla browser. What you have done manually in this article will be done dynamically and much more completely by a mechanism called thechrome registry. this needs rewording: , which, like the Windows registry, is a database in which information about a user's software and environment can be recorded and accessed as necessary. Software components and users will be able to update the chrome registry and change the global skin. And with the advent of new CSS2 conventions like positioning, the changes you can make to the presentation and behavior of the basic structure in a XUL file is dramatic.

The syntax for creating all this information with text -- added to the distributed nature and the sheer volume of text required to define a single chrome -- can sometimes make the progress seem slow. But the advantages of using XUL so far outweigh those of using the standard C++ toolkits that XUL authoring should rightfully be considered in a separate category of development. XUL represents, as one evangelist put it, the "democratization" of interface design and ofapplications development, about which we will have more to say in a later article.

In short, XUL provides the tools for anybody to create interfaces as complex and as attractive as any C++/MFC/Visual IDE/Templates toolkit user's, and it does so in a way that makes these interfaces available on any platform. You don't have to know the vagueries of a "4GL" programming language or acquaint yourself with the innards of a particular platform and its native widgetry at the expense of others.

XUL's technologies are interoperable, consistent, cross-platform, free, and readily available. Not only is the production of such interfaces democratized, in other words; the consumption and distribution of these interfaces is equally democratic. As with anything truly democratic, you have to fuss a little bit with things to make them work. You have to share, and you have to have a little bit patience. Once you get the hang of things, though, you will find creating XUL files and skins as easy as creating basic web pages in HTML.

Original Document Information