Born Geek

Chapter 5: Skinning the Toolbar

A "skin" is a collection of styling rules (specified with CSS) and images that get used to change the appearance of chrome (in our case, the toolbar we are building). Keep in mind that although skinning is entirely optional, it can greatly improve the quality of your extension. After all, a user’s first impression of your toolbar will be its appearance, not its functionality. However, if you are comfortable using only text labels for your toolbar buttons (or your extension doesn’t make use of a chrome overlay at all), you can skip this step.

Updating the File Structure

The first step in creating a skin for our toolbar is to create the folder that will hold all of our skin files. Create a folder named skin inside of the chrome folder. The resulting file structure should look like the following:

TutToolbar/
 |-- install.rdf
 |-- chrome.manifest
 +-- chrome/
      |-- content/
      |    +-- tuttoolbar.xul
      +-- skin/

Now that we have a place to store our skin’s files, we need to register this location with our chrome.

Updating the Chrome Manifest

Remember the chrome manifest file we created in chapter 2? We need to add a line of code to that file which will register our skin. Let’s take a look at the line of code that is necessary (it has been highlighted below):

content tuttoolbar chrome/content/
overlay chrome://browser/content/browser.xul chrome://tuttoolbar/content/tuttoolbar.xul
skin tuttoolbar classic/1.0 chrome/skin/

This additional line of code is quite simple, and has only four parts. The first part, which is simply the word "skin", states that what follows is the skin’s registration information. Next up is the package name which, in this tutorial, is tuttoolbar. The third part indicates the name of an installed skin which we will be extending. The value shown (classic/1.0) is the value you should always use for Firefox extensions. Finally comes the most important part: the relative path name to the folder that contains our skin’s files. This path is always relative to the chrome directory. It is very important that you note the trailing slash (/) in the given path above. That slash is required, so make sure you include it.

Creating the Image Files

We will be using an image sheet for our toolbar buttons, and a separate image for the resize gripper. An image sheet is simply a single image that contains all the sub-images you wish to use in your skin. This reduces the amount of overhead required for your skin and generally improves performance. The following list shows both of the images that we will use for our extension:

  • Image Sheet (image_sheet.png): Toolbar Image Sheet
  • Resizing Gripper Icon (gripper.png): Resizing Gripper Icon

Let’s save these images to our skin folder that we created moments ago. Our resulting file structure will look like this:

TutToolbar/
 |-- install.rdf
 |-- chrome.manifest
 +-- chrome/
      |-- content/
      |    +-- tuttoolbar.xul
      +-- skin/
           |-- image_sheet.png
           |-- gripper.png

Applying the Images With CSS

Now that we have some images to use, and our skin directory has been registered, we can begin applying the images to our toolbar buttons. We will do so through the use of a Cascading Style Sheet (CSS). Let’s create our CSS file, naming it tuttoolbar.css and placing it inside of the skin folder, along with our images. Here is the resulting file structure:

TutToolbar/
 |-- install.rdf
 |-- chrome.manifest
 +-- chrome/
      |-- content/
      |    +-- tuttoolbar.xul
      +-- skin/
           |-- image_sheet.png
           |-- gripper.png
           +-- tuttoolbar.css

Let’s take a look at the contents of our style sheet before we go into any detail:

.TutTB-HasIcon {
    list-style-image: url("chrome://tuttoolbar/skin/image_sheet.png");
}

#TutTB-MainMenu {
    -moz-image-region: rect(0px 16px 16px 0px);
}

#TutTB-Combined-Button {
    -moz-image-region: rect(0px 32px 16px 16px);
}

#TutTB-Combined-Button > .toolbarbutton-menubutton-button {
    -moz-box-orient: horizontal;
}

#TutTB-Web-Button,
#TutTB-Combined-Web {
    -moz-image-region: rect(0px 48px 16px 32px);
}

#TutTB-Combined-Image {
    -moz-image-region: rect(0px 64px 16px 48px);
}

#TutTB-ResizeBar {
    background-image: url("chrome://tuttoolbar/skin/gripper.png");
    min-height: 22px;
    min-width: 3px;
}

#TutTB-ResizeSplitter {
    background: transparent;
    border: none !important;
}

The first rule shown specifies the image to use for anything that has the associated TutTB-HasIcon class applied to it. Note that we’re pointing to our image sheet in this rule by using the list-style-image CSS property. Next up is the rule to be applied to the "main menu" button. Note that we make use of the -moz-image-region property to specify where in our image sheet the image we want to use resides. The order of the values in this rule are as follows:

  1. Offset to top edge
  2. Offset to right edge
  3. Offset to bottom edge
  4. Offset to left edge

These offsets are always measured from the upper left corner, which happens to be offset (0,0). The values we used for the TutTB-MainMenu button correspond to the left-most image in our image sheet.

Proceeding down the style sheet, you can see that we use similar rules for all of the toolbar buttons, as well as the menu items in our combined search button’s menu. There’s one caveat to handling menu item icons, however. If you recall, we made use of a special class value for the menu items in our combined search menu. That special class was menuitem-iconic, and it is a built-in class provided by Firefox. In a sense it "enables" icon support for each menu item that uses it.

You undoubtedly also noticed the special rule for the combined search button:

#TutTB-Combined-Button > .toolbarbutton-menubutton-button {
    -moz-box-orient: horizontal;
}

The special CSS property used here (-moz-box-orient) specifies how the label for our button should appear: aligned vertically or horizontally. By default, toolbar button labels are aligned vertically, meaning that the label shows up underneath the icon. We don’t want that in this case, so we use the horizontal value to force the label to show up after the icon.

There are two rules in our style sheet that deal with the resizing gripper. Remember that vbox element that we placed inside of our splitter element? We use the ID of that vbox to display a background image for our gripper. This time we use the background-image property. We also must provide a minimum height and width (using the min-height and min-width properties), so that our gripper shows up. By default, the vbox and hbox elements size to the smallest value possible for their content. Since our vbox is empty, it sizes to a default of 0, which prevents us from seeing the background image.

We also provide a rule for the splitter element itself. We tell the background to become transparent (so that we can see the vbox image), and we tell it to not use a border (by default, all splitter elements have a border). Now that our CSS file is complete, we need to tell our overlay how to use it.

Using the Style Sheet

Only one line of code needs to be added to our XUL overlay to enable the style sheet we just created. It must be placed underneath the XML directive at the top of the file, but before the actual overlay element. Below I show the first few lines of our XUL overlay file, highlighting the line we need to add:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://tuttoolbar/skin/tuttoolbar.css"
                 type="text/css"?>

<overlay id="TutTB-Overlay"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

(... rest of XUL overlay file ...)

Like we saw with the images in the style sheet, a chrome path gets used to specify the location to the style sheet. The type attribute simply tells the parser that the file being referenced is a CSS file. And that’s all there is to it! Let’s take a look at the entire XUL overlay file as it appears with this additional line: [View XUL Overlay Revision 6].

And don’t forget to test it out! Open the Firefox instance that includes your dynamic extension installation (which we discussed in the previous chapter), and see what the extension looks like. Next up, we’ll be bringing the toolbar to life.

| Table of Contents |