Home > Articles > Programming > ASP .NET

This chapter is from the book

Using Themes and Skins

The previous section illustrates how you can customize your controls by setting the style properties of the controls themselves. ASP.NET 2.0 introduced the theme mechanism. This mechanism allows the developer to style the appearance of Web server controls on a site-wide basis. Like CSS, ASP.NET themes allow you to separate Web server control styling from the pages themselves, but have the additional benefit of having a complete object model that can be manipulated programmatically. Themes still allow you to use CSS for the majority of your visual formatting, and because theme support is built in to ASP.NET, you can dramatically alter the appearance of your Web site with a single line of programming (or a single line in the Web.config file). For instance, Figure 6.2 illustrates how a single Web Form's appearance can be radically transformed using three different themes.

Figure 6.2

Figure 6.2 Same page—three different themes

An ASP.NET Web application can define multiple themes. Each theme resides in its own folder within the App_Themes folder in the root of your application. Within each theme folder, there are one or more skin files, as well as optional subfolders, CSS files, and image files (see Figure 6.3).

Figure 6.3

Figure 6.3 Theme file structure

Defining Skins

A skin describes the appearance of one or more control types. For example, a skin file might look like the following.

<asp:Label runat="server" ForeColor="Blue" Font-Size="10pt"
   Font-Name="Verdana" />

Notice that a skin simply contains a control definition without the id attribute. A given skin file can contain multiple control definitions. Alternately, many developers have a separate skin file for each control type (a theme can contain any number of skin files).

Not all properties can be skinned. Generally speaking, only properties relating to appearance (i.e., the properties in Table 6.1 plus additional properties depending upon the control) can be specified in a skin. Referencing a property that is not themeable in a skin file generates an error. As well, certain controls, such as the Repeater, are not themeable, generally because they do not inherit from the WebControl class.

There is no Visual Studio designer support for creating skins. That is, the only way to create and modify a skin file is directly in Source view within Visual Studio. Even worse, Visual Studio's Intellisense is not available in Source view when modifying a skin. As an alternative, you could create a temporary Web Form, use the Design view or Source view as needed to add controls and set up their properties, copy and paste the markup to your skin file, and then remove the id attribute from each of the controls.

Creating Themes in Visual Studio

Themes reside in separate folders within the App_Themes folder within your site. You can create this folder yourself in Visual Studio by right-clicking the Web project in the Solution Explorer and choosing Add ASP.NET Folder → Theme option, as shown in Figure 6.4.

Figure 6.4

Figure 6.4 Adding a theme folder

Alternately, Visual Studio can automatically create a theme folder for you when you add a skin file via the Add New Item menu option (see Figure 6.5). In general, you probably want to avoid this approach because Visual Studio names the theme folder the same as the skin file.

Figure 6.5

Figure 6.5 Automatically adding a theme folder

Walkthroughs 6.1 and 6.2 demonstrate how to create a theme and a skin.

Applying a Theme

After a theme has been created (that is, after you've created one or more skin files), you can apply a theme to a page. This can be done in a few different ways. One way is to simply assign the theme using the Theme=themeName in the Page directive, for instance:

<%@ Page ... Theme="Cool" %>

You can also set the theme for all pages in a site via the Web.config file. To do so, simply specify the theme via the theme attribute of the pages element within the system.web element, as shown in the following.

<system.web>
   ...
   <pages theme="Cool" />
   ...
</system.web>

A page's theme can also be set programmatically. To do so, you can set the Theme property (defined in the Page base class) for a form in its code-behind class. This is covered in more detail later in the chapter. Finally, another, less common way to set the theme is to set it for all sites on a machine via the machine.config file. This file is located at [windows]\Microsoft.NET\Framework\[version]\CONFIG. Just as with setting the theme for a site via the Web.config file shown earlier, you can set the global theme for the machine as a whole via the Theme attribute of the pages element within the system.web element of this machine.config file. The specified theme folder and its contents must be located in the global theme space for the machine, located at [windows]\Microsoft.NET\Framework\[version]\ ASP.NETClientFiles\Themes.

How Themes Work

Now that you have seen how to create and use themes, let us peek under the hood and examine what ASP.NET does to make themes work. Like everything in ASP.NET, it all begins with a request. When a request arrives for a resource from an ASP.NET application that uses themes, the runtime parses and compiles all the skins in each theme. Recall from Chapter 2 that the markup in an aspx page is parsed into a class and then compiled into an assembly; an analogous thing happens with the skin files—each theme is parsed and compiled into a separate assembly.

Each theme is realized as a concrete subclass of the PageTheme class. This class maintains a collection of ControlSkinDelegate objects. This delegate represents or "points to" the actual method that applies the correct skin to the control; this method exists in the class file generated for the skin.

When the runtime executes a page that has a theme, it iterates through the page's Controls collection, and if there is a delegate for the control type, it calls the delegated method (in the generated skin class) which then decorates (i.e., changes the properties specified in the skin) the specific control object.

Overriding Themes

As previously mentioned, skin definitions for a control type override any settings for that control type made within a given page. For instance, consider the following skin definition.

<asp:Label runat="server" ForeColor="Green" />

Now imagine that you use this skin in a page that contains the following markup.

<asp:Label runat="server" id="labOne" Text="Hello" />
<asp:Label runat="server" id="labTwo" ForeColor="Blue"
   Text="World" />

What text color will the content of these two Label controls have when rendered by the browser? In fact, both will be green, because skin definitions override page definitions. You can have a control ignore a skin setting via the EnableTheming property, as in the following.

<asp:Label id="labTwo" ... EnableTheming="false" ForeColor="Blue"/>

There is another way to have properties defined within individual controls override skin settings. You can do so by changing the Page directive of the form and use the StyleSheetTheme attribute rather than the Theme attribute. Unlike those applied by the Theme attribute, the properties applied by the StyleSheetTheme are overridden by control properties defined within the page. As such, the StyleSheetTheme behaves in a manner more akin to the cascade within CSS. For instance, in the following example, the "World" text is blue.

<%@ Page ... StyleSheetTheme="Cool" %>
...
<body>
  <asp:Label runat="server" id="labOne" Text="Hello" />
  <asp:Label runat="server" id="labTwo" ForeColor="Blue"
     Text="World" />
</body>
</html>

You can also set the StyleSheetTheme via the Web.config file. To set it in the Web.config file, you would use the styleSheetTheme attribute (rather than the Theme attribute), as in the following.

<system.web>
   ...
   <pages styleSheetTheme="Cool" />
   ...
</system.web>

Other than the fact that one allows skin properties to be overridden and the other does not, what else is different between the Theme and StyleSheetTheme attributes? A Theme is applied after the properties are applied to the server-side control, which is why the properties set by the Theme override those of the control. A StyleSheetTheme is applied before the properties from the server-side control, and are therefore overridden by the properties on the control. As well, the Visual Studio designer displays skins set by the StyleSheetTheme, but not by the Theme. If you specify both a Theme and StyleSheetTheme, the Theme takes precedence (i.e., control properties are overridden by the theme).

So which should you use? StyleSheetTheme is probably ideal during development because the Visual Studio designer displays the skins, and you can make quick changes to the page's Web server control appearance properties as part of your debugging and development. But because one of the primary benefits of themes is that you can change the entire appearance of a site through one simple theme change, it probably makes sense to use the Theme property when your site is ready for deployment; by then, you will no longer need the designer support and you will probably want to override any page properties by the formatting specified by the individual skins.

Named Skins

If you need to override the appearance of a skinned control, perhaps a better approach than using StyleSheetTheme is to use named skins. For instance, you might not want all of your Label controls to have the same appearance. You can thus define alternate skin definitions for the Label control by giving the different skins separate SkinID values. You can then reference this SkinID in your Web Form's Label controls. For instance, let's define a skin file with the following content.

<asp:Label runat="server" ForeColor="Green" Font-Size="10pt" />
<asp:Label runat="server" ForeColor="Red" Font-Size="14pt"
   Font-Name="Verdana" Font-Bold="True" SkinID="Quote" />

To use the named skin in any of your Web Forms, you simply need to add the reference to the SkinID in the controls that will use the named skin, for instance:

<asp:Label ID="labQuote" runat="server" Text="Hello"
   SkinID="Quote"/>
<asp:Label runat="server" id="labMsg" ForeColor="Blue"
   Text="World" />

In this case, the word "Hello" appears in bold, 14pt red Verdana, whereas the word "World" appears as 10pt green text.

Themes and Images

One of the more interesting features of themes is that a given theme folder can also contain images and CSS files. You can thus radically transform a Web page by substituting different images and different style sheets. For instance, different themes could use a different set of images for bullets, image buttons, or for the icons used by the TreeView control. The only requirement is that the skin must use a relative URL for the image. This means that the image files must exist somewhere inside the same themes folder as the skin file itself.

For instance, the following skin defines two controls. The first is a named skin that displays the masthead image for the site; the second defines the look for all BulletedList controls. The relative path for the images indicates that the files are contained in a subfolder named images within this particular theme folder.

<asp:Image runat="server" ImageUrl="images/logo.gif"
   AlternateText="Masthead Image" SkinID="logo" />

<asp:BulletedList runat="server" BulletStyle="CustomImage"
   BulletImageUrl="images/bullet.gif" DisplayMode="HyperLink" />

To use this skin, your Web Form might look like that shown here. Notice how the resulting code in the Web Form is quite simple, because the additional properties are contained in the skin rather than in the Web Form. Figure 6.6 illustrates how the visual appearance of this form might vary simply by having different images for logo.gif and bullet.gif in two different themes containing the exact same skin.

Figure 6.6

Figure 6.6 Using images in theme skins

<asp:Image runat="server" ID="imgLogo" SkinID="logo" />

<asp:BulletedList ID="blstSample" runat="server">
   <asp:ListItem Value="">Home</asp:ListItem>
   <asp:ListItem Value="">Browser</asp:ListItem>
   <asp:ListItem Value="">About</asp:ListItem>
</asp:BulletedList>

Themes and CSS

There is a certain amount of overlap between CSS and ASP.NET skins. Both allow you to specify consistent site-wide formatting. For example, if you want all of your text boxes to have a certain border style and color scheme, you could do so via a skin, as in the following.

<asp:TextBox runat="server" BackColor="Beige"
   ForeColor="DarkKhaki" BorderColor="LightGray"
   BorderWidth="1px" />

You could achieve the same effect by defining a CSS class in the theme's style sheet.

.myTextBoxes { border: 1px solid LightGray; color: DarkKhaki;
   background-color: Beige; }

You could then reference this class in the skin.

<asp:TextBox runat="server" CssClass="myTextBoxes" />

So which approach is better? In general, try to place as much appearance formatting as possible into a theme's CSS files. Many Web sites are created in conjunction with a Web designer, who undoubtedly is familiar already with CSS. A designer can easily modify and even swap the CSS files in any given theme without knowing anything about ASP.NET. If all of a site's formatting is contained within skin files, formatting changes will instead require the intervention of an ASP.NET developer (which is perhaps a good thing if your sole concern is to boost the employment of ASP.NET developers). As well, CSS provides more control over the appearance of a page than is possible with skins, which are limited to those appearance properties exposed by the Web server controls. If you use appearance properties to define the look of the controls in a theme's skin, the downloaded size of the resulting rendered markup will be larger than the CSS approach, because these properties will be emitted in each HTML element. Finally, even with skins, CSS probably is still necessary to format plain HTML text.

Ultimately, then, your site is much more maintainable if as much formatting as possible is contained within CSS. If your site design requires a change in the font or color, it is much more preferable to change just one file (the style sheet), rather than having to change both a style sheet and multiple skins. Finally, another benefit of CSS is that if your Web Forms use CSS rather than HTML tables for layout, different themes could completely change the layout of the site, as was illustrated back in Figure 6.2.

Thankfully, you do not have to choose between CSS and themes. Each theme can in fact contain multiple CSS files. ASP.NET automatically links all of a theme's CSS files into a page by adding the appropriate <link> element for each CSS file into the header of a page. Note that each page must have the runat="server" attribute in the <head> for this to occur, as shown here.

<head runat="server">
   <title>Some title here</title>
</head>

Despite the benefits of CSS, there are several things that skins can do, which CSS cannot. Some server control properties that are themeable have no CSS equivalent. For instance, you can specify the textual format to display the days of the week in a Calendar control or the locations for the hot spots in an ImageMap control. As well, because themes are applied on the server side, it is possible to dynamically specify a theme based on user input or configuration information without the bother of Javascript-based CSS file swapping.

In addition, the more complex templated controls, such as Calendar, GridView, MultiView, Wizard, and so on, are probably styled more easily through skins, because it is up to ASP.NET to determine exactly what markup to use when rendering these controls. Yet even here, there still is a role for CSS. For example, in the following GridView skin definition (we cover the GridView control later in Chapter 10), the three style templates contain appearance properties.

<asp:GridView runat="server" GridLines="Vertical" >
   <HeaderStyle BackColor="#FF9900" ForeColor="#FFFFFF" />
   <RowStyle BackColor="#FFFFFF" ForeColor="#333333" />
   <AlternatingRowStyle BackColor="#F2F2F2" ForeColor="#333333"/>
</asp:GridView>

A better approach is to define the template styling information via CSS classes.

.gridHeader
{
   background-color: #FF9900;
   color: #FFFFFF;
}
.gridRow
{
   background-color: #FFFFFF;
   color: #333333;
}
.gridAltRow
{
   background-color: #F2F2F2;
   color: #333333;
}

With the CSS classes defined, you could then simply reference these classes in the skin, as shown here.

<asp:GridView runat="server" GridLines="Vertical" >
   <HeaderStyle CssClass="gridHeader" />
   <RowStyle CssClass="gridRow" />
   <AlternatingRowStyle CssClass="gridAltRow" />
</asp:GridView>

Again, the benefit of this approach is that the typical Web designer, who probably does not know ASP.NET, can still make changes to the visual appearance of the ASP.NET application by modifying the appropriate CSS files.

Dynamically Setting the Theme

One of the key benefits that themes provide to the Web developer is the ability to programmatically change a page's theme. A page's theme can be set programmatically in the code-behind class. However, you may recall from Figure 2.3 in Chapter 2 that theme skins are applied before the controls and page are initialized. Thus, you must set the page's Theme property in the PreInit event handler for the page, as shown here.

protected void Page_PreInit(object o, EventArgs e)
{
   // Set theme for this page
   this.Theme = "Cool";
}

The PreInit event is new to ASP.NET 2.0. It is raised just before the Init event of the page, but after the controls for the page have been instantiated. Of course, with the simple example shown earlier, it makes much more sense to simply set the theme in the Web.config or in the Page directive. The real advantage of using the programmatic approach is that the page's theme can be set dynamically based on user preferences. This preference can even be persisted in a user profile (covered in Chapter 14), in a session (covered in Chapter 12), or in a database.

Like with the Theme property, you can also set the StyleSheetTheme property programmatically. However, unlike with setting the Theme property, the programmatic setting of the StyleSheetTheme property is not done in the PreInit method, but is achieved by overriding the property in your code-behind class, as in the following.

public override String StyleSheetTheme
{
  get { return "Cool"; }
}

Setting the theme dynamically based on user input is not quite so straightforward. The problem lies in the fact that the theme needs to be set in the PreInit event of the page, which is before any of the controls have had their values loaded from the view state or the form input data. For example, imagine a page with a drop-down list by which the user can select the theme for the page. The list would have an event handler that would process the user's theme selection, but unfortunately you cannot set the page theme in this event handler. It has to be set before the postback event handling in the page's PreInit event. Yet during the PreInit event, you cannot yet know what the user selected!

The solution to this conundrum is that you need some way to store the user's theme selection in a way that is available to the PreInit event, and then reload the page so that the PreInit event is invoked again. How then can you store the user's theme selection? Later in Chapter 14, you will learn about the user profile system, which could be used for this problem. An alternative we will use here is to use ASP.NET session state (refer to Chapter 12 for more detail).

Session state allows you to store and retrieve values for a browser session as the user moves from page to page in the site. Recall that HTTP is a stateless protocol. This means that a Web server treats each HTTP request for a page as an independent request and retains no knowledge of code-behind data members or form values used during previous requests. ASP.NET session state provides a way to identify requests received from the same browser during a limited period of time and provides the ability to persist values for the duration of that session.

ASP.NET session state can be accessed from an ASP.NET Web Form via the Session property of the Page base class. This property references an object collection that is indexed by name. When you save an object in the session collection, you identify it by using a name, which can be any text string that you want. You can thus use session state to save the user's theme choice in the list event handler, as shown here.

protected void drpThemes_SelectedIndexChanged(object o,
      EventArgs e)
{
   // Save theme name in session. You identify this value
   // using "theme" but you could use any name
   Session["theme"] = drpThemes.SelectedItem.Text;

   // Re-execute page so PreInit event can be re-triggered
   Server.Transfer(Request.Path);
}

The PreInit event handler can now retrieve the user's choice using the following.

protected void Page_PreInit(object sender, EventArgs e)
{
   // Retrieve theme from session
   string theme = (string)Session["theme"];

   // Must make sure that session exists
  if (theme != null)
  {

     // Set the page theme
     this.Page.Theme = theme;
  }
  else
  {
     // Set default theme if nothing in session because no theme
     // has been selected yet (or the session has timed-out)
     this.Page.Theme = "Cool";
  }
}

Notice that retrieving the theme name from the session collection requires a casting operation (from object to string). Also, the method cannot assume that the session collection actually contains a theme name. It might be the first time the page has been requested and thus the theme does not exist yet in the session. Alternately, the session may have timed out and thus is empty. For this reason, any time you retrieve an item from session state, you must always verify that the item does exist, typically by comparing it to null.

Creating a Sample Page with Two Themes

To finish our coverage of themes, let's examine an example that demonstrates the dynamic selection of themes. The example page contains a drop-down list that allows the user to select one of two different themes to be applied to that page. The markup for this page is shown in Listing 6.3. Notice that the page contains no appearance markup, only structured content. All formatting is contained in the theme skins and CSS files.

Listing 6.3. ThemeTester.aspx

<%@ Page Language="C#" AutoEventWireup="true"
   CodeFile="ThemeTester.aspx.cs" Inherits="ThemeTester"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
   <title>Themes Tester</title>
</head>
<body>
   <form id="form1" runat="server">
      <div id="container">
         <div id="header">
            <asp:Image runat="server" ID="imgLogo" SkinID="logo"/>
         </div>
         <div id="menu">
            <asp:BulletedList ID="blstSample" runat="server" >
               <asp:ListItem Value="">Home</asp:ListItem>
               <asp:ListItem Value="">Products</asp:ListItem>
               <asp:ListItem Value="">About</asp:ListItem>
            </asp:BulletedList>
         </div>
         <div id="content">
            <h1>Technical Books</h1>
            <p>
            Microsoft. Cisco. IBM. Hewlett Packard. Intel. Adobe.
            Macromedia. There's a reason the top technology
            companies choose Pearson Education as their publisher
            partners. Publishing over a thousand new titles each
            year, much of our content is also available online -
            so busy professionals and students can access it from
            any computer, day or night.
            </p>
            <div id="register">
               <fieldset>
                   <legend>Contact Us</legend>
                   <asp:Label ID="labName" runat="server"
                      AssociatedControlID="txtName"
                      Text="<u>N</u>ame" />
                   <br />
                   <asp:TextBox ID="txtName" runat="server"
                     AccessKey="n" TabIndex="1" /><br />
                   <asp:Label ID="labEmail" runat="server"
                      AssociatedControlID="txtEmail"
                      Text="E<u>m</u>ail" /><br />
                   <asp:TextBox ID="txtEmail" runat="server"
                      AccessKey="m" TabIndex="2" /><br />
                   <asp:Label ID="labZip" runat="server"
                      AssociatedControlID="txtZip"
                      Text="<u>Z</u>ip" /><br />
                   <asp:TextBox ID="txtZip" runat="server"
                      AccessKey="z" TabIndex="3" /><br />
                   <asp:Button ID="btnSubmit" runat="server"
                      Text="Send" TabIndex="4" AccessKey="d" />
               </fieldset>
            </div>
            <p>
            <asp:DropDownList ID="drpThemes" runat="server"
                  AutoPostBack="True"
                  OnSelectedIndexChanged=
                   "drpThemes_SelectedIndexChanged" >
               <asp:ListItem>Pick a theme</asp:ListItem>
               <asp:ListItem>Cool</asp:ListItem>
               <asp:ListItem>Professional</asp:ListItem>
            </asp:DropDownList>
            </p>
         </div>
      </div>
   </form>
</body>
</html>

The markup contains a drop-down list that allows the user to select the theme. The code-behind for the page performs this processing, as shown in Listing 6.4.

Listing 6.4. ThemeTester.aspx.cs

public partial class ThemeTester : System.Web.UI.Page
{
   /// <summary>
   /// Set the page's theme based on the user's selection
   /// </summary>
   protected void Page_PreInit(object sender, EventArgs e)
   {
      // Retrieve theme from session
      string theme = (string)Session["theme"];

      // Must make sure that session exists
      if (theme != null)
      {
         this.Page.Theme = theme;
      }
      else
      {
         // Set default theme
         this.Page.Theme = "Cool";
      }
   }
   /// <summary>
   /// Process the user's theme choice by saving it in
   /// session state
   /// </summary>
   protected void drpThemes_SelectedIndexChanged(object sender,
         EventArgs e)
   {
      // Ignore the first item ("pick a theme") in list
      if (drpThemes.SelectedIndex != 0)
      {
         // Save theme in session
         Session["theme"] = drpThemes.SelectedItem.Text;

         // Re-request page
         Server.Transfer(Request.Path);
      }
   }
}

By keeping your markup devoid of appearance formatting, it can be quite radically transformed by your themes. This example has two different themes: one called Cool and the other called Professional. Figure 6.7 illustrates how this page appears in its two themes (the Cool theme is the one on the right with two layout columns).

Figure 6.7

Figure 6.7 ThemeTester.aspx with its two themes

The skins for these two themes (shown in Listings 6.5 and 6.6) are quite similar as well as quite straightforward. Notice that both skins delegate the actual formatting to each theme's CSS file.

Listing 6.5. Cool.skin

<asp:Image runat="server" ImageUrl="images/cool.gif"
   AlternateText="Masthead Image" SkinID="logo" />

<asp:BulletedList runat="server"
   BulletStyle="CustomImage"
   BulletImageUrl="images/bullet.gif"
   DisplayMode="HyperLink" />

<asp:TextBox runat="server" CssClass="txtBox" />

<asp:Button runat="server" CssClass="myButton"/>

Listing 6.6. Professional.skin

<asp:Image runat="server" ImageUrl="images/prof.gif"
   AlternateText="Masthead Image" SkinID="logo" />

<asp:BulletedList runat="server" BulletStyle="NotSet"
   DisplayMode="HyperLink"/>

<asp:TextBox runat="server" CssClass="txtBox" />

<asp:Button runat="server" CssClass="myButton"/>

As mentioned, the majority of the heavy lifting for these themes is done by the CSS file for each theme. Listings 6.7 and 6.8 contain the content of each CSS file. The two CSS files are similar in that they use class, ID, and descendant selectors to specify the text formatting and the positioning for the different elements in your Web Form. The professionalStyles.css file is the easier of the two to understand because it contains no positioning styles. The only complexity in this style sheet is how the unordered list items are turned into a horizontal menu—that is, by turning off the bullets (list-item: none), keeping the list items together on a single line (display: inline), and by styling the link and hover pseudo elements.

Listing 6.7. professionalStyles.css

body {
   background-color: White;
   font-size: small;
}

h1 {
   margin-top: 3em;
   font-family: Georgia, Times New Roman, serif;
   font-size: 1.2em;
   padding-bottom: 4px;
   border-bottom: 1px solid #cc0000;
   color: #666666;
   text-transform: uppercase;
   letter-spacing: 0.4em;
}

p {
   font: normal .8em/2.0em Verdana, Arial , sans-serif;
}

#container {
   position: relative;
   top: 30px;
   left: 30px;
   width: 400px;
}

/* style the list as a horizontal menu */
#menu {
   font-family: Verdana, Arial , sans-serif;
   font-size: 0.9em;
}

#blstSample {
   margin-left: 0;
   padding-left: 0;
   white-space: nowrap;
}

#blstSample li {
   display: inline;
   list-style: none;
   text-transform: uppercase;
}

#blstSample a {
   font-weight: bold;
   padding: 3px 10px 3px 20px;
   margin-right: 2px;
}

#blstSample a:link, #blstSample a:visited {
   text-decoration: none;
   color: white;
   background-color: Gray;
}

#blstSample a:hover {
   color: #cc0000;
   border-bottom: 4px solid #cc0000;
   padding-bottom: 2px;
   text-decoration: none;
   background: url(images/bullet.gif) no-repeat 0 50%;
   background-color: white;
}

/* style the form elements */
fieldset {
   border: 1px solid #cc0000;
   padding: 1em;
}

.txtBox {
   border:1px solid #666666;
   margin: 0.2em 0 0.8em 0.2em;
}

.myButton {
    border:1px solid gray;
    color:#FFFFFF;
    background-color:#FF9900;
    font-size:1em;
    font-weight: bold;
    margin: 0.2em 0 0.8em 0.2em;
}

label {
   font: normal 0.8em Verdana, Arial , sans-serif;
   margin: 0.2em 0 0 0.2em;
}

legend {
   font-family: Georgia, Times New Roman, serif;
   font-size: 1em;
   font-weight: bold;
   color: #666666;
   text-transform: uppercase;
   letter-spacing: 0.2em;
}

The coolStyles.css file is a bit more complex. It uses CSS positioning and margins to place the menu <div> and the content <div> into two separate columns. The menu <div> is floated to the left (float: left) of the subsequent content in the form (the content <div>) and given a specified width. The content <div> is given a left margin that places all of the content to the right of the menu <div>. One interesting feature of this CSS file is the use of the so-called Tan Hack to deal with a bug with Internet Explorer 6.0 and earlier. In this case, Internet Explorer is adding the content <div> left margin setting to the form's <input> elements (the TextBox and Button controls). To fix this problem, the style sheet uses the * html selector (which is only supported by IE) to override the correct margin settings and apply a negative margin. The rest of the CSS is simple text formatting.

Listing 6.8. coolStyles.css

body {
   background-color: #0A4581;
   font-size: small;
}

h1 {
   margin-top: 0;
   padding: 0.2em;
   font-family: Verdana, Tahoma, Helvetica, Arial, sans-serif;
   font-size: 1.2em;
   background-color: #ABC6EE;
   color: #666666;
}

P {
   font: normal .9em/2.2em Verdana, Helvetica, Arial, sans-serif;
}

/* style each of the principle div elements */
#container {
   width: 90%;
   margin: 10px auto;
   background-color: #ffffff;
   color: #333333;
   border: 1px solid gray;
}

#content {
   margin-left: 16em;
   border-left: 1px solid gray;
   padding: 1em;
}


#header {
   padding: 0;
   height: 92px;
   background: url(images/header_background.gif);
}

/* style the list as a vertical list of links */
#menu {
   float: left;
   color: black;
   width: 9em;
   margin: 1em;
   padding: 0.5em;
   border: 1px solid #000;
   font-family: Verdana, Tahoma, Helvetica, Arial, sans-serif;
   background-color: #ABC6EE;
}

#blstSample li {
   padding-top: 0.4em;
}
#blstSample a:link, #blstSample a:visited {
   text-decoration: underline; color: blue;
}
#blstSample a:hover   {
   color: #cc0000;
   border-bottom: 3px solid #cc0000;
   text-decoration: none;
}

/* style the form elements */
#register {
   font-family: Verdana, Tahoma, Helvetica, Arial, sans-serif;
}

fieldset {
   border: 1px solid #666666;
   padding: 1em;
}

legend {
   font-size: 1em;
   font-weight: bold;
   color: #666666;
   text-transform: uppercase;
   letter-spacing: 0.2em;
   background-color: #ABC6EE;
   border: 1px solid #666666;
}

.txtBox {
   border:1px solid #666666;
   margin: 0.3em 0 0.8em 0.2em;
}

/* IE 6 adds the #content margin to the text box and button so we
   must give the text boxes and buttons a negative margin using
   a CSS format only understood by IE (which will override the
   margin set in the .txtBox rule just above).
*/
* html .txtBox { margin-left: -16em; }
* html .myButton { margin-left: -16em; }

label {
   font: normal 0.8em Verdana, Arial , sans-serif;
}

One other feature worth mentioning about these two themes is their use of em units for sizing. By avoiding the use of pixels, these two layouts still work even if users change the display size of the text in their browser (see Figure 6.8). We could have achieved a similar result as well by using percent units (e.g., font-size: 90%;) for sizing.

Figure 6.8

Figure 6.8 Cool theme with different user-selected font sizes

The em unit is the size of the character box for the element's parent. If no other font sizes are specified in other containers, a font size of 1em is equivalent to the default font size (determined by the browser). The principle used in these styles is to set the default font size in the body to small, and then make all other dimensions relative to whatever the browser sets for the small font size.

body { font-size: small; }
h1 { font-size: 1.2em; }
p { font-size: 0.8em; }

If the browser's font size for small is 14px, the h1 is displayed at around 17px (14 x 1.2) and the p is displayed at around 11px (14 x 0.8). If the user increases the size of her text through browser preferences, so that small is now 18px, the h1 and the p are 21 and 14 pixels, respectively (18 x 1.2 and 18 x 0.8).

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020