text/plain

Substance and Style: Fundamentals

Introduction

Though it has been around for decades, CSS continues to confuse developers and designers alike. Its numerous implementations have blurred the line between standards-compliant and host-specific features. Through all of those implementations, there are some very important fundamentals. They are explained in detail below.

Nomenclature

CSS nomenclature is an important starting point. By understanding the underlying nomenclature, one can therefore understand extensions of the language and peruse standards documents with comfort.

First is the at rule[0]. At rules are denoted by an at sign (@). For example, the media at rule is used to target a specific media type, as seen below:

@media screen /* at rule */
{
    body {
        margin: 0;
    }
}

Second is the selector[1]. Below is a table of basic selectors are their purposes:

Name Example Purpose
Universal * Selects all elements.
Type body Selects elements of a certain tag name.
Descendant ol li Selects all elements of the second type which are descendants of the first element type (may be descendants of descendants).
Child ol > li Selects all elements of the second type which are direct descendants of the first element type (may not be descendants of descendants).
Adjacent dt + dd Selects all elements of the second type which are immediate siblings (after) of the first element type.
Attribute a[href] Selects all elements of a certain type which possess the specified attribute.
Class .enabled Selects all elements which possess the specified HTML class.
Id #header Selects all elements which possess the specified HTML id (should only be one).

Third is the block[2]. Web developers may recognise blocks from programming languages with C-type syntax. Blocks are placed right under selectors. For example:

body /* block starts below */
{   
    font-size: 100%;
} /* block ends */

Fourth is the rule[1]. A rule is a combination of a selector followed by a block. Below is an example:

/* rule starts */

/**
 * @selectors: body, .heading
 */

body,
    .heading
{
    margin: 0;
}

/* rule ends */

Fifth is the declaration[3]. Declarations consist of a property name followed by a colon (:) and a value. Declarations, when used in plurality, may be separated by a semicolon (;). See below:

body
{
    /**
     * @property: margin
     * @value: 0
     */
    margin: 0;
    font-size: 100%;
}

By specification, parsers must ignore invalid properties or values[4].

Specificity

When a parser parses CSS declarations, it analyses their specificity[5]. Specificity is a measure by which the combined values of selectors, and declarations are all calculated. The specificity value is the concatenation of four separate numbers. Those numbers are as follows:

  1. The number 1 if the style is from the HTML style attribute (inline).
  2. The number of id selectors inside of the selector.
  3. The number of attribute or class or pseudo-class (:) selectors.
  4. The number of type (element) and pseudo-element (::) selectors.

All other selectors have no specificity. Below are some examples of specificity:

<!DOCTYPE HTML>
<html dir="ltr" lang="en">
    <head>
        <meta http-equiv="Content-Type"
            content="text/html;charset=utf-8">
        <title>Specificity</title>
    </head>
    <body>
        <div id="header">
            <!-- 1000 specificity -->
            <h1 class="heading" style="font-weight: bold;">Specific</h1>
        </div>
    </body>
</html>

/* 0000 specificity */

*
{
    margin: 0;
    padding: 0;
}

/* 0001 specificity */

body
{
    font-size: 100%;
}

/* 0010 specificity */

.heading
{
    margin: .5em;
}

/* 0100 specificity */

#header
{
	background-color: #FFFFFF;
}

/* 0120 specificity */

#header .heading:hover
{
    border: 1px solid #000000;
}

In specificity wars, the trump card is the !important rule[6]. Its use instructs parsers to ignore specificity for a particular declaration. In the specificity war, think of it as if it were a nuclear bomb. The only counter to a nuclear bomb is a bigger nuclear bomb. !important rules muddy the cascade[7]. They were created to permit users to override author style sheets, not to override previous author declarations. For example, consider the following:

<!DOCTYPE HTML>
<html dir="ltr" lang="en">
    <head>
        <meta http-equiv="Content-Type"
            content="text/html;charset=utf-8">
        <title>Bad Technique</title>
    </head>
    <body></body>
</html>

/* 0001 specificity */

body
{
    margin: 0 !important;
}

/* 0001 specificity */

body
{
    margin: 1em;
}

The latter declaration is supposed to apply because the selectors have the same specificity. However, because of the !important rule inside of the former declaration, the former declaration instead applies. A specificity war is thereby created and the normal, expected cascade is muddied.

Class-Based CSS

Because it is not an actual programming language, CSS often confuses developers. It seems to be difficult to organise. Therefore, the common id selector pattern has emerged. The pattern, however, leads to bloated style sheets full of styles suited to one and only one particular element. The problem is that elements often share common styles. Imagine the following two scenarios:

<!DOCTYPE HTML>
<html dir="ltr" lang="en">
    <head>
        <meta http-equiv="Content-Type"
            content="text/html;charset=utf-8">
        <title>Bad Technique</title>
    </head>
    <body>
        <div class="one_but_also_three" id="one"></div>
        <div id="two"></div>
    </body>
</html>

/* Bad Technique */

/* 0100 specificity */

#one,
    #two
{
    padding: 0;
}

/* 0010 specificity */

.one_but_also_three
{
    padding: 1em;
}
<!DOCTYPE HTML>
<html dir="ltr" lang="en">
    <head>
        <meta http-equiv="Content-Type"
            content="text/html;charset=utf-8">
        <title>Good Technique</title>
    </head>
    <body>
        <div class="one one_but_also_three"></div>
        <div class="two"></div>
    </body>
</html>

/* Good Technique */

/* 0010 specificity */

.one,
    .two
{
    padding: 0;
}

/* 0010 specificity */

.one_but_also_three
{
    padding: 1em;
}

In the first example, the declaration using the class selector will be overridden because it has a lower specificity number than the declaration with the id selectors, regardless of its place in the cascade[7]. Therefore, a specificity war will be created. Users and abusers of !important will recognise the problems which arise from specificity wars. In the second example, both declarations are used with selectors of the same specificity. Therefore, the logical order of the cascade is preserved. That is, the second declaration will override the first one because it resides later in the style sheet. The W3C has very specific guidelines for the cascade[8]. They are as follows (emphases are mine).

  1. Find all declarations that apply to the element and property in question, for the target media type. Declarations apply if the associated selector matches the element in question and the target medium matches the media list on all @media rules containing the declaration and on all links on the path through which the style sheet was reached.
  2. Sort according to importance (normal or important) and origin (author, user, or user agent). In ascending order of precedence:
    1. user agent declarations
    2. user normal declarations
    3. author normal declarations
    4. author important declarations
    5. user important declarations
  3. Sort rules with the same importance and origin by specificity of selector: more specific selectors will override more general ones. Pseudo-elements and pseudo-classes are counted as normal elements and classes, respectively.
  4. Finally, sort by order specified: if two declarations have the same weight, origin and specificity, the latter specified wins. Declarations in imported style sheets are considered to be before any declarations in the style sheet itself.

In simpler words, the cascade is calculated as follows.

  1. Declarations which match the target in question and have the correct media type are collected.
  2. Those declarations are then sorted in the following order:
    1. user !important declarations
    2. author !important declarations
    3. author normal declarations
    4. user normal declarations
    5. user agent declarations
  3. Those declarations are then sorted by specificity, highest to lowest. That is, the most specific declarations win.
  4. Those declarations are then sorted by their place in the style sheet, latest to earliest. That is, the latest declarations win.

On specificity alone, class-based selectors are a great idea. On the metric of code written, class-based selectors are an even better idea. By sharing common styles and not incurring specificity wars, class-based CSS is far more concise. Consider this example:

<!DOCTYPE HTML>
<html dir="ltr" lang="en">
    <head>
        <meta http-equiv="Content-Type"
            content="text/html;charset=utf-8">
        <title>Bad Technique</title>
    </head>
    <body>
        <div id="section_one"></div>
        <div id="section_two"></div>
        <div id="section_three"></div>
        <div id="section_four"></div>
        <div id="section_five"></div>
    </body>
</html>

#section_one,
    #section_two,
    #section_three,
    #section_four,
    #section_five
{
    margin: .5em;
}

By not applying a common HTML class to the sections, the rule becomes complex. Instead, the following rule could be written:

<!DOCTYPE HTML>
<html dir="ltr" lang="en">
    <head>
        <meta http-equiv="Content-Type"
            content="text/html;charset=utf-8">
        <title>Good Technique</title>
    </head>
    <body>
        <div class="section"></div>
        <div class="section"></div>
        <div class="section"></div>
        <div class="section"></div>
        <div class="section"></div>
    </body>
</html>

.section
{
    margin: .5em;
}

Classes are an excellent way to group common styles. When used in unison, they can be used for toggling styles. What follows is an example.

<!DOCTYPE HTML>
<html dir="ltr" lang="en">
    <head>
        <meta http-equiv="Content-Type"
                content="text/html;charset=utf-8">
        <title>Good Technique</title>
    </head>
    <body>
        <table class="table">
            <tbody class="table_section">
                <tr class="odd_row table_row">
                    <td class="table_cell">1</td>
                    <td class="table_cell">2</td>
                    <td class="table_cell">3</td>
                </tr>
                <tr class="even_row table_row">
                    <td class="table_cell">4</td>
                    <td class="table_cell">5</td>
                    <td class="table_cell">6</td>
                </tr>
                <tr class="odd_row table_row">
                    <td class="table_cell">7</td>
                    <td class="table_cell">8</td>
                    <td class="table_cell">9</td>
                </tr>
            </tbody>
        </table>
    </body>
</html>

.odd_table .even_row
{
    display: none;
}

If the initial class were not present on the corresponding tables, then the even rows would be shown; if it were present, then they would be hidden. By toggling the presence of the initial class, the display of certain child nodes may also be toggled.

A useful way to build upon browser defaults is to set base classes for specific elements. Take the anchor element as an example. By default, its text is blue in colour and changes with the state of the anchor. The following is an example:

<!DOCTYPE HTML>
<html dir="ltr" lang="en">
    <head>
        <meta http-equiv="Content-Type"
            content="text/html;charset=utf-8">
        <title>Good Technique</title>
    </head>
    <body>
        <a class="anchor" href="http://null.invalid"
            tabindex="1"
            title="Navigate to invalid link.">Invalid Link</a>
    </body>
</html>

body,
    .anchor
{
    color: #000000;
}

.anchor:hover,
    .anchor:focus
{
    color: #777777;
}

By using a base class instead of selecting every single element of a certain tag name, specificity becomes more manageable. Elements without the base class may maintain their default browser style in addition.

Base classes may also be overridden by proceeding classes. An element may reference both the base class and an override class. For example, consider this:

<!DOCTYPE HTML>
<html dir="ltr" lang="en">
    <head>
        <meta http-equiv="Content-Type"
            content="text/html;charset=utf-8">
        <title>Good Technique</title>
    </head>
    <body>
        <div class="header">
            <h1 class="heading title_heading">Good Technique</h1>
        </div>
        <h2 class="heading">Sub-Section</h2>
        <h2>Anomalous Sub-Section</h2>
    </body>
</html>

.heading
{
    margin: .5em;
    font-weight: normal;
}

.title_heading
{
    margin: 0;
}

The base class sets a default margin for the headings. The override class then overrides and removes that existing margin. Regardless, all headings with the base class maintained the normal font weight. Because the anomalous heading has neither class, it maintains the default browser style.

Units

Another common pattern is to use fixed units such as pixels. Pixels are suitable for inflexible layouts, but are fallible when multiple viewport sizes are desirable. Consider the following example:

body
{
    width: 960px;
    font-size: 12px;
}

Both the width and font size are very inflexible. The width is fallible when the viewport width is fewer than 960 pixels (most tablets and mobile devices). The font size is fallible for those who want to zoom or have a custom size set. Instead of a fixed width, a percentage width may be used. Once a certain threshold has been hit, the element may be targeted with a media query to modify the width. Instead of a fixed font size, ems may be used. Ems are relative to the size of the uppercase letter M. Therefore, they scale with zooming and are relative to pre-existing font size preferences. Imagine the following scenarios:

body
{
    width: 960px;
    font-size: 12px;
}

If the viewport were 800px wide by 600px long and the default font size configured (by preference or zoom) were 20px, then the body would be 960px wide and the size of its text would be 12px. The body would therefore overflow past its viewport and the text would be much smaller than the user desired.

body
{
    width: 75%;
    font-size: 1em;
}

Most often, that font size will be the default specified by W3C standards[9]. That is, it will be 1em (16px most often), just like the preceding example. If a larger size is desired, then it may be overridden via an additional override. See below:

/* This sets the initial base size. */

body
{
    font-size: 100%;
}

/* This overrides the initial base size. */

body
{
    font-size: 2em;
}

Because ems correlate with the current text size, they are also quite useful as units for widths, heights, paddings, and margins. Consider the following revision to the previous, fixed width example:

body
{
    width: 60em;
}

At the default, specified font size (1em at 16px), the body will be 960px wide. However, it will also scale with the size of the font. That additional flexibility is gained by using ems instead of pixels.

Character Set

One of the more esoteric and often forgotten features of a CSS style sheet is its character set[10]. Just as in HTTP, the character set may be declared inside of a CSS style sheet. Here is an example:

@charset "utf-8";

body
{
    font-size: 100%;
}

Just as in HTTP, the character set should be declared before the actual content (request body in HTTP) is sent. The ideal spot is at the top of a style sheet.

Email
["Articles".toLowerCase();]@fortybelow.ca
Twitter
mkmcdonald