CSS

CSS is a completely different language from HTML, with the code put in a different file and joined to the page via a special HTML tag. We need a new language because we want to keep them separate, and they have different purposes. HTML is about the structure and content of the page, which is often the only thing the client (such as a screen reader or web scraper) is interested in. CSS is about style and appearance, and we can have different style rules for different media, such as mobile phones versus desktop screens, or print versus screen.

Ottergram Example

Let's start with an example. The following two pages are both Ottergram, and the HTML is (pretty much) the same. Yet the appearance of the two pages is very different, because the second one has applied some CSS style rules:

I suggest opening each in a separate window, placing them side by side and scrolling up and down a bit. Also:

  • View Source, to see the changes to the HTML
  • Inspect an element and see the CSS rule(s) that are applied

There's a video introduction on our videos page.

Principles

With software applications like MS Word, Google Docs, and the like, we're used to formatting something by selecting it (often by clicking/dragging with the mouse), and then choosing fonts (Verdana), colors (red), sizes (16px), styles (italics) and so forth. The result is easy and intuitive and was a revolution in amateur typesetting ... long before you were born. The style is called WYSIWYG, pronounced "wizzy-wig".

One trouble with that technique is consistency: Two days later, you're editing the same document, (or a related one), and you want to style some element the same way. Do you remember all the choices you made? What if you rely on your memory and it's faulty: now your document is inconsistent.

Another trouble is maintenance. If the boss decides that the font should be different and the color isn't quite right and so forth, can you remember all the places you applied that style? If you don't update all of them, your site will be inconsistent. And think of how tedious it would be to find and update dozens or hundreds of occurrences of some kind of element.

Instead, CSS is based on separating selection from styling:

  • we select some set of elements (for example, all H2 headers), and
  • apply a set of style property values to them (for example, font size and color)

Here's a specific example. In this document, all the H2 headers are styled similar to this:

h2 {
    color: deepskyblue;
    border-top: 1px solid steelblue;
    font-size: 4.2rem;
    margin-top: 0;
    margin-bottom: 2rem;
    font-weight: lighter;
}

Don't worry about the details here; we'll get to them later. Also, we'll learn more about colors next time; for now, I've substituted names of colors that look similar.

Before we look deeper at rules, let's look at how to attach the set of rules to the file. In the head of the HTML file, we can insert one or more link tags:

    <link rel="stylesheet" href="stylesheets/styles.css">

There are two attributes: rel (which defaults to stylesheet, so we could really omit it) and href which is the URL of the file of CSS code. (In the example above, we use a relative URL. The stylesheets folder is in the same folder as the HTML file, and the styles.css file is inside the stylesheets folder.)

In the CSS file, we put the CSS rules, like the one we saw in the last section.

CSS rules

Let's take a look at the syntax of a CSS rule:

selector {
    property1: value1;
    property2: value2;
    property3: value3;
}

In the example, the selector was h2: that is, it selects all the h2 elements on the page. So, whether you use zero, one or a hundred h2 elements, the effort of coding and updating the rule is exactly the same. This is a tremendous advantage over the WYSIWYG approach.

Before we turn to different kinds of selectors, let's look at how to connect the CSS code with the HTML file.

Selectors

There are quite a few kinds of selectors available in CSS. Some are used often; some only rarely. We'll start with just three of the simplest ones, and we'll learn more selectors next time and later in the course.

  • tag: style every such tag (e.g. paragraphs <p> or list items <li>) You have to specify one of the existing HTML tags, like h2 or p.
  • classes: style every element with that class. Make up a class name, say fred and use .fred as the selector. Specify the class with an attribute, like <p class="fred">
  • id: style the (unique) element with that ID. Make up an ID, say george and use #george as the selector. Specify the id with an attribute like <p id="george">

Some web developers advocate avoiding the ID selector, including the authors of the FEWD book that I used. Their reasoning is that such rules can't be reused (applied to other elements), because an ID must be unique. That reasoning is correct, but if some element is definitionally unique (e.g. the table of contents or the copyright notice), I don't see a problem with giving it a unique ID, and styling it using that ID.

Furthermore, IDs are the only way to specify a location within a page using a URL.

Let's see how to use the class and ID selectors.

Class Selectors

Suppose that you have two categories of H2 headers, say "required" and "optional". How can you style the required H2 headers in Blueviolet and the optional H2 headers in CornflowerBlue?

There are two things that we need to do:

  1. We need to label some of the H2 elements to be required and others to be optional.
  2. We need to specify the style rules for each kind of H2 element.

We do these using classes, which we mean in the sense of category or kind.

To label an element, we specify its class:

<h2 class="required">Essential Material</h2>

<h2 class="optional">For the Curious Reader</h2>

Note that as web developers, we invent the names for classes. There's no list anywhere of the possible class names. We could call them "fred" and "george" if we wanted. (But we shouldn't because those are terrible names -- choose meaningful names like "required" and "optional").

Then, in the CSS file, we specify the rules for each class like this:

.required {
    color: blueviolet;
}

.optional {
    color: cornflowerblue;
}

If the selector is a tag, we just give the name of the tag, but if the selector is a class, we use a dot before the class name.

Rules Accumulate

If more than one CSS rule applies to an element, all of them are applied. So, if we have an element like this:

<h2 class="required">Essential Material</h2>

and our CSS has:

h2 {
    font-size: 16px;
}

.required {
    color: blueviolet;
}

The "Essential Material" header font is both 16px in size and blueviolet in color.

Note that if the rules conflict (say, they both specify the color, but with different values), there is a complex system to determine which rule wins, but the outcome is very intuitive:

  • the more specific rule applies (e.g. class is more specific than tag)
  • the later rule applies (rules later in the CSS file can override earlier rules)

In practice, the rules almost always work as you expect.

Also, an element can have more than one class, if desired:

<h2 class="required important">Essential Material</h2>
.required {
    color: blueviolet;
}

.important {
    font-weight: bold;
}

CSS Properties

There are many, many CSS properties; we won't learn all of them. Here are a few to get you started.

  • background background colors
  • border an optional box around the element
  • color font colors
  • display how an element is laid out on the page: block stacks vertically, inline is like text. There are other values, like none to act as if the element doesn't exist
  • font-family sets the font for the element
  • font-size sets the size of the font
  • list-style can change or remove the bullets in a bullet list.
  • margin spacing outside the element's border
  • padding spacing between the box and the contents
  • text-align can center text, right-align it and such
  • text-decoration can add or remove underlines and such
  • text-transform can capitalize, lowercase or uppercase text
  • width is the width of the contents of the element, not including any padding, borders or margins. This can be very confusing.

Several of the above are shorthand properties. You can be more specific, like border-left-style

Another example of "shorthand" properties is border which allows you to specify the width, style and color of the border. The following are equivalent:

selector {
    border: 2px solid red;
}

selector {
    border-width: 2px;
    border-style: solid;
    border-color: red;
}

I always use the shorthand. Either way, make sure you specify all three values.

Block Versus Inline Elements

We haven't been explicit about it before, but HTML tags fall into two broad categories:

  • block elements, like p, li, and div
  • inline elements, like a, em, and span

The difference is that block elements are big rectangular things that (by default) stack vertically on the page, while inline elements are stretches of text usually within a paragraph. This paragraph is a block element, but this sentence is an inline element, because it isn't necessarily a rectangle.

The generic block element is div and the generic inline element is span.

Box Model

Quite a few of the properties are based on the "box" model. That is, a block element like li or p can be thought of as a box. The box model is most easily learned by playing with the dev tools. Here's a screenshot of the developer tools which shows the box model for a particular li on the page:

box model of an LI element

The idea is fairly simple:

  • block elements work like big boxes that are (by default) stacked vertically on the page
  • they have the following properties (from outside to inside):
    • margins. These just have widths. The width is the distance between the content of the surrounding block and the border of the current block. The margins have the background color of the parent block
    • borders. These are lines around the content. They can have widths, styles, and colors
    • padding. These just have widths. The width is the distance between the border and the content of the box. They take on the background color of this block
    • content. This has width and many other properties

Here's a pair of nested div elements (generic block elements) with borders and background colors that should help clarify these distances:

content

Here's the HTML:

<div class="outer"><div class="inner">content</div></div>

and the CSS:

.outer {
    background-color: antiquewhite;
    border: 2px solid black;
    padding: 20px; /* all four sides */
}

.inner {
    background-color: lavender;
    margin: 10px 50px 20px 50px; /* top right bottom left */
    border: 2px dashed black;
    padding: 20px; /* all four sides */
}

Note that the margins of the inner box determine the distance between the dashed border of the inner box and the solid border of the outer box, and, therefore, determine how big the antiquewhite area is. If we added margins to the outer box, they would be irrelevant, because they are outside the solid border (and part of the white background of this page).

If you'd like to see that example in a separate simple page, so you can use the developer tools, here's the outer inner example

You can use display:block as a CSS property-value pair to turn an inline element (like A, IMG or SPAN) into a block element (like P or LI).

Borders

Specifying borders is a little tricky, because there are actually three properties you need to specify:

  • width
  • style (e.g. solid, dashed, dotted, double, groove)
  • color

For example:

nav { 
    border-width: 2px;
    border-style: solid;
    border-color: blue;
}

Or, with the shorthand syntax, specify all three in one go:

nav {
    border: 2px solid blue;
}

Unfortunately, the default style is none, so if you forget to specify the style, you get no border. (For example, a 2px missing blue border.) This catches a lot of people.

IDs

This section is really about URLs. We learned that URLs uniquely specify a single webpage in the world. URLs are even more powerful than that. They can even specify a location within a page. This is done by doing two steps:

First: Label the location with an ID. That's done in HTML with the id attribute, almost exactly like the class attribute. Any element in HTML can be given an ID, like shown this:

<span id="george">this span is george</span>

This span is george

Second: The absolute URL to specify that location is like http://domain.com/path/to/page.html#id-of-element The # is a special character (called a hash mark, sharp sign, pound sign, ...) separating the URL for the page from the ID of the element (called a fragment).

With relative URLs, you can omit parts of the URL and let them default. So a within-page link to a fragment would just be #id-of-fragment.

Try these two examples, and look at the location box in your browser:

Every section of these notes has an ID, so you can send someone a hyperlink to the exact section where you read something.

ID in CSS

You can also use an ID as a CSS selector, and we again use the # syntax. So, to style the "george" span above, we could put the following rule in our CSS file:

#george {
    font-size: 20px;
}

So, now we have three kinds of selectors in CSS:

  • TAG
  • .class
  • #id

That list is, unsurprisingly, in order from least specific to most specific.

ID versus Class

If you're confused about the difference between ID and class, you're not alone. Many students have been confused about this.

Here's the key difference: an ID has to be unique, meaning there can be only one element with a particular ID. If we anthropomorphize the elements on our page, an ID is like a Banner ID: there should be only one person with a given ID (barring identity theft). For example, there's only one element whose ID is "george".

If we use an ID to identify a place on a page for a URL, we want to specify a single place to go, not multiple places. This reminds me of a short (1:20) clip from Monty Python's Life of Brian: you are all individuals

Classes and IDs are similar in the following ways:

  • we make up a label
  • we apply the label to some number of elements
  • we refer to the label from the CSS rules

The difference, of course, is that an ID is a label that can be applied to at most one element, while a class is a label that can be applied to any number of elements.

You never have to use an ID selector in CSS; it's just an option. If you prefer to avoid it, just use a class selector and only apply it to one element.

In a URL, you must use an ID to identify the fragment; nothing else will do.

Units

When we give the width of an element or border or whatever, we can choose from a number of different units. Here are some examples of a few common ones:

  • px a distance in pixels, which depends on the device resolution. Common for widths of borders and other lines.
  • pt a distance in printer's "points" (72 points per inch), usually used with fonts. Best for printed output; rarely used on-screen.
  • % a distance in percentage of the width of the current element or the current font size. Really useful for the widths of big blocks, like ul or nav.
  • em a distance that is relative to the size of the current font, so 2em is twice the size of the current font. Learn more about EM. Really useful for things that you want to scale with respect to the font, such as margins and padding.
  • rem a distance that is relative to the font size of the root element (the body) tag. "rem" is almost the same as "em" but "em" can change in different contexts while "rem" is the same throughout the document. Similar to em in usefulness, but less context-dependent.

Learn more about CSS units

Example:

nav {
    width: 50%;
    border: 2px solid blue;
    padding: 3em;
    }

For a nav element where we want it to be half the width of its container (probably the page as a whole, but if it's inside some other element, then that element). We want a thin blue line around it. We want the padding to be roughly the width of 3 capital letter Ms, so if the font is 15px, the padding is 45px.

Interactive Demonstration

I created an interactive selector display that will help show you what elements various selectors pick out. To use it, click on the selectors below the example content and the selected elements are highlighted with red boxes. Below is an excerpt of the content; it's not the whole page, just the part with the beige background. The HTML looks something like:

    <h2>this is an h2 header</h2>
    <p id="par1">This paragraph has ID <code>par1</code></p>
    <h2>this is another h2 header</h2>
    <p>this paragraph precedes the list of fruits and veggies</p>
    <ol id="list1">
      <li class="fruit">apple</li>
      <li class="veg">broccoli</li>
      <li class="fruit" data-tag="tough">coconut. this is tough</li>
      <li class="fruit">date</li>
      <li class="veg">endive</li>
      <li class="veg" data-tag="yucky">fennel. this is yucky</li>
      <li class="fruit">"g" fruits
        <ul>
          <li>gooseberry</li>
          <li>grape</li>
          <li>grapefruit</li>
          <li>guava</li>
        </ul>
      </li>
      <li class="veg">horseradish</li>
      <li>tomato</li>
    </ol>
    <p>this paragraph follows the list of fruits and veggies</p>

Take a brief look at the tags, classes, ids, and the overall structure. Then click through and try the various selectors, some of which we will get to next time.

Normalize

In turns out that browsers can have different default styles for different tags, so even without a single line of CSS, a plain HTML file can look slightly different from one browser to another.

To have a consistent basis for styling our pages, it's nice to remove those differences. There's a CSS file called normalize.css that specifies the same style for all those tags, and so it's useful to load that CSS file first, and then our own code.

We could copy the normalize.css file to our own folder and load it from there, but we can also load it from the web. (From something called a CDN or Content Delivery Network.) Like this:

    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/3.0.3/normalize.min.css">

Thus, the head of our index.html file is now:

  <head>
    <meta charset="utf-8">
    <title>ottergram</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/3.0.3/normalize.min.css">
    <link rel="stylesheet" href="stylesheets/styles.css">
  </head>

Ottergram HTML

Here's the body of the revised Ottergram page.

  <body>
    <header>
      <h1 class="logo-text">ottergram</h1>
    </header>
    <main>
      <ul class="thumbnail-list">
        <li class="thumbnail-item">
          <a class="thumbnail-item-a" href="imgs/otter1.jpg">
            <img class="thumbnail-item-img" src="imgs/otter1.jpg" alt="Barry the Otter">
            <span class="thumbnail-item-span">Barry</span>
          </a>
        </li>
        <li class="thumbnail-item">
          <a class="thumbnail-item-a" href="imgs/otter2.jpg">
            <img class="thumbnail-item-img" src="imgs/otter2.jpg" alt="Robin the Otter">
            <span class="thumbnail-item-span">Robin</span>
          </a>
        </li>
        <li class="thumbnail-item">
          <a class="thumbnail-item-a" href="imgs/otter3.jpg">
            <img class="thumbnail-item-img" src="imgs/otter3.jpg" alt="Maurice the Otter">
            <span class="thumbnail-item-span">Maurice</span>
          </a>
        </li>
        <li class="thumbnail-item">
          <a class="thumbnail-item-a" href="imgs/otter4.jpg">
            <img class="thumbnail-item-img" src="imgs/otter4.jpg" alt="Lesley the Otter">
            <span class="thumbnail-item-span">Lesley</span>
          </a>
        </li>
        <li class="thumbnail-item">
          <a class="thumbnail-item-a" href="imgs/otter5.jpg">
            <img class="thumbnail-item-img" src="imgs/otter5.jpg" alt="Barbara the Otter">
            <span class="thumbnail-item-span">Barbara</span>
          </a>
        </li>
      </ul>
    </main>
  </body>

The HTML is the same as the original except that we added classes to many elements in order to style them. Why not just style the tags? Two reasons:

  1. you should get comfortable with seeing HTML with class attributes, and
  2. if we expanded the page with other H1, UL, LI, A, IMG and SPAN tags that aren't part of this list, we wouldn't necessarily want these style rules to carry over to the new elements.

The second reason is important: labeling things with classes allows you to be more precise about what elements your style rules apply to. Styling every LI in a particular way is fine if you want to really commit to styling every LI that way, but it can be good to plan ahead or at least allow for variation in the future.

Just be aware of your options. Later, we'll see a way to reduce this clutter of extra CSS classes.

Ottergram CSS

Now, let's turn to the CSS rules. We'll go through them one at a time, but here's a link to the CSS file.

body {
  font-size: 62.5%;
  background: skyblue;
}

This is a rule for the body element, changing its font-size to be smaller than the default font size (from the browse). It also changes the background color.

.logo-text {
  background: white;
  text-align: center;
  text-transform: uppercase;
  font-size: 3.7em;
}

This next rule uses the selector .logo-text which applies to any element that has class="logo-text". Note the dot in the selector syntax, but not in the HTML. That's because the dot is not part of the name of the class; it just says "this is a class name".

We can apply this class to any element that we want to use for the logo text. In this page, it's just the H1.

The rule is pretty intuitive: it changes the background color to white, centers and converts the text to uppercase, and changes the font-size to 370% of the base size of the page. (Recall that em is a unit of measure that is relative to the current font size.)

.thumbnail-item-a {
  text-decoration: none;
  display: block;
  border: 1px solid white;
}

This rule happens to apply to the hyperlinks that surround each picture. (You can look back at the HTML to see all the elements that are class="thumbnail-item-a".) The rule removes the text decoration (the underline) that is the default for hyperlinks. It also uses display:block to convert the hyperlink into a block element, rather than inline (which is its default). That means the hyperlinks will be boxes that stack vertically on the page. We also add a white border to the box.

.thumbnail-list {
  padding: 0;
}

This next rule happens to apply to the UL element (bullet list). UL elements by default have a generous left margin, so that the list items will be indented. Here, we remove that. Note that padding is a shorthand for all four sides of the box.

.thumbnail-item {
  display: inline-block;
  border: 2px solid white;
}

This rule is for each of the LI (list item) elements of the UL. By default, LI elements are block elements, but here we want to allow them to come next to each other on the page, so we make them inline-block. The inline-block value is a hybrid between block and inline: it is similar to block in that the element is a box and has the full box model (margins, borders, padding, and width), but is similar to an inline element in that they can come next to each other on the line if there is room (like words in a paragraph).

As a side-effect, setting display: inline-block gets rid of the bullet. The default display property for an li element is display: list-item.

.thumbnail-item-img {
  display: block;
  width: 100%;
}

This rule is for the IMG (image) elements. By default, images are inline elements and come next to each other on the page, like great big words. (Most people find this pretty weird at first: the image looks like a block element (a big box), but doesn't act like a block element.) Having turned it into a block element, we can use the width:100% property so that the image will be automatically resized to fill its container. This is pretty cool.

.thumbnail-item-span {
  display: block;
  margin: 0;
  padding: 0.4em 1em;
  background: slategray;
  color: lightblue;
  font-family: sans-serif;
  font-size: 1.8em;
}

Our last rule is a doozy. It converts the SPAN inside each LI element into a block element (rather that the default, which is inline). It then changes a lot about the box mode: margins, padding, and background color. Finally, the color, family and size of the font is modified.

That's it! 42 lines of CSS in total, and the page looks much better.

Summary

  • CSS is how we apply style to our page.
  • It consists of a set of rules
  • Each rule comprises a set of property / value pairs, like color: red
  • The box model applies to all block elements, such as paragraphs (p), lists (ol and ul), list items (li) and div.
  • In the box model, an element has (from outside to inside):
    • margin. This just has width
    • border. This has a width, style and color
    • padding. This just has width. Its background color is the same as for the content
    • content.
  • Each rule also has a selector, which chooses which element(s) to apply the rule to.
  • Simple selectors include:
    • tag, like p to apply to all paragraphs. Has to be one of the built-in HTML tags.
    • .class_name to apply to all elements with class='class_name'. We get to make up the class name.
    • #id_name to apply to the sole element with id='id_name'. We get to make up the id name.
  • The difference between classes and ids is that an id has to be unique.