13

Eric Meyer on CSS in CSS

Self-plagiarism is style.
—Alfred Hitchcock

Design ideas often are sparked by things we see in the real world. A billboard ad, a magazine article, or a book's layout can be the source of inspiration. As this book was being written and designed, an idea came to me: What if I created a project that did its best to re-create the look of the book itself? Doing so would require an array of skills and techniques, making it an excellent way to bring together everything discussed elsewhere in the book. It would present a unique challenge: to take a design I had not created myself and see how closely I could reproduce it.

When the book's final design arrived, I knew it was a challenge I had to accept. Therefore, this project will be devoted to re-creating the design of the book itself and translating it into HTML and CSS. This will not be a completely realized goal, and what we do not do (and the reasons why we don't) should be as instructive as what we do.

Project Goals

Given that we're going to be re-creating the visual layout of the book you're reading right now, the primary goal in a sense is to give you a sense of dèjá vu when working through the project. On a more practical level, the goals are twofold:

These are broad generalizations, of course, but with this project, every piece will almost be its own mini project, so it's difficult to articulate specific goals. We'll just have to dive in and see where things take us—so let's get to it!

Preparation

Web

See the introduction for instructions on how to download the files from the Web site.

Download the files for Project 13 from this book's Web site. If you're planning to play along at home, load the file ch13proj.html into the editing program of your choice. This is the file you'll be editing, saving, and reloading as the project progresses.

Laying the Groundwork

Flipping through the book will bring one fact immediately to your eye: There are effectively two columns on every page, the main text and the sidebar. In print, the sidebar is always on the outer edge of the page, opposite the spine of the book. We could make the sidebar flip from side to side every few paragraphs, but that would be really annoying. We'll put the sidebar on the right side of the design.

In doing so, however, we're going to have to figure out how to get the notes and figure captions to their proper locations. The obvious choice might be to position them, but that contains a hidden danger: If two sidebar elements are too close together, they could vertically overlap each other with no way to prevent it. If we float them, we can make sure they don't overlap by using the property clear. This approach is more robust for our purposes, but it brings its own problems to the party, as we'll see very soon.

Beyond that, it's a matter of making sure the content itself is properly structured so that it can be styled. Paragraphs should be contained in the p element, titles in h3 and h4 elements, sidebar notes in appropriately classed divs, and so on. Instead of trying to figure all that out ahead of time, we'll just look at each piece, figure out how it should be structured, and then style it.

Styling the Document

Because our goal is to reproduce the book's layout, we can use it as a point of comparison as we work through the project. There are many ways to attack this problem, but we'll start by addressing the fundamental basis of the book's design: the two-column layout it uses to put notes and captions into a sidebar.

The Sidebar

In setting up the sidebar, we really only need to ensure that there's a border separating sidebarit from the main content and that the notes and captions actually make it into the sidebar. This turns out to be a lot trickier than one might have hoped.

We could wrap all of the content in a div and then give the sidebar elements a negative right margin to pull the floats into the sidebar. That would let us set a right border on the content div, thus ensuring that the border would be as tall as the main content itself. The floats, with their negative margin, would be placed just outside the border. Unfortunately, taking that approach trips across a number of bugs in Internet Explorer for Windows that exist through IE6. These bugs are bad enough that they lead to a near-complete breakdown of the layout in IE/Win, and working around the bugs causes a similar breakdown in almost any other browser.

We could break the content up into multiple divs with class values like main and sidebar. This would avoid most of IE/Win's bugs and would make it a lot easier to work around the rest. That's an awful lot of structural hacking, though, so let's not do that either.

Here's a thought: How about giving the various "top-level" elements in the document a wide right margin to open up the space? That way, we can avoid adding a div for the sole purpose of creating the columns and can also avoid IE/Win's flaws. It's important to make sure we get all of the elements that are children of the body element, but fortunately, the content lends itself fairly well to such an effort. Creating the first rules in our style sheet has the result shown in Figure 13.1.

<head>
<title>Project 13</title>
<style type="text/css">
body {margin: 0; padding: 0; color: black;
  background: white;}
h1, h2, h3, h4, h5, p, pre, table, div {margin-right: 22%;
  margin-left: 8%; padding: 0;}
ul, ol {margin-right: 25%; margin-left: 13%; padding: 0;}
div.listing pre {margin: 0;}
</style>
</head>
figure
Figure 13.1

Applying margins to elements within the body to create a column effect.

Tip
Extra Indentation

The masthead is indented further than the rest of the text because it's all enclosed in a div. Thus the elements inside the masthead div get offset by both the left margin on the div and their own left margins. We'll fix that in the next section.

This results in a content column that's 70% of the width of the body element. It's not really a column, of course, but it creates the illusion of one. The reason for using the value 22% for the right margin will become clear in just a bit. The list margins are made a little bit wider than other elements because we want them to be indented a bit as compared to the normal text flow. The rule for div.listing pre has been inserted to avoid problems in IE/Win as we move forward. (It's a rule we would have written anyway, but including it now will prevent confusion as we work on the project.)

Now all we need to do is figure out how to draw a line between the main column and the sidebar. We could try to draw a right border on every element to which we just gave a 22% right margin, but then we'd have to enforce vertical separation with padding, and it would start to get messy. Furthermore, not all elements touch the separator line. If the line is created from the borders of content elements, they all effectively touch it.

Instead, let's borrow a trick from the old days of Web design and rework it a bit. Remember single-pixel GIF tricks? We're going to use one here by taking a 1-pixel GIF that's the appropriate shade of blue and applying it to the background of the body element. If we position it correctly and then only tile it vertically, we'll get a separator line, as shown in Figure 13.2.

<style type="text/css">
body {margin: 0; padding: 0; color: black;
  background: white url(blue.gif) 80% 0 repeat-y;}
h1, h2, h3, h4, h5, p, pre, table, div {margin-right: 22%;
  margin-left: 8%; padding: 0;}
figure
Figure 13.2

A simple background image on the body creates the separation between "columns."

Remember setting all those right margins to be 22%? Because the right margins are all 22% and the line has been placed at 20% of the distance from the right edge of the body element, there's a 2% space between the element edges and the line. Thus, we've created the slight distance between the content and the separator line.

The Masthead

Tip
Delayed Images

The three preview images that also appear on the project's first page are not part of the masthead, nor are they even present in the current project file. We'll get to them in the next section.

With the content column set up, let's turn to the masthead: the light blue box that leads off every project with the number, title, and epigram for that project. If we look at the markup for the masthead, we find this:

<div id="masthead">
<h1>13</h1>
<h2><cite>Eric Meyer on CSS</cite> in CSS</h2>
<blockquote>Self-plagiarism is style.</blockquote>
<div id="attrib">&mdash;Alfred Hitchcock</div>
</div>

Thanks to the div that encloses the masthead's content, creating the blue box is fairly simple. We want the masthead to fill the entire space between the left edge of the body and the separator line, and we can do this with margins. The border is simple as well: Set up a 1-pixel border on the right and bottom edges of the masthead. Finally, to keep the content from getting too close to the top or bottom of the masthead, we'll give the div some padding.

ul, ol {margin-right: 25%; margin-left: 13%; padding: 0;}
div#masthead {margin: 0 20% 2.5em 0; padding: 2em 0 1.5em 0;
  border: 1px solid #006; border-width: 0 1px 1px 0;
  background: #BDF;}
</style>
Tip
Different-Size Caps

IE5 for Windows will render small-caps text in all uppercase letters. This is technically permitted in CSS1, but it might not be a desirable effect. We'll keep using small-caps text in this project, but exercise caution in your own projects.

To style the epigram, all we need is a few styles. The quotation, enclosed in a blockquote, should be slightly smaller than normal and italicized. The attribution should be the same, plus it needs to be over to the right and set in a small-caps font, as illustrated in Figure 13.3.

div#masthead {margin: 0 20% 2.5em 0; padding: 2em 0 1.5em 0;
  border: 1px solid #006; border-width: 0 1px 1px 0;
  background: #BDF;}
div#masthead blockquote {font-size: 90%; font-style: italic;}
div#attrib {font-size: 90%; font-style: italic;
  text-align: right; font-variant: small-caps;}
</style>
figure
Figure 13.3

Laying down the basics of the masthead with some borders and a background.

Things are shaping up pretty well except for the left edge of the content, where things are a bit ragged. It would be nice to have everything line up, but this would require giving them all the same left margin. Let's start out with the blockquote and its left margin along with the rest of its sides.

div#masthead blockquote {font-size: 90%; font-style: italic;
  margin: 2em 22% 0.5em 10%;}

The top and bottom margins just help keep it separate from the other masthead content, of course. The right margin is large enough to make sure a long quotation doesn't get too close to the separator line, and the left margin will line up the quotation with the main content. Let's make similar changes to the h1 and h2 elements and set their font sizes.

ul, ol {margin-right: 25%; margin-left: 13%; padding: 0;}
h1 {font-size: 300%; margin: 0.5em 0 0.5em 10%;}
h2 {font-size: 200%; margin: 0 0 0.66em 10%;}
div#masthead {margin: 0 20% 2.5em 0; padding: 2em 0 1.5em 0;
  border: 1px solid #006; border-width: 0 1px 1px 0;
  background: #BDF;}

At first glance this seems fine, but there's a small mistake lurking in our styles. To reveal it, we need only give the h1 a bottom border:

h1 {font-size: 300%; border-bottom: 2px solid white;
  margin: 0.5em 0 0.5em 10%;}

The problem is that the border stretches from the separator line to just to the left of the number 13 instead of continuing on to the left edge of the browser window. To fix this, we'll need to eliminate the h1's left margin and compensate with left padding.

h1 {font-size: 300%; border-bottom: 2px solid white;
  margin: 0.5em 0 0.5em 0; padding: 0 0 0.125em 10%;}

Finally, we should change the font of the title to look a little more like what we have in print. Using the exact same font isn't really a possibility, but we could roughly approximate the feel of the print version by using small-caps. Because all of the titles and headings (except for h5 elements) in the book look the same, we'll set them all to be small-caps in our project. The result can be seen in Figure 13.4.

ul, ol {margin-right: 25%; margin-left: 13%; padding: 0;}
h1, h2, h3, h4 {font-variant: small-caps;}
h1 {font-size: 300%; border-bottom: 2px solid white;
  margin: 0.5em 0 0.5em 0; padding: 0 0 0.125em 10%;}
figure
Figure 13.4

The masthead is finished with nicely styled content.

Matching Fonts in CSS

Even though it's easy to change the font of an element using CSS, it's hard to change to any but the most common fonts. This is because a Web browser is completely dependent on the fonts installed on the user's machine. You can specify that an element should be displayed using the font New Century Schoolbook, as follows:

p {font-family: "New Century Schoolbook", serif;}

This will work fine on any computer that has the font installed. If the font isn't available, however, the user's default font will be used instead. This is why we aren't trying to precisely reproduce the title font used in the book.

Obviously, this dilemma could be solved if the author could specify a font to be downloaded and used in a Web page. At the height of the browser wars, Netscape and Microsoft each invented its own method for font downloading, and neither one supported the other. When CSS2 was released, it provided font description and downloading features that matched neither Microsoft nor Netscape's mechanisms. For the time being, cross-browser downloadable fonts remain solidly in the realm of wishful thinking.

Placing the Previews

There's one last thing to do here at the top of the document and that's drop in the three preview images that appear on the first page of each project. These previews are reproductions of figures that appear elsewhere in the project. Here, we'll just point to the images we want and place them appropriately.

It's important to put the images at the correct spot in the markup, however. Because we want them to start out next to the masthead and we need to float them over to the side, we need to insert the images before the masthead itself.

<body>
<div id="previews">
<img src="13CSS03.jpg" alt="preview 1">
<img src="13CSS10.jpg" alt="preview 2">
<img src="13CSS15.jpg" alt="preview 3">
</div>
<div id="masthead">
<h1>13</h1>

Now all we have to do is float the div and size the images.

div#attrib {font-size: 90%; font-style: italic;
  text-align: right; font-variant: small-caps;}
div#previews {float: right; width: 33%; margin: 0; text-align: center;}
div#previews img {width: 80%; margin-top: 1em;}
</style>

You might note that the div is wider than the 20% margins set for the main content. That's because, as in the print version, we want the preview images to stick out of the sidebar. We've made the images 80% of the width of their containing div, and the text-align value will center them in the div. This will push them away from the edge of the body (see Figure 13.5).

figure
Figure 13.5

Re-creating the preview images with a few changes that make life easier.

This isn't exactly the same as the print version, of course. We're still missing the rounded-corner boxes that surround the images and the dark blue background for the sidebar. We could attempt to re-create these effects, but we won't. Why not? For the boxes, it would take a great deal of effort and structural hacking to make them look right, and it just isn't worth the effort for so small a part of the design. The dark blue background, on the other hand, is being omitted because it would look fairly strange to have the dark blue suddenly stop just below the images and leave an empty sidebar below it. So we're going to skip re-creating those effects and move on to the main content.

Title Spacing

As soon as we hit the first heading, "Project Goals," we can see that the spacing is off as compared to the print version. It needs to be moved down closer to the text following and further away from the paragraph before it. The same is true of all h3, h4, and h5 elements, so we'll style them all together.

h1, h2, h3, h4 {font-variant: small-caps;}
h3, h4, h5 {margin-top: 1.25em; margin-bottom: 0;}
h1 {font-size: 300%; border-bottom: 2px solid white;
  margin: 0.5em 0 0.5em 0; padding: 0 0 0.125em 10%;}
Tip
Interparagraph Spacing

Although we've reduced the top margin on paragraphs, two paragraphs in a row will still be about 1em apart because the default bottom margin for paragraphs is still in effect. Because vertically adjacent margins collapse and the distance between element borders is always the greater of the two margins, the 1em bottom margin will preserve traditional interparagraph spacing.

That in itself isn't enough, though. If we want the titles to get close to the following text, we also need to reduce the top margin on paragraphs. While we're at it, we'll also set a slightly larger line-height.

h2 {font-size: 200%; margin: 0 0 0.66em 10%;}
p {margin-top: 0.5em; margin-bottom: 1em; line-height: 1.2em;}
div#masthead {margin: 0 20% 2.5em 0; padding: 2em 0 1.5em 0;
  border: 1px solid #006; border-width: 0 1px 1px 0;
  background: #BDF;}

We also ought to increase the size of the h3 element, which is bigger in print as compared to the normal text size (see Figure 13.6).

h2 {font-size: 200%; margin: 0 0 0.66em 10%;}
h3 {font-size: 150%;}
p {margin-top: 0.5em; margin-bottom: 1em; line-height: 1.2em;}
figure
Figure 13.6

Touching up the paragraphs and setting the title spacing to match the book.

Since we've started sizing heading elements, let's fill in sizes for the rest of them. That way, we won't have to worry about it later on.

h3 {font-size: 150%;}
h4 {font-size: 110%;}
h5 {font-size: 100%;}
p {margin-top: 0.5em; margin-bottom: 1em; line-height: 1.2em;}

With that accomplished, let's figure out how to liven up our bulleted lists.

Bulleted Lists

Just a little bit into the "Project Goals" section, we find an unordered list. In this book, such lists have small blue diamonds for bullets instead of the usual block dot. So long as we have an appropriately sized graphic file that shows a blue diamond on a white background, we can make use of it.

div#previews img {width: 80%; margin-top: 1em;}
ul li {list-style: outside square url(diamond.gif);}
</style>

It's also the case that such lists are separated a little bit from each other. We could fiddle around with the line-height of the list items, but there is a better way: increasing either the margin or the padding of the list items. The only real difference between the two is that if we ever wanted to set background colors on the lists, with an increased margin, the backgrounds would touch and create one big block of color. We won't be doing that, however, because it's not how lists look in this book, so we'll increase the bottom margin of the li elements. This has the result shown in Figure 13.7.

ul li {list-style: outside square url(diamond.gif);
  margin-bottom: 0.5em;}
figure
Figure 13.7

Using images to replace boring bullets with dazzling diamonds.

Sidebar Notes

Moving into the "Preparation" section, we find our first second-column note. This is one of the green Web site notes, and it is unusual compared to the blue notes and red warnings for one reason: Web notes don't have titles. Here's the markup for the Web note:

<div class="note web">
<img src="web-icon.gif" alt="Web">
<p>
See the introduction for instructions on how to download the files 
from the Web site.
</p>
</div>

Here's the markup for one of the blue notes:

<div class="note tip">
<img src="tip-icon.gif" alt="Tip">
<h5>Delayed Images</h5>
<p>
The three "preview" images that also appear on the project's first page 
are not a part of the masthead, nor are they even present in the current 
project file.  We'll get to them in the next section. 
</p>
</div>

Structurally speaking, the only difference between the two is the h5 element. Of much greater importance are the class values for these two notes. We can see that both have the word note, and a quick search through the HTML shows that all sidebar notes share this value. Then comes another word that describes the kind of note (the possibilities being web, tip, and warn).

Thus, any styles that are common to all notes can be written into one rule, and the styles specific to each type will go into its own rules. We want to float the notes into the sidebar, but we also want to make sure that any note will appear below another note and not to its left. If we throw in a width and some margins, we have the start depicted in Figure 13.8.

ul li {list-style: outside square url(diamond.gif);
  margin-bottom: 0.5em;}
div.note {float: right; clear: right; border-width: 0;
  width: 19%; margin: 0 1% 0 0; padding: 0;}
</style>
figure
Figure 13.8

The first steps toward styling second-column notes to match the print version.

It turns out that Explorer for Windows has a bit of trouble with the styles we've just added; it thinks for some reason that 19% plus 1% equals more than 20%. So we'll use the voice-family trick to give IE/Win the value it needs while still delivering the correct number to other, more robust browsers.

Tip
Hacking voice-family

For a discussion of the voice-family trick and other ways to use browser bugs to your advantage, see Appendix B, "Tricking Browsers and Hiding Styles."

div.note {float: right; clear: right; border-width: 0;
  width: 18%; margin: 0 1% 0 0; padding: 0;
  voice-family: "\"}\""; voice-family:inherit;
  width: 19%;}

Obviously, we're going to want to move the icon over to the right. Because images are inline content just like text, we could right-align it using text-align. However, we want the title and paragraph text to be left-justified.

div.note {float: right; clear: right; border-width: 0;
  width: 18%; margin: 0 1% 0 0; padding: 0;
  text-align: right;
  voice-family: "\"}\""; voice-family:inherit;
  width: 19%;}
div.note h5, div.note p {text-align: left;}
</style>

We still need to make the text smaller than normal and set it in a sans-serif font like the one used in the book. It's easiest to do this on the div itself.

div.note {float: right; clear: right; border-width: 0;
  width: 18%; margin: 0 1% 0 0; padding: 0;
  text-align: right; font: 80% Arial, Verdana, Helvetica, sans-serif;
  voice-family: "\"}\""; voice-family:inherit;
  width: 19%;}

Now let's turn our attention back to the actual contents of the notes. The image element lacks the attributes height and width, so we need to supply those values through CSS. Also, we want to make sure the text in the notes stands a little bit away from the sidebar's border and runs over to the right edge of the note's div. This yields the following:

div.note h5, div.note p {text-align: left; margin-left: 1em; margin-right: 0;}
div.note img {height: 30px; width: 30px; margin: 0;}
</style>

Finally, we need to connect the icon to the separator line with a dark blue horizontal line. Why not reuse the trick employed to create the separator line itself? We know the icon is 30px tall and is in the top-right corner of the note. Therefore, we can draw a line in the background of the div that's 15px from the top of the div by repeating the single-pixel file in the horizontal direction, as shown in Figure 13.9.

div.note {float: right; clear: right; border-width: 0;
  width: 18%; margin: 0 1% 0 0; padding: 0;
  text-align: right; font: 80% Arial, Verdana, Helvetica, sans-serif;
  background: transparent url(blue.gif) 50% 15px repeat-x;
  voice-family: "\"}\""; voice-family:inherit;
  width: 19%;}
figure
Figure 13.9

With only a very few styles, we've gotten close to reproducing the note's original look.

Now all we need to do is set the color for the text and pull the text upward so that it's closer to the line we just drew. We shouldn't assign the same color value to all notes, though; remember that each type of note has different-colored text. This is where the second word in each note's class comes in handy.

div.note img {height: 30px; width: 30px; margin: 0;}
div.web {color: #399;}
div.tip {color: #006;}
div.warn, div.warn code {color: maroon;}
</style>
Tip
Inheriting Styles

Another way to get warning code text to match its parent would be to use the value inherit in a new rule: div.warn code {color: inherit;}. This value is fairly well supported by browsers, and we didn't use it solely because it wasn't any more efficient than the method we chose.

We've added in a selector to color any code text in a warning the same as the text that surrounds it. This overrides an earlier rule that made all code elements dark blue.

As for moving the text upward a bit, that calls for some caution. We can just set a negative top margin to accomplish this, but we don't want text to overlap the icons. Therefore, we need to make sure that whatever element comes first in the various types of notes has a right margin that leaves space for the icon. In Web notes, the first element is always a paragraph.

div.note img {height: 30px; width: 30px; margin: 0;}
div.web p {margin: -10px 30px 0 1em;}
div.web {color: #399;}

The right margin of 30px, being the exact width of the icon, should prevent any overlap between text and image. We need to apply similar styles to the first element of blue notes and red warnings, always an h5. These note titles are not in small-caps text, so let's get rid of that styling and make them normal again.

div.note img {height: 30px; width: 30px; margin: 0;}
div.note h5 {margin: -5px 30px 0 1em; padding: 0;
  font-variant: normal;}
div.web p {margin: -10px 30px 0 1em;}

The padding: 0; set for the note titles is mostly for insurance because one never knows when a browser might decide to use padding instead of margins to open up space around heading elements.

We also need to make sure any code text within the notes is legible. In many browsers, code text is smaller than normal text. In the context of the notes, we want it to be about the same size as the paragraph text, as illustrated in Figure 13.10.

div.web p {margin: -10px 30px 0 1em;}
div.note code {font-size: 100%;}
div.web {color: #399;}
figure
Figure 13.10

A blue note that mirrors the printed version closely.

Of course, the lines won't break in exactly the same places in the Web version as they do in print, and this can make notes taller or shorter than they are on the page. Even so, the resemblance is close enough to move on to making code, changed or otherwise, stand out.

Code Blocks and Fragments

In the section titled "Laying the Groundwork," we find that some text has been enclosed in code elements. Consider, for example, the third paragraph:

<p>
Beyond that, it's a matter of making sure the content itself is properly 
structured so that it can be styled.  Paragraphs should be contained in 
the <code>p</code> element, titles in <code>h3</code> and 
<code>h4</code> elements, sidebar notes in appropriately 
<code>class</code>ed <code>div</code>s, and so on.  Instead of trying to 
figure all that out ahead of time, we'll just look at each piece, figure 
out how it should be structured, and then style it.
</p>
Tip
Fighting code Spread

Depending on the monospace font that gets used by the browser, the code elements might look a bit spread out. One way to fix this would be with a negative value for letter-spacing.

In the book, such pieces of code are set in a monospace font and are colored dark blue. That's incredibly simple to reproduce, of course, but let's wait a moment. Blocks of code are set in the same monospace font as the code elements, but they aren't blue. Looking at the source, we find that these blocks are pre elements. So we'll write the following:

p {margin-top: 0.5em; margin-bottom: 1em; line-height: 1.2em;}
code, pre {font-family: "Courier New", Courier, monospace;}
code {color: #006;}
div#masthead {margin: 0 20% 2.5em 0; padding: 2em 0 1.5em 0;
  border: 1px solid #006; border-width: 0 1px 1px 0;
  background: #BDF;}

In the book, code blocks often have portions that are dark red, indicating changes that are being made to the project. Let's take a closer look at one of the code blocks from the HTML document.

<pre>
ul li {list-style: outside square url(diamond.gif);
  <b>margin-bottom: 0.5em;</b>}
</pre>

It's interesting that changes are marked using a b element, which is the deprecated boldface element. In the book, the changes are dark red and not boldfaced. Rather than try something complicated like replacing the b elements with spans, let's just work with what we have. In addition, let's make sure the code block text is indented a bit as compared to normal text and is smaller as well (see Figure 13.11).

code {color: #006;}
pre {margin-left: 10%; font-size: 80%;}
pre b {color: maroon; font-weight: normal;}
div#masthead {margin: 0 20% 2.5em 0; padding: 2em 0 1.5em 0;
  border: 1px solid #006; border-width: 0 1px 1px 0;
  background: #BDF;}
figure
Figure 13.11

Code fragments and code blocks stand out better thanks to their new styles.

Figures

Now, at long last, we come to one of the most challenging parts of this project: figures and their captions. Handling the layout of these structures will require not only CSS but a little bit of added HTML as well.

First let's examine the markup we already have for figures, using the figure from earlier in the project.

<div class="figure">
<img src="13CSS04.jpg" height="300" width="400" alt="figure">
</div>
<div class="caption">
<h5>Figure 13.4</h5>
<p>
The masthead is finished with nicely styled content.
</p>
</div>

Although there are many ways in which a figure and its caption could be structured, this one is actually very useful. Because the figure is in one div and the caption is in another, we can easily float them next to each other, sending the picture to the left and the caption to the right. Let's do the figure first.

div.warn, div.warn code {color: maroon;}
div.figure {float: left; width: 75%; margin: 0; padding: 0;}
</style>
Tip
Why We Float

Although it might seem like we can just let the caption flow into the space to the right of the figure itself, doing so would have severe drawbacks in this situation, as we'll see shortly.

In doing this, we leave enough room for the caption to go into the sidebar plus 5% more. (This avoids some problems in IE/Win.) Let's now float the caption to the right, using the same basic declarations as we did with the notes. Our progress to date is shown in Figure 13.12.

div.figure {float: left; width: 75%; margin: 0; padding: 0;}
div.caption {float: right; width: 18%; padding: 0 1% 0 0; margin: 0;
voice-family: "\"}\""; voice-family:inherit;
  width: 19%;}
</style>
figure
Figure 13.12

The figure and its caption have been floated, but there's still much work to be done.

The figure is out of alignment, but let's worry about that after the caption is styled. The simplest part is the actual caption text, which is contained in a p element. Re-creating its appearance is a snap.

div.caption {float: right; width: 18%; padding: 0 1% 0 0; margin: 0;
  voice-family: "\"}\""; voice-family:inherit;
  width: 19%;}
div.caption p {font: italic 80% Arial, Verdana, Helvetica, sans-serif;
  color: #555;}
</style>

Re-creating the top border of the caption might seem simple because we have to set a top border on the div itself. What makes it a little bit trickier is the way in which the line sticks into the main column. We'll set the border and see how close we get to the look we want.

div.caption {float: right; width: 18%; margin: 0 1% 0 0; padding: 0;
  border-top: 1px solid #006;
  voice-family: "\"}\""; voice-family:inherit;
  width: 19%;}

That gets us a top border that stops at the separator line. If we hadn't floated the caption, the line would have gone all the way across the page to the left side of the screen, thanks to the way floats affect backgrounds and borders. By floating the caption, we avoided that problem.

To extend the line to the left, we'll have to add some left-side padding. In the course of doing so, we need to adjust the first width value so that IE/Win doesn't mess things up too much. Unfortunately, it thinks that any padding on a floated element is calculated with respect to the size of the float, so if we said 25% left padding, it would make the content very skinny. It would also be far too much padding for browsers that calculate padding correctly. A great deal of trial and error leads us to the following combination of values (illustrated in Figure 13.13).

div.caption {float: right; width: 30%; margin: 0 1% 0 0;
  padding: 0 0 0 40%;
  border-top: 1px solid #006;
  voice-family: "\"}\""; voice-family:inherit;
  width: 19%; padding-left: 10%;}
figure
Figure 13.13

Extending the caption's top border into the main column with some padding.

Whoops! The caption has suddenly dropped below the figure. This is because the padding has made the caption wide enough that its element box overlaps the box created by the floated figure's div. Floats are not allowed to overlap, so the second one (the caption) is placed below the first. We can avoid this simply by reducing the width of the figure's div. Technically, we could use 70% because the caption totals a width of 30%, but let's make sure they don't overlap by dropping the value lower.

div.figure {float: left; width: 67%; margin: 0; padding: 0;}

This brings the caption back up where it's supposed to be, but some of the following paragraph comes up along with it! That's because, before, the figure div was wide enough that there was no room for following content to flow next to it. Thanks to the demands of our caption styles, that's no longer true.

This development points out a related problem. Suppose a note comes just before a figure, and the bottom of the note is lower than the top of the figure. The figure's caption would float down below the end of the note, which would look a little odd. There isn't any way to say in CSS that two floated elements have to line up with each other, but we can add a little bit of HTML that will serve the same purpose.

<hr>
<div class="figure">
<img src="13CSS04.jpg" height="300" width="400">
</div>
<div class="caption">
<h5>Figure 13.4</h5>
<p>
The masthead is finished with nicely styled content.
</p>
</div>
<hr>
Tip
Hidden Elements

The difference between visibility: hidden and display: none is that the former simply makes elements invisible while allowing them to affect the layout of the document. The latter completely removes an element from the layout, preventing it from having any layout effects.

Just adding an hr element before every figure and after every caption is enough for our needs. We'll just set such elements to clear: both and prevent them from appearing (see Figure 13.14).

div.warn, div.warn code {color: maroon;}
hr {clear: both; visibility: hidden;}
div.figure {float: left; width: 67%; margin: 0; padding: 0;}
figure
Figure 13.14

Invisible hr elements keep the figures and captions lined up and standing alone.

Tip
Rounding Off Corners

For a detailed exploration of using background images to round off corners, see Project 10, "Sneaking Out of The Box."

Now all we need to do is style the caption's label (for example, "Figure 13.4"). A quick glance at the book tells us that the label needs to line up with the sidebar's separator line, look like a blue tab, and not stretch all the way to the end of the caption's top border. Creating the tab look requires inserting a small background graphic into the bottom-right corner of the h5 element and setting a background color. Let's also spread out the letters just a touch.

div.caption {float: right; width: 30%; margin: 0 1% 0 0;
  padding: 0 0 0 40%;
  border-top: 1px solid #006;
  voice-family: "\"}\""; voice-family:inherit;
  width: 19%; padding-left: 10%;}
div.caption h5 {letter-spacing: 1px; color: black;
  background: #9BD url(captioncurve.gif) bottom right no-repeat;}
div.caption p {font: italic 80% Arial, Verdana, Helvetica, sans-serif;
  color: #555;}

With a little padding and margins, we'll be there. To make the label text line up with the paragraph, we need to figure out the paragraph's margins. The rule that sets the margins for the caption's paragraph is as follows:

h1, h2, h3, h4, h5, p, pre, table, div {margin-right: 22%;
  margin-left: 8%;}
Tip
Circle Gets the Boot

As for the small circle placed on every caption label, we aren't going to reproduce that effect in this project. It would certainly be possible to do so, but as with the boxes around the preview images, the effort would be too great for so small an aspect of the design.

Although these work okay for the paragraphs, they won't do for the caption label. We need to set new margins for the h5 element, and to keep things consistent, we'll apply similar margins to the paragraphs. At the same time, we'll make the label into small-caps text because that's what appears in the book's design.

div.caption h5 {margin: 0 1em 0 0; padding: 0.33em 10px 0 1em;
  color: black; letter-spacing: 1px; font-variant: small-caps;
  background: #9BD url(captioncurve.gif) bottom right no-repeat;}
div.caption p {font: italic 80% Arial, Verdana, Helvetica, sans-serif;
  color: #555; margin: 0; padding: 0.25em 1em;}

As with the sidebar notes, we need to make sure that any code text within our captions is the same size as its surrounding text. We'll do this by adding a selector to the rule that already exists for the note text.

div.note code, div.caption code {font-size: 100%;}

The last thing we need to do is get the figure over toward the center of the text. Unfortunately, due to all the workarounds we had to use, it isn't possible to just center the image and have that work. Recall that the div enclosing the figure is now only 67% of the width of the body element. Instead, we'll right-align the figure, putting its right edge against the right edge of the div (see Figure 13.15).

div.figure {float: left; width: 67%; margin: 0; padding: 0;
  text-align: right;}
figure
Figure 13.15

The finishing touches for styling figures and captions.

It isn't perfect, but it will work fairly well in most browsers, and it ensures a small but noticeable separation between the figure and the caption's top border, just like in the book.

Code Listings and Tables

To wrap up our project, we'll look at two very different structures that end up having very similar styles: code listings and tables. Listing 13.1 provides an example of what we need to re-create.

Listing 13.1—A Sample Listing
div.web {color: #399;}
div.tip {color: #006;}
div.warn, div.warn code {color: maroon;}

Just in glancing at the printed version of the listing, the markup necessary to re-create it is almost obvious, except perhaps for the heading. Let's put it into an h5 element and wrap a span around the listing number itself. This leads to:

<h5><span>Listing 13.1</span>—An example listing</h5>

Now we can color the listing numbers and give the span a right margin to push the listing title away from the number.

h5 {font-size: 100%;}
h5 span {color: #006; margin-right: 0.5em;}
p {margin-top: 0.5em; margin-bottom: 1em; line-height: 1.2em;}

There is one fly in our ointment: The h5 element has a left margin of 22%, and it's contained inside a div that also has a 22% left margin. We need to change that to prevent the h5 from being massively indented, so we'll replace the left margin of the h5.

div.listing pre {border: 1px solid #006; border-width: 1px 0;
  padding: 0.5em 1em; margin: 0.125em 0 1.5em;}
div.listing h5 {margin-left: 0.5em;}
ul, ol {margin-right: 25%; margin-left: 13%; padding: 0;}

As for the listed code, having it in a pre element makes the most sense. In fact, we already have a div.listing pre rule that had to be added at the beginning of the project to avoid problems in IE5/Windows. We'll just rewrite it to add the top and bottom borders and to massage the margins and padding a bit (see Figure 13.16).

div.listing pre {border: 1px solid #006; border-width: 1px 0;
  padding: 0.5em 1em; margin: 0.125em 0 1.5em;}
figure
Figure 13.16

Styling the listings is a matter of a just a few simple rules.

Tables are very similar to listings in that they have top and bottom borders and a title just above the top border. There are a few differences, though, as Table 13.1 illustrates.

Table 13.1—A Sample Table
Column 1Column 2Column 3
Thisisan
exampletableK?

The title is the same as with a listing, and because we're dealing with a table, the markup will involve a table.

<h5><span>Table 13.1</span> An example table</h5>
<table cellspacing="0">
<tr>
<th>Column 1</th><th>Column 2</th><th>Column 3</th>
</tr>
<tr>
<td>This</td><td>is</td><td>an</td>
</tr>
<tr>
<td>example-</td><td>table</td><td>K?</td>
</tr>
</table>
Tip
Giving Width to Tables

In many browsers, tables by default are made only as wide as they need to be to display their contents. That's why we've explicitly given our tables a width: to override default browser behavior.

You might be tempted to add a class to the table, but there's no reason to do so. The only table elements in our design will be the ones that enclose tables like Table 13.1. So we'll give them top and bottom borders, reduce the font size slightly, tack on a bottom margin to keep other text away, and declare a width.

div.listing h5 {margin-left: 0.5em;}
table {border: 1px solid #006; border-width: 2px 0;
  font-size: 90%; margin-bottom: 1.5em; width: 70%;}
ul, ol {margin-right: 25%; margin-left: 13%; padding: 0;}

The column headings are all that remain to be styled. The rule we add will have to set the color and left alignment of the text as well as draw a border underneath it.

table {border: 1px solid #006; border-width: 2px 0;
  font-size: 90%; margin-bottom: 1.5em; width: 70%;}
th {color: #006; border-bottom: 1px solid #006; text-align: left;}
ul, ol {margin-right: 25%; margin-left: 13%; padding: 0;}

As a last touch, we'll give our table cells a little bit of padding so that their contents will be less likely to jam up next to each other. The results are shown in Figure 13.17.

th {color: #006; border-bottom: 1px solid #006; text-align: left;}
th, td {padding: 0.125em 0.66em;}
ul, ol {margin-right: 25%; margin-left: 13%; padding: 0;}
figure
Figure 13.17

Re-creating table layout is as simple as writing three new rules.

Postproject Analysis

Obviously, although we've gotten close to reproducing the look of the book with CSS, a few things were left out. The inability to download fonts is one of the basic design limitations of the Web, although in a way it's a blessing in disguise. Because designers can't count on a certain font being used, they're encouraged to think in terms of more flexible design principles.

The other big stumbling block in doing such a design is, as always, browser limitations. In this particular project, Internet Explorer for Windows was the big problem, but depending on the project you're attempting, any browser could end up playing that role. Fortunately, browsers are advanced enough that it's usually possible to create a minimal workaround that doesn't mess up other browsers.

We also left out five different design aspects:

All told, however, there was very little we had to leave out and a great deal we were able to re-create. The final style sheet we've created is provided in Listing 13.2.

Listing 13.2—The Complete Style Sheet
<style type="text/css">
body {margin: 0; padding: 0; color: black;
  background: white url(blue.gif) 80% 0 repeat-y;}
h1, h2, h3, h4, h5, p, pre, table, div {margin-right: 22%;
  margin-left: 8%;}
div.listing pre {border: 1px solid #006; border-width: 1px 0;
  padding: 0.5em 1em; margin: 0.125em 0 1.5em;}
div.listing h5 {margin-left: 0.5em;}
table {border: 1px solid #006; border-width: 2px 0;
  font-size: 90%; margin-bottom: 1.5em; width: 70%;}
th {color: #006; border-bottom: 1px solid #006; text-align: left;}
th, td {padding: 0.125em 0.66em;}
ul, ol {margin-right: 25%; margin-left: 13%; padding: 0;}
h1, h2, h3, h4 {font-variant: small-caps;}
h3, h4, h5 {margin-top: 1.25em; margin-bottom: 0;}
h1 {font-size: 300%; border-bottom: 2px solid white;
  margin: 0.5em 0 0.5em 0; padding: 0 0 0.125em 10%;}
h2 {font-size: 200%; margin: 0 0 0.66em 10%;}
h3 {font-size: 150%;}
h4 {font-size: 110%;}
h5 {font-size: 100%;}
h5 span {color: #006; margin-right: 0.5em;}
p {margin-top: 0.5em; margin-bottom: 1em; line-height: 1.2em;}
code, pre {font-family: "Courier New", Courier, monospace;}
code {color: #006;}
pre {margin-left: 10%; font-size: 80%;}
pre b {color: maroon; font-weight: normal;}
div#masthead {margin: 0 20% 2.5em 0; padding: 2em 0 1.5em 0;
  border: 1px solid #006; border-width: 0 1px 1px 0;
  background: #BDF;}
div#masthead blockquote {font-size: 90%; font-style: italic;
  margin: 2em 22% 0.5em 10%;}
div#attrib {font-size: 90%; font-style: italic;
  text-align: right; font-variant: small-caps;}
div#previews {float: right; width: 33%; margin: 0; text-align: center;}
div#previews img {width: 80%; margin-top: 1em;}
ul li {list-style: outside square url(diamond.gif);
  margin-bottom: 0.5em;}
div.note {float: right; clear: right; border-width: 0;
  width: 18%; margin: 0 1% 0 0; padding: 0;
  text-align: right; font: 80% Arial, Verdana, Helvetica, sans-serif;
  background: transparent url(blue.gif) 50% 15px repeat-x;
  voice-family: "\"}\""; voice-family:inherit;
  width: 19%;}
div.note h5, div.note p {text-align: left;
  margin-left: 1em; margin-right: 0;}
div.note img {height: 30px; width: 30px; margin: 0;}
div.note h5 {margin: -5px 30px 0 1em; padding: 0;
  font-variant: normal;}
div.web p {margin: -10px 30px 0 1em;}
div.note code, div.caption code {font-size: 100%;}
div.web {color: #399;}
div.tip {color: #006;}
div.warn, div.warn code {color: maroon;}
hr {clear: both; visibility: hidden;}
div.figure {float: left; width: 67%; margin: 0; padding: 0;
  text-align: right;}
div.caption {float: right; width: 30%; margin: 0 1% 0 0;
  padding: 0 0 0 40%;
  border-top: 1px solid #006;
  voice-family: "\"}\""; voice-family:inherit;
  width: 19%; padding-left: 10%;}
div.caption h5 {margin: 0 0.5em 0 0; padding: 0.33em 7px 0 0.5em;
  color: black; letter-spacing: 1px;
  background: #9BD url(captioncurve.gif) bottom right no-repeat;}
div.caption p {font: italic 80% Arial, Verdana, Helvetica, sans-serif;
  color: #555; margin: 0; padding: 0.25em 0.5em;}
</style>

Branching Out

There isn't as much room for change when you're trying to re-create a book's design, but here are a few suggestions for things to try anyway.

  1. branch Reduce the amount of vertical space the masthead consumes without making it look significantly different than in the printed version. Don't worry about making the borders line up with the preview images, since because they won't line up in most cases anyway.
  2. branch Write styles that will come close to recreating the look of the "Branching Out" section. Remember the compromises we made for the preview images next to the masthead, and take a similar approach with the layout of this section.
  3. branch Write styles to re-create blue "aside" boxes, which are divs with a class of aside. It will require two images to carry off the full effect, with both of them used in the heading of the aside. While you won't be able to put both in the background of the heading, try to find creative ways to manipulate the HTML so that both images can be placed using CSS and not involving an img element in the HTML.