A Quick Tour of CSS2

Web Review
February 1998

With the latest release of the CSS2 draft specification on 28 January, CSS has taken a giant step forward in capability... and complexity. Web Review's CSS guru, Eric Meyer, has been busily combing the new spec for its newest treasures, and reports back to us on just what's different and what's new.

You're no doubt aware that Cascading Style Sheets (CSS) are a developing Web technology that promises a great deal in the way of Web page presentation. Browser authors are still working to implement Cascading Style Sheets, level 1 (CSS1), and they seem to get closer with each new version.

Meanwhile, never content to rest on its accomplishments, the CSS Working Group of the World Wide Web Consortium (W3C) is working on the next level of style sheets. Logically enough, the emerging standard is called Cascading Style Sheets, level 2 (CSS2). Illogically enough, both Navigator and Internet Explorer attempt to support some of the things which are new in CSS2, even though they haven't finished implementing CSS1 yet.

So what is new in CSS2? I'm so glad you asked. Let's take a quick tour, shall we? Just remember that this itinerary is subject to change-- by the time the CSS2 specification is completed, some of these properties could be changed, or even dropped altogether. Also, there may be properties which are added, so be on the lookout for anything new! (Speaking of which, I've assembled a list of new stuff in CSS2 which accompanies this article.)

Additions to CSS1

Only a few CSS1 properties have gained new values. One is display. Now, in addition to block, inline, line-item, and none, we have run-in and compact, as well as a number of values specific to tables (which we'll get to in a bit).

compact has an effect similar to <DL compact> (assuming your browser supports that bit of HTML). Basically, if an element is set to {display: compact;}, then it will appear in the margin of the next element, assuming there is enough room for it. Otherwise, the elements will be treated as block-level elements. Think of a 'compacted' element as one which is floated, but only if there is room for it to be displayed without altering the formatting of the following element.

run-in, on the other hand, has the effect of turning an element into an inline element at the beginning of the following element. Confused yet? This should make it simple:

<H4 style="display: run-in;">A Heading.</H4>
<P>This is a paragraph of text....</P>

The result will look something like this:

A Heading. This is a paragraph of text which has a run-in heading at its beginning. It doesn't look like an H4, does it?

However, this should only work if the next element is block-level, and is not floating or positioned absolutely (more on that next). So, for example, if you try to set a list item to run-in, and the next element is another list item, the items shouldn't run together.

font also picked up a few new values: caption, icon, menu, messagebox, smallcaption, and statusbar. The effects these values will have is to apply a font family, size, weight, etc., which matches the computer's settings for such things in its own environment. For example, icons on a Macintosh are typically labelled using 9-point Geneva. Assuming that hasn't been changed by the user, then any font declaration with a value of icon will result in 9-point Geneva for that text.

Perhaps the biggest area of expansion over CSS1 is in selectors. The draft specification shows a plethora of new selectors, including the ability to include tag attributes in the selectors. For example, H1[href] would match any H1 with an href attribute, regardless of its value. CSS2 provides ways to define parent-child relationships, so that styles are applied to elements which are children of another element. You can also apply styles to elements in only those cases where they follow another element-- for example, you could set red text for only those paragraphs which follow an H1, without the use of class names.

Speaking of class names, some additions have happened there as well. It is possible to set multiple class names on a given element, such as <P class="footnote example reference">. In CSS1, you could only refer to one of these values, such as P.example. Well, in CSS2 you could modify this selector so that the class name must be an exact match, or set it up so that only one of the values has to match. Given the above three-class paragraph, P[class="example"] wouldn't match it, because the values are different (example isn't the same as footnote example reference). On the other hand, P[class~="example"] would match, because this declaration has to only match one of the values in the class attribute. The only difference is the tilde character ( ~ ), but what a difference!

Miscellaneous Stuff

Instead of putting them off to the end, I'll handle the odd properties out right now. First, there is text-shadow, which has the effect you'd probably expect from its name: you can define a drop-shadow of a given color for text. You can even set an offset and a blur radius, which means you can get cool fuzzy shadows, or even glow effects, using this property. (I fully expect to see this property heinously abused the instant it's supported by any browser.)

In other news, :hover is intended to affect display of an element while the mouse is over it. For example, you could set anchors to have no underlining, except while the mouse is over the anchor, by declaring A:hover {text-decoration: underline;}. There is also a smattering of other new pseudo-classes, but we'll get to those later in the article in the sections on paged media and generated content.

The font section gains a new property: font-size-adjust is intended to help browsers make sure that text will be the intended size, regardless of whether or not the browser can use the font specified in the style sheet. It is often a problem that authors will call for a font that the user doesn't have available, and when another font is substituted, it's either too big or too small to read comfortably. This new property addresses that very problem, and should be very useful for authors who want to make sure that their documents are readable no matter what font gets substituted.

Finally, there is one very important new feature of CSS2: the value inherit. If you were to ask the question, "Okay, to which properties did inherit get applied?" the answer would be, "Every last one of them." Before you ask the next question, inherit is used to explicitly declare that a given computed value should be inherited from its parent. In other words, if the font-size for BODY is computed to be 14 points, then the declaration P {font-size: inherit;} would set all paragraph text to 14 points in size.

Positioning On all Three Axes

The idea behind positioning is fairly simple. It allows the author to define exactly where element boxes will appear, relative to where they would ordinarily be-- or relative to the browser window itself. The power of this is both obvious and surprising. What shouldn't be too surprising is that this is the part of CSS2 which both major browsers are currently trying to support.

Unfortunately, positioning support is sketchy enough that it's almost impossible to provide working examples. But the effects are easy enough to describe. Let's say you have a page laid out in a three-cell table something like this:

Cell 1 Cell 2
Cell 3

Once you break it down, of course, you have three chunks of information-- the contents of each cell. So let's get rid of the table markup, and wrap each chuck of information in DIV tags. Now we simply add some positioning rules, and discover that the page looks just as it did to begin with, except without any table markup whatsoever!

We can take this further. Using positioning markup, it is possible to recreate frame-type layouts without any sort of frames markup whatsoever. With just a few declarations, all of the content in a single document can be arranged in a way that only frames could do before-- and all of the information is in a single page. No more messing around with <NOFRAMES> tags and duplication of content across multiple documents. Positioning can take care of all of this!

In my opinion, this is the single most important new area of the CSS2 specification. It can make the job of Web authors much easier, allow for document display in any browser at all, and make it much easier for search engines to index documents. It is to be hoped that both Microsoft and Netscape put implementation of this section of the CSS2 specification very high on their respective "to-do" lists (right below creating a full, stable implementation of CSS1).

In a sort of accompaniment to the positioning properties which let you set an element's horizontal positioning, z-index lets you determine an element's "vertical" position. Since (thanks to positioning properties) elements can overlap each other, it makes sense that you should be able to define which are "in front" or "on top" of others. That's what z-index will do.

A Whole New Generation

Generated content is a new way of adding things to your content without having to alter the content itself. It's done by using the pseudo-elements :before and :after, and the property content. Here's a basic example-- given the following markup fragments:

P:before, P:after {content: "\""; color: red;}

<P>This is a quote.</P>
...then the browser will display the following:

"This is a quote."

How about that? Note that the double-quote mark was escaped out-- that is, preceded by a back-slash. This is necessary, since text values for content must be enclosed in double-quote marks. You could also place images before (or after) content, using something like P:before {content: url(para.gif);} to put a paragraph symbol at the beginning of each paragraph. You can even string multiple values together, like this:

P:before {content: url(para.gif) " -- ";}

This would cause each paragraph to be started with a paragraph symbol, a blank space, two dashes, and then another blank space. Note that all of this is considered part of the paragraph, and is inlined within it. You cannot, however, apply styles to the generated content; the content will simply inherit the styles of its parent element (a paragraph, in the above example).

Widths, Heights, and Sizeable Fun

Yes, CSS1 has width and height. In CSS2, though, positioning makes it necessary to be able to define certain ranges of sizes, not just a specific percentage, or pixel width, or whatever. Thus we have min-width and max-width, and min-height and max-height. These properties let you define the upper and lower limits of the size of a given element. Of course, you can also set height and width, but browser can override these settings if they feel it necessary. Just in case you have some hard limits, these properties will let you set them.

Given this, however, what happens if your maximum height and width don't leave enough space for the element's content? In that case, you'll want to turn to the overflow property. With this property, you can define whether the browser should override the element's size to display the content, the content should be 'clipped' (cut off) at the boundaries of the element, or the browser should put in a scrollbar so that you can get to all of the content, even if it isn't immediately visible. If you choose to clip the content, then you'll probably also want to invoke the clip property, which is sort of like padding, except in this case it defines the area of the element in which content is visible-- and, by implication, those areas in which content is not visible.

Speaking of things being visible, there is also a new property called visibility. Basically, you can set something to be either visible or hidden. If the element is hidden, it will still occupy just as much space on the page as though it were visible. This is different from display: none;, which causes the browser to act like the element doesn't even exist.

Environmental Issues

CSS2 offers the ability to both alter the browser's environment and to integrate its look more closely to that of the user's operating system. To achieve the former, we have the cursor property, which lets you declare what shape the browser's cursor will take as it passes over a given element. Want to make a humorous point about download times? Change the cursor to the wait-cursor (an hourglass or watch) when the cursor passes over hyperlinks. You can even hook this property up to "cursor files" (which are not defined by the specification), so you could class your anchors based on where they go and load different icons for each type of link. For example, off-site links could cause the cursor to change into a globe, while links intended to provide help could trigger a question-mark cursor.

In order to let Web pages more closely match the user's desktop environment, there are a whole list of new color keywords like buttonhighlight, threedshadow, and graytext. These are all intended to use the colors of the user's operating system. In all, there are 27 of these new color keywords, so I won't list them all out here. If you really want to know what they are, see the sidebar which accompanies this article.

Even More Borders

In CSS1, there are quite a few properties devoted to setting borders around element boxes, such as border-top-width and border-color, not to mention border itself. CSS2 adds a few more border properties, pretty much all of which are aimed at giving the author even more specific control of the borders. Before, it was difficult to set a specific color or style for a given side of the border, except through properties like border-left, and that required more than one value. The new CSS2 properties address this, and are pretty self-explanatory.

Why? That's a good question, but it's one that could be asked of some of the CSS1 properties. Rumor has it that these incredibly specific properties were included at the behest of Netscape engineers who claimed that their inclusion was absolutely crucial to Netscape's rendering engine. Then again, since very few of these CSS1 border properties were supported by Navigator until just recently, no doubt it's just a rumor.

Tables and Columns

Perhaps in response to the abysmal handling of tables and style sheets which both major browsers evince, CSS2 includes a handful of properties which apply directly to tables and table cells. First, there are ten values for display: table, inline-table, table-column-group, table-column, table-row-group, table-row, table-cell, table-caption, table-header-group, and table-footer-group. While most of these have obvious effects from their very names, at least two may not be familair to you. table-header-group and table-footer-group are used to mark the headers and footer of tables. These are displayed, respectively, above or below all the rows of the table, but not outside of the table's caption.

Familiar to HTML veterans, row-span and col-span are basically the same as the HTML attributes for table cells. In CSS, however, these properties can be applied to a cell, a column, or a column-group.

Among the new properties are found cell-spacing, which influences the placement of borders around cells; border-collapse, which can be used to influence how cell borders interact; and table-layout, which tells the browser whether or not it can resize the table as necessary. There are also rules describing how visibility and vertical-align are applied to tables. There is also a caption-side property which functions exactly the same as the ALIGN attribute on the CAPTION tag, and the property speak-header-cell, which controls how header cells are handled by speech-generating browsers (more on that later).

In general, the section on tables is very much in flux. A good third of the chapter is marked "UNDER CONSTRUCTION," so expect even more changes in this area before the specification is finalized.

Media Types and At-rules

Don't get too excited yet. We aren't talking about media types in the sense of things like audio and video authoring. Well, not exactly, anyway. Instead, what you can do is create rules for presentation in various kinds of media. The defined types of media are thus far screen, as in a computer screen; print, for things like printouts and "print-preview" displays; projection, for projected presentations such as slide shows; braille and embossed for tactile feedback devices and printers; aural for speech generators; tv for television-type displays (think WebTV); tty for fixed-width character displays; handheld, for palmtop computers; and the ubiquitous all. These are all values of @media, which is one of several at-rules.

Others are @font-face, which is used in the definition of a font; @import, which has more power than CSS1 gave it; and @page, which allows you to define the size of a page in paged-media style sheets.

Paged Media

Since I just brought up paged media, I should probably mention that there are some new properties which apply to such media. Four of them apply to page breaks and where they appear: page-break-before, page-break-after, orphans, and widows. The first two are used to control whether or not a page-break should appear before or after a given element, and the latter two are common desktop-publishing terms for the minimum number of lines which can appear at the end or beginning of a page. They mean the same thing in CSS2 as they do in desktop publishing.

There is also size, which is simply used to define whether a page should be printed in landscape or portrait mode, and the length of each axis. If you plan to print your page to a professional printing system, you might want to use marks, which can apply either cross- or crop-marks to your page.

The Spoken Word

To round things out, we'll cover some of the properties in the area of aural style sheets. These are properties which help define how a speaking browser will actually speak the page. This may not be important to many people, but for the visually impaired, these properties are a necessity.

First off, there is voice-family, which is much the same as font-family in its structure: the author can define both a specific voice and a generic voice family. There are several properties controlling the speed at which the page is read (speech-rate), as well as properties for the pitch, pitch-range, stress, richness, and volume of a given voice. There are also properties which let you control how acronyms, punctuation, dates, numerals, and time are spoken. There are ways to specify audio cues which can be played before, during, or after and given element (such as a hyperlink), ways to insert pauses before or after elements, and even the ability to control the apparent position in space from which a sound comes via the properties azimuth and elevation. With these last two properties, you could define a style sheet where the text is read by a voice "in front of" the user, whereas background music comes from "behind" and audio cues come from "above" the user!

Whew!

Well, that pretty much wraps up our Quick Tour of CSS2. There is a lot of new power, and this extremely broad overview doesn't do justice to the depth of the new specification. For example, assuming a decent browser implementation, it should be simple to set up a page which looks like it's frame-based using the positioning properties-- and yet have it print out very professionally, including page numbers, multiple columns, and margins that leave room for three-hole punching, all by using the paged-media rules. You don't even have to worry about whether or not the user prints out the correct frame, because the print-media style sheet is used when printing, and besides, there are no frames. They just hit "Print..." and it prints! Furthermore, that very same page can use other style sheets to deliver the content to the blind, either through braille or the spoken word, and even be used for a presentation to a packed conference session.

Hopefully, this has given you a good taste of what's coming in the world of style sheets. So long as the browser vendors keep improving their style sheet implementations, Web authors everywhere will be able to vastly enrich their pages and make them available to a wider audience.