At an earlier point in Mozilla's history, all interface files -- the XUL, the CSS, and the images -- were stored in directories named after the main Mozilla packages in the application chrome directory. The best way to look at a skin was just to poke around in those directories, change things in the CSS files you found, and reload to see what had changed in the browser. The CSS files are no longer stored in regular directories.
To organize things better and make a smaller footprint for Mozilla, all chrome is stored in special compressed archives in the chrome directory. These archives are Java Archive (JAR) files, whose subdirectory structure reflects the structure of Mozilla's major components, to some extent. There is one JAR archive for every theme. By default, Mozilla is distributed with the Classic and Modern themes, represented in the chrome as classic.jar and modern.jar. Figure 4-5 shows some of the contents of the modern.jar file in a zip utility.
You have already seen some of the structure inherent to CSS in the previous examples. When an element has both a class-based and an id-based rule, for example (as well as a basic element "look and feel" defined in the global skin), the element style is applied. Then, the more specific class-based rule is applied and overwrites the properties of the general rule if they conflict. Finally, the ID-based rule is applied and overwrites whatever conflicting style values are in the more general selectors. In this way, the most specific style rules inherit from the most basic. This is the "cascade" in Cascading Style Sheets. In addition to this definition, the syntax of CSS allows you to specify selector relationships -- such as when you create a parent-child selector and apply a style rule to only the selectors that have some other particular element as a parent in the XUL content model. However, there is also a strong inheritance mechanism in the way that the Mozilla browser uses CSS -- in the way skin files are organized in the chrome and applied to the XUL. The strong hierarchical structure present in Mozilla's CSS and the XUL allow the chrome registry to maintain the skin and the various components that get skinned as different modules, but find and apply the right resources whenever they are called for. This structure is described in the Section 4.3.2 section later in this chapter.
For the sake of discussion, this book describes two kinds of inheritance: the more basic form, in which a specific skin like navigator.css inherits all style rules from global.css, and modularization, in which navigator skin rules specific to the toolbar are distributed into widget-specific CSS files (e.g., toolbar.css is part of the global skin). The global skin -- once a large, unmodular set of style rules contained in global.css -- is now spread out over several modularized CSS files, as Figure 4-6 shows.
This modularization makes it possible for a XUL file to load the global.css file in a single statement and use any of the style rules defined in these skins. We will discuss the global skin in more detail in the section Section 4.3.4.2 later in this chapter. Skin inheritance and skin modularization work together to give skins their structure and make it possible to create new skins or apply CSS only to particular parts of the application.
Figure 4-6 shows a very specific skin, new.css, inheriting the style information from communicator.css and then being loaded into the XUL file. In a situation like this, ex.xul can use any style rule defined in the communicator.css file (or in any CSS file that it imports).
Though they look very different, the Modern and Classic themes that are installed with Mozilla have similar structures. This is because the structure of a theme reflects, in many ways, the structure of the components to which it applies. So, for example, both themes have subdirectories (in the JAR files in which they are stored) where the CSS and image resources for each of the main components are stored. Modern, for example, has a communicator component subdirectory, and that subdirectory has subdirectories representing the various parts of the communicator interface: bookmarks, help, search, sidebar, and so on. Example 4-7 shows the Modern and Classically themed Navigation bars side by side.
Both themes are complete. They each contain all skin resources for the major components of the application.[1] The resources themselves vary, but their structures are almost identical. This ability is what makes the skins dynamically changeable.
Skin developers can, for example, create a skin for a single component in Mozilla (e.g., messenger) and let the Modern theme continue to take care of the other components for which they have not created any new CSS information. Which components are skinned by which themes is specified in the installed-chrome.txt file, where a single entry represents the application of the appropriate theme resources to a single component, such as navigator. (See Chapter 6 for more information about this file and about how themes and other packages are registered and applied in Mozilla.) This situation does not apply to new applications like xFly, however, for which the XUL is typically a single package and the CSS that applies to it is another single package. Unlike the Mozilla browser, your application will probably have a single manifest and content subdirectory and a single manifest and skin subdirectory:
xfly.jar: content/ contents.rdf <xul content here> skin/ contents.rdf <css content here>
An important difference here is that your skin requires a single manifest whereas the Mozilla themes use as many manifests as they have major components to skin. When the application that needs to be skinned is as large as the Mozilla browser, modularity is almost imperative -- particularly if that application supports add-on applications (like xFly itself, which will be accessible from the Mozilla Tasks menu when you are done).
If you haven't already looked at it, using the skin-switching UI (View Menu > Apply Theme > Modern) in Mozilla will give you an idea about the differences between the two skins that come preinstalled with the browser. The Classic skin is modeled after earlier versions of the Mozilla UI and of the Netscape 4.x Communicator product. It has the familiar light grey box look, with the larger, primary-colored navigation button and a squared-off geometry. The Modern theme is a newer take on the browser interface. It has a smoother overall look, with rounded edges on many of the widgets, subtle color differentiations, gradients, and 3D icons.
However, both skins sit on top of the same XUL. With one notable exception -- a powerful feature of CSS in Mozilla discussed later in this chapter in the Section 4.5.1 section -- the applications themselves are identical, and themes themselves provide all the differences in the browser's look and behavior.
Obviously, we cannot describe even a fraction of the CSS files that go into making up a single, overall theme. There are, however, some CSS files that help determine how the Mozilla browser looks. In this section, we will go over some of those files so you can see how they relate to one another, where the browser gets its look, and what strategies you might use to create your own complete skin.
The following sections provide a brief, representative sampling of the Modern theme. The global skin, the navigator skin, and the communicator skin are discussed as they pertain to the Modern theme in the Mozilla browser.
One of the most specific and complex skin files in the Modern theme hierarchy is the navigator.css file, which contains style information for the browser itself. When you look through this skin, you will see rules for such things as the Print button. In Example 4-6, note how several selectors are grouped with a single style rule, and how the parent-child relationship between elements (see the earlier section Section 4.2.2.7 for an explanation of this selector) is used to style print buttons appearing in different places (i.e., under different element parents) in the UI.
Almost all of the most specific skin files (e.g., navigator.css) inherit from the global skin, which includes but is not limited to the global.css file located in chrome://modern.jar!/skin/global/skin/.
The global skin includes other stylesheets that define localizable settings and general global formatting, which the global.css file loads at runtime. If you look at the top of the global.css file as shown in Example 4-7, you can see the stylesheet import statements that collect these skins into a single global skin:
The global.css serves as a base into which these other skins can be loaded. When you load global.css into your XUL file by means of a xul-stylesheet processing instruction, you in effect load these skins.
Also included in Example 4-7 are a couple of binding attachments, which attach content to elements that match certain style rules. On a related note, most global skins on a widget-per-widget basis are now included in the binding themselves, as opposed to being imported in a global skin, which used to be the case. Take this button stylesheet inclusion from the XBL file button.xml as a case in point:
<resources> <stylesheet src="chrome://global/skin/button.css"/> </resources>
Here the XBL specific <stylesheet> element includes the stylesheet, which can be included in a binding and then inherited by other button bindings.
Like global.css, the communicator.css file (Example 4-8) is another CSS file that does imports to build up the communicator skin. The CSS style rules in the file itself are minimal, but if you look at the top, you can see that many styles that the communicator component uses come from the CSS files also located in the communicator subdirectory of the current skin.
[1] | There are just a couple of exceptions to this rule. The content directory of a package (typically the place where just the XUL and JS are stored) sometimes holds a file called xul.css. This file defines style information that is so fundamental to the way widgets are rendered -- more fundamental, even, then global.css and its siblings -- that it is set apart from the regular skin and put in with the content, where it is loaded automatically. It's not a good idea to edit this file. |