O'Reilly Network    
 Published on O'Reilly Network (http://www.oreillynet.com/)
 See this if you're having trouble printing code examples


How to Change Your Look With Mozilla Skins

by Ian Oeschger
05/19/2000

"Skin-ability" has been one the longest-awaited and least-well-understood features of the Mozilla project. By using technologies such as XML (extensible markup language) and CSS (cascading style sheets), Mozilla developers can now customize their application interfaces by creating skins (or, in Netscape 6, themes, which are based upon skins). In this article I'll show you how to create skins and explain the role they play within the Mozilla development platform.

What's a Skin?

Skin refers to the look or overall style of an application such as a web browser. In Gecko-based applications, the skin includes the images, colors, styles, positioning, and to some extent the behavior of elements in the UI. For the most part, the skin is created with CSS and images applied to the structural elements of the UI.

The skin of a Gecko-based application is separate from its structure and function because of the way in which the interface is defined. In broadest terms, XUL defines the structure of the application, JavaScript describes the behavior, and Cascading Style Sheets define the coherent look, or skin. By changing the CSS files or pointing to a different set of CSS files entirely, you can change the skin of the application without affecting the underlying structure or functionality.

Who Does What for Gecko

XUL / DOM

Structure

JavaScript / XPCOM

Behavior

Cascading Style Sheets and Images

Skin

Related Articles:

Mozilla as an Application Virtual Machine

XUL Tools and What They Mean

Given the basic structure as defined in XUL and the linking or functionality as defined in JavaScript, the skin is free to express the look of the interface in almost any way it chooses. As you can see from the figures below -- which show two structurally identical browsers with different skins applied -- the skin can have a very powerful influence over the interface and thus over the experience of the user.

Alphanumerica's Sullivan Skin

Alphanumerica's Sullivan Skin.

FruityGum Skin, also from Alphanumerica.

FruityGum Skin, also from Alphanumerica.

Skins, CSS, and Interactions With Other Technologies

With the recommendation for acceptance of CSS Level 2 as a standard, style sheets have reached a point where they can be used quite effectively in interface design. In particular, the addition of absolute positioning, table layout, and special user interface properties to the host of features in CSS Level 1 gives the designer much more control over the layout of UI elements.

Beyond that, Mozilla technologies like XPCOM and XBL blur the lines between interface development and application development. It's not only the XUL interface itself that takes advantage of these technologies, but also the skin. When full CSS support and other web standards are coupled with some of these technologies, you get skins that can change content on the fly, add event handlers, and execute services in the application core.

Skins As Collections of Files

A skin consists of a group of CSS and image files located in a hierarchical structure (often a directory named skin) that has been registered with the Mozilla browser or another Gecko-based application. The CSS files are applied to the XUL interface by means of special import statements, processing instructions, and the special hierarchy, which are discussed in greater detail later. In this way, the global style information in the CSS files is applied to the application as a whole.

The most important single file in the skin -- the one that controls the color, font information, and style of the whole application -- is the global skin file, global.css. This file, sitting below the global/skin directory in Mozilla, is the basic source for the skin, though there are a number of other helper files, including platform-specific CSS, widget-specific skins, and images.

Cross-Platform UI

One of the most important features of skins is that they are created with cross-platform web standards instead of proprietary tool kits or languages. Not only does this make the resulting skin -- and indeed the user interface in general -- lightweight and easy to edit, it also makes it portable and nearly identical on different platforms.

This is an incredible boon for user interface developers, who are often forced to develop different user interfaces for different platforms, or else use the same UI and see it rendered differently. Using a standard like Cascading Style Sheets to style the UI frees developers from the native tool kits and allows them to truly write once and run anywhere. Also, the extensive use of CSS in web design creates an even shallower learning curve for new UI developers. XUL and CSS provide real UI development tools that are genuinely cross-platform and that anyone can use.

How XBL Provides Extensibility for Skins

Earlier, I alluded to some of the ways in which the skin is more than simply the look of the application. One important component of the extensibility of skins is XBL, the Extensible Bindings Language, in which much of the XUL widgets are described.

XBL is a companion language to XUL; where XUL is used to define the basic structure of the UI in terms of a set of UI widgets, XBL is used to:

The XBL UI is referenced from the skin. The dynamic quality of CSS itself is what makes XBL dynamic, and what allows you to swap UIs at runtime. Using Mozilla's broad support for the DOM and JavaScript, developers can change the class of the UI elements, and in this way change the XBL content referenced there. In the following diagram, code snippets from the base XUL, the applicable CSS, and the referenced XBL are shown in their relation to one another: When the class of the XUL menu element is swapped, the contents of the menu are changed. The anonymous content defined in the XBL is only picked up by the XUL when the corresponding CSS class style statement is in effect.

The relationship between XUL, CSS and XBL.

The relationship between XUL, CSS and XBL.

This is only a small example of how the skin can extend the interface. Refer to Mozilla's XBL Reference document for more information about this extensibility.

An Introduction to Creating and Editing Skins

You can use CSS to apply styles to XUL widgets for creating skins. Here's an example of how to do that.

To start creating a XUL skin:

  1. Add a style sheet processing instruction to the top of your XUL file.
    <?xml-style sheet 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; } 
    titledbutton#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 appears as follows:
No Style sheet.

No Style sheet.

Just the Global Skin.

Just the Global Skin.

Sample.CSS Importing Global Skin.

Sample.CSS Importing Global Skin.

The example 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 how to create basic style statements in CSS.

To read more about creating skins in CSS, see Skinning XUL Files By Hand, on the Mozilla web site.

Packaging and Installing New Skins

New skins are easy to install, and they don't need to reside within the chrome directory structure of Mozilla or any Gecko-based application. The chrome registry, described below, enables the user to download and apply a skin to the browser by clicking a hyperlink. Mozilla XPInstall technology handles the actual download and installation, and the chrome registry manages the skins and the skinning of the browser.

The UI for installing skins is not yet in place in Mozilla. However, the services that handle the installation and application of skins have been checked in recently and can be called from JavaScript. The following sections describe the creation and installation of a skin archive, respectively.

Creating a Skin Installation

The skin's organization within a single zip file makes it easy to manage on the distribution end. To create a skin installation, place all of your chrome files in a zip archive. The structure under the zip file should reflect the structure in the Mozilla chrome hierarchy:

chrome/
 skins/
   modern/
      [component dirs, e.g., navigator, editor, global, etc.]
     skin/
                    [files for a particular component's skin]

   classic/
      [component dirs, e.g., navigator, editor, global, etc.]
     skin/

   ...other skins...

 packages/
  ...

Note that the skins directory is a peer of the packages directory, which means that skins can be registered, edited, and selected independent of the packages to which they apply. Like the "modern" and "classic" skins above, a new skin must have subdirectories that name the components to which it applies -- and in those subdirectories, the applicable CSS and image files.

For example, if you are creating a new global skin called "myskin" for the Mozilla application, all the files would be organized under myskin/skin in a zip file. At the top level of this zip file, you must also place a file called manifest.rdf that describes the skin. The format of this RDF file is discussed in the chrome registry section below. The zip file should contain a single skin only.

Launching a UI Install Package from JavaScript

To install a skin that you have packaged as described above, use the following JavaScript function:

InstallTrigger.installChrome(InstallTrigger.SKIN, <url>, <name>);

where <url> is a relative url or a special chrome:// url that points to the zip archive, and <name> is the string denoting the name of the skin. For example, to install the skin mentioned above, newmoz.zip, you could write an oncommand menu event handler in XUL like the following:

<menuitem value="Skin Swap" 
  oncommand="InstallTrigger.installChrome(InstallTrigger.SKIN, 
    file://Projects/Skins/newmoz.zip, 
    'Acid Rain')" />

This function provides a directive for Gecko to treat references to the global skin in XUL as references to the new, zipped-up global skin file you have installed.

<?xml-style sheet href="chrome://global/skin" type="text/css"?>

Provided that the hierarchy within the zip file is the same as that of the already-installed skin files, the menu item in the example above installs the new skins and registers them in the chrome registry.

The Chrome Registry and RDF

The chrome registry is the set of files that Mozilla uses to describe the structure of skin and locale information on the user's system. Skin installations and selections read from and write to the chrome registry.

There are five RDF files maintained by the chrome registry:

RDF Files in the Chrome Registry

all-skins

a table of all installed skins, complete with all of the relevant information for each

user-skins

the user's current selections

all-locales

a table of all installed locales

user-locales

the user's current locale selections

all-packages

a table of all installed packages, complete with information about each

Each of the files uses the Resource Description Framework (RDF) to describe the skin and locale resources. The all-skins.rdf file, for example, takes the following format:

<?xml version="1.0"?> 
<RDF:RDF 
 xmlns:chrome="http://www.mozilla.org/rdf/chrome#" 
 xmlns:RDF= 
   "http://www.w3.org/1999/02/22-rdf-syntax-ns#"> 

 <!-- A list of all installed skins --> 
 <RDF:Seq about="urn:mozilla:skin:root"> 
   <RDF:li 
resource="urn:mozilla:skin:aqua/1.0"/ <urn:mozilla:skin:aqua/1.0> > 
 </RDF:Seq> 

 <!-- Information for the Aqua skin --> 
 <RDF:Description 
about="urn:mozilla:skin:aqua/1.0"> 
   <chrome:displayName>Aqua 
   </chrome:displayName> 
   <chrome:author>Steve Jobs 
   </chrome:author> 

   <chrome:previewURL> 
http://www.mac-rabies.org/mozilla-skin.gif 
   </chrome:previewURL> 

   <chrome:packages 
    resource="urn:mozilla:skin:aqua/1.0:packages"/ <urn:mozilla:skin:aqua/1.0:packages> > 
   </RDF:Description> 

 <!-- A list of the affected packages --> 
 <RDF:Seq 
   about="urn:mozilla:skin:aqua/1.0:packages"> 
   <RDF:li 
     resource="urn:mozilla:skin:aqua/1.0:global"/ <urn:mozilla:skin:aqua/1.0:global> > 
   </RDF:Seq> 

 <!-- The base URL for a given package --> 
 <!-- and skin entry, plus a convenience --> 
 <!-- pointer to the package resource --> 
 <RDF:Description 
   about="urn:mozilla:skin:aqua/1.0:global"> 
   <chrome:baseURL>resource:/chrome/ 
   </chrome:baseURL> 
   <chrome:package 
resource="urn:mozilla:package:global"/ <urn:mozilla:package:global> > 
 </RDF:Description> 

</RDF:RDF>

If you're familiar with RDF, you can see that the RDF for each skin describes a number of important things about it: Metadata such as the author and name, a url for viewing a preview, a list of affected packages (which are themselves described in the all-packages.rdf part of the registry), and the url for getting to the skin are all included in the RDF. When skins are registered in this way, they can be applied to packages or to the whole application very simply, for example within a simple browser dialog that takes advantage of the metadata to display basic information about each skin and perhaps display a preview.

The other registry files have a similar structure for describing the locale, the particular files that the user has selected, and the packages installed on the system.

Where To Go From Here

Resources

Writing Skinnable XUL and CSS

Writing Efficient CSS

Mozillazine's ChromeZone

AlphaNumerica

Skinning XUL Files By Hand

As a collection of CSS files and images, your browser's default skin can be played with and altered in innumerable ways. One of the best ways to familiarize yourself with the way that skins work is to edit some of the style statements already present in the default skin and view the results. This way, you don't need to perform any new installation procedures, and you will learn what parts of the browser's look are determined by which files.

From there, you might consider grabbing a skin zip file, giving it an overhaul, and then testing the installation procedures outlined in this article. Finally, creating a new skin for the Mozilla browser and packaging it for installation provides the most challenge and flexibility.

There are a few things that need to be stabilized and resolved before skins are switchable, installable, and settled entirely. But that point is very close. There's already useful documentation about creating skins available on the Mozilla web site, and new documentation and functionality are still being checked in. In the meantime, the sheer coolness of skins -- their power, flexibility, and standards support -- makes the learning process constructive and rewarding.

Ian Oeschger is a Senior Principal Writer at Netscape Communications.


Discuss this article in the O'Reilly Network General Forum.

Return to the O'Reilly Network Hub.

Copyright © 2009 O'Reilly Media, Inc.