Mimsy Were the Borogoves

Hacks: Articles about programming in Python, Perl, PHP, and whatever else I happen to feel like hacking at.

Cascading style sheets and HTML

Jerry Stratton, March 20, 2005

HTML uses “tags” that have some form of meaning. A headline tag says that this is a headline for what follows. A paragraph tag says that this text forms a unified thought. A table header tag says that this cell is a header for a row or column.

Cascading style sheets provide no meaning. They allow you to change how an HTML tag displays, but not what an HTML tag means. In general, when you create web pages using HTML and CSS, the HTML should describe your web page, and your CSS should describe its presentation. The page should remain readable in a wide variety of browsers and browser types without any of the CSS.

A simple web page

We are going to use a CSS-free review of Mistress of Mistresses as an example. As it stands, it is a perfectly readable page, but it does not draw the reader’s attention as it should. The headlines do not stand out from the body, and the recommendations lie lifeless on the left of the page along with everything else.

Download that page and save it as “html” or “source”. You want to keep all of the HTML intact.

If you look at the source code for that page, you’ll see that it references a file called “reviews.css”:

  • <link rel="StyleSheet" href="reviews.css" type="text/css" media="all" />

This is how you include a stylesheet in your web page. Often, you’ll have several web pages all including the same style sheet. This way, if we have hundreds of book reviews, we can change the appearance of all of our reviews by changing a single style sheet.

Margins and padding

For our first trick, we’ll add a nice margin on the left and right so that our text is not flush left and crowded. Use a text editor to create a style sheet called “reviews.css” in the same folder as your new web page. In that style sheet, add the following CSS:

[toggle code]

  • body {
    • width: 80%;
    • margin-left: 10%;
    • text-align: justify;
  • }

This makes the web page 80% of the browser’s width, and makes a left margin of 10% of the browser width. Then, it fully justifies all text on the page.

When we specify widths and heights of blocks in percentages, we are specifying a percentage of the containing item. In this case, the body is contained by the html tag, which is the browser itself. If we had a paragraph inside of a table, and we specified that the table was 50% width and the paragraph was 50% width, the paragraph will be 50% the width of the table, which will be 25% of the width of whatever contains the table.

Now, I think that looks quite a bit better already, but that left margin is kind of empty. Let’s add a border to our left margin:

[toggle code]

  • body {
    • width: 80%;
    • margin-left: 10%;
    • text-align: justify;
    • border-left-style: dashed;
    • border-left-color: orange;
    • border-left-width: .2em;
  • }

This adds a dashed orange border directly to the left of the text. The border is “.2em” in width, which is to say, 20% of the upper-case font size. The border will thus change in width proportionally to any changes in font size that the reader requires.

Our border is much too close to our text. It is the same problem that we had when our text was flush left to the side of the browser. We can move the border further away from the text that it belongs to using padding. Add one more line to your CSS:

[toggle code]

  • body {
    • width: 80%;
    • margin-left: 10%;
    • text-align: justify;
    • border-left-style: dashed;
    • border-left-color: orange;
    • border-left-width: .2em;
    • padding-left: 1em;
  • }

This adds a padding between the border and the text of one “em” width.

How do margins and padding work?

HTML tags have margins and padding. If you were to draw a border around a tag’s contents, the margins are outside of the border and the padding is inside of the border. When, in fact, you add borders to an HTML tag, the borders go between the padding and the margin.

So, when we added a border on the left of the body of our web page, the border is indented by 10% because that’s the margin we gave the body. When we add padding to the body, that pushes the text further in without moving the border.

You can more clearly see the margins vs. the padding by adding a background color to the tag that contains the body tag, and specifically setting the body’s background to white:

[toggle code]

  • body {
    • width: 80%;
    • margin-left: 10%;
    • text-align: justify;
    • border-left-style: dashed;
    • border-left-color: orange;
    • border-left-width: .2em;
    • padding-left: 1em;
    • background-color: white;
  • }
  • html {
    • background-color: tan;
  • }

Once you see the tan margins around the body of your document, go ahead and remove the “html” section of your CSS file.

CSS syntax

Style sheet syntax is fairly simple: the name of the HTML tag you wish to modify, a space, an opening curly bracket, and then a list of modifiers and a closing curly bracket.

The modifiers themselves are a name, a colon, and then a value, followed by a semicolon.

[toggle code]

  • tagname {
    • modifiername: value;
  • }

You can have as many tagnames and modifiernames as you want. If two modifiers conflict with each other, the last modifier takes precedence. For example, if you set all margins to 10%, and then set margin-left to 20% later, the left margin will be 20% and the rest of the margins will be 10%. But if you do it in the reverse order: first specify the margin-left and then specify all margins, then all margins will be 10%.

The last modifier you specify is the one that takes effect.

Let’s say that you want all of your headlines to have an indented border on the top and bottom. You can specify multiple tagnames in for your style sheet definition by separating them with commas.

Add the following definition below the body definition that we already have:

[toggle code]

  • h1, h2 {
    • border-top-style: inset;
    • border-bottom-style: inset;
    • border-width: .15em;
    • border-color: orange;
    • color: brown;
  • }

This changes the appearance of all of our h1 and our h2 tags. They get a border on the top and bottom, and their color changes to brown.

Measurements

The most common measurements used with style sheets are the percentage and the em-width, which we’ve already seen, and the pixel (px) and point (pt) which we haven’t. You should be very careful using static measurements such as pixels, points, and picas. They do not adjust themselves to the browser.

%a percentage of the element or an enclosing element, depending on context.
emthe height of the current font (upper-case characters)
exthe height of the current font (lower-case characters)
mmmillimeters
cmcentimeters
ininches
pcpicas: a pica is one sixth of an inch
ptpoints: a point is 1/72nd of an inch
pxpixels

When you use “0”, you don’t need to specify a measurement: zero is the same no matter what the measurement is.

Classes

Often you will want to differentiate between two different classes of the same tag. You might, for example, want to have the paragraph that displays the author of this review display differently than the rest of the paragraphs.

Use your text editor to change your HTML file from:

  • <p>review by Jerry Stratton, Wednesday, February 23, 2005</p>

to:

  • <p class="byline">review by Jerry Stratton, Wednesday, February 23, 2005</p>

We’ve added the class “byline” so that we can differentiate between byline paragraphs and other paragraphs.

Inside your style sheet file, add:

[toggle code]

  • p.byline {
    • text-align: right;
    • font-family: cursive;
  • }

Here, we’ve specified that for paragraphs of the class “byline”, align them to the right and give them a cursive font. You could also specify simply “.byline” instead of “p.byline” and then the definition would apply to any tag of the class byline.

You can have as many classes as you want in the class="class1 class2 classetc." modifier. Each class name is separated by a space. The order of the classes in the tag modifier does not matter. Only the order of the class definitions in the style sheet file matters. For example, class="byline jerry" is exactly the same as writing class="jerry byline". Any conflicts will be resolved by the order of the definitions in the css files, not by the order of the class names in the class="" modifier.

Font families

One of the advantages of good HTML is that when a browser does not understand a tag or a modifier, it can safely degrade to what it does know. CSS often does not have that advantage, but in some cases it is necessary. Fonts, for example, are often unavailable on the computer of the person reading your web page.

So, CSS allows you to specify multiple fonts, and to specify generic font types. The first font that matches an available font is used by the browser.

You have five generic font families: serif, sans-serif, cursive, monospace, and fantasy. You can specify multiple font names, and should usually specify a generic family as the last choice. You don’t know what fonts the browser on the other hand has available. The generic font family tells the browser what kind of font to use if the specific fonts are unavailable.

In the above example, we specified the generic font family cursive, and let the browser choose which cursive font to use.

Add the following to your h1, h2 style definition:

  • font-family: VTypewriter RoyalDeLuxe, American Typewriter, Courier, sans-serif;
  • font-weight: normal;

If the browser has VTypewriter RoyalDeluxe, that’s what it will use to display level 1 and 2 headlines. Otherwise, it will look for American Typewriter, and if that isn’t available it will look for Courier. Finally, if none of those are available, it will use its standard sans-serif font.

We also set the font-weight to normal. By default, most browsers will set headlines to bold, but if they don’t have the font they need in a bold version, they’ll skip to the next font in the list.

Contained by

You have a number of ways of focussing in on specific tags. One of the most common is to try to affect only tags that are contained in other tags. For example, you might have a specific table class, and want to affect the header cells in that table.

Change the table tag from

  • <table>

to

  • <table class="bookinfo">

Add the following to your style sheet:

[toggle code]

  • table.bookinfo th {
    • text-align: right;
    • border-right-style: solid;
    • border-right-width: .15em;
    • border-right-color: orange;
  • }

This definition will only affect “th” tags that appear inside of tables with the class “bookinfo”. This is specified by placing the “th” in the definition after the “table.bookinfo”, separated by a space.

Earlier, we separated different tags by a comma to apply the same definition separately to each of those tags. Hear, we are separating tags by spaces to apply the definition only to the final tag, and only if it is contained by the previous tag(s). You can have as many tags as you want in the chain. For example:

[toggle code]

  • td blockquote em {
    • font-style: normal;
    • font-weight: bold;
  • }

This will remove the italics from emphasized text and make that emphasized text bold, but only if the emphasized text occurs within a blockquote, and only if the blockquote occurs within a table’s data cell.

The basics

These are the basics of what style sheets can do for your web pages. There’s a lot more available, such as affecting adjacent tags, positioning blocks of text on the page, and allowing text to wrap around blocks or images. Look for all of that and more in part 2 of this tutorial.

I’ll be teaching a half-day tutorial on cascading style sheets in April. This will be the lesson plan for that class. I will probably also turn it into an open source document in PDF, HTML, and RTF formats. If I do that I’ll place it on the Neon Alley tutorials page.

  1. <- Hacks Category
  2. Style Sheets 2 ->