lesson 3

CSS part 2

Typography

Although CSS can very capably position and style text, the typographic control available still pales in comparison to those in print. Combined with varied screen size and platform rendering differences, typography on the web is a challenge. Fortunately, however, there are many tools at our disposal, as well as several exciting additions currently in development.

font-* property group

The font-* group of properties deals mainly with the selection and appearance of individual typefaces:

font-family

The font-family property is a prioritized list of font family names, or generic family types, used to select a font in which to render selected element text. From highest to lowest priority, the selection of family to use is based on the availability of individual character glyphs, and takes into account other font-* properties applied. In general, the browser will select the first font on the list that is installed on the computer (or that can be downloaded using the information provided by an @font-face at-rule), or the system default for a generic font family type if one is specified


    body {
      font-family: Georgia, Times, "Times New Roman", serif;
    }
        

Always include a generic family name (serif, sans-serif, cursive, fantasy, monospace) as a final fallback

@font-face

Unfortunately, there are very few font-family choices that work by default across platforms/devices, so our choice of font families is limited. Fortunately, however, it is possible to use web friendly versions of any font with the @font-face at-rule. Doing so, we are able to load specific font styles and weights at runtime:


    @font-face {
      font-family: 'MavenProBold';
      src: url('../fonts/mavenpro-bold-webfont.eot');
      src: url('../fonts/mavenpro-bold-webfont.eot?#iefix') format('embedded-opentype'),
        url('../fonts/mavenpro-bold-webfont.woff') format('woff'),
        url('../fonts/mavenpro-bold-webfont.ttf') format('truetype'),
        url('../fonts/mavenpro-bold-webfont.svg#MavenProBold') format('svg');
      font-weight: normal;
      font-style: normal;
    }
        

use the font squirrel @font-face generator to convert a font to a web font

font-size

font-size is the primary basis for establishing a consistent and unified typographic layout. Remembering that many typographic styles are inheritable, setting the base font-size on the body will define a starting value from which all others may be derived. Using em values to specify an element's font-size will then be based off this initial value:


    body {
      font-size: 100%; /* browser default of 16px */
    }
    h1 {
      font-size: 2.5em; /* 40px = 16px * 2.5 */
    }

    body {
      font-size: 87.5%; /* 14px = 16px * 0.875 */
    }
    h1 {
      font-size: 2.5em; /* 35px = 16px * 2.5 */
    }
        

Be aware that em values are compounded because they are relative to an element's parent value. As a result, if a parent element specifies a font-size of 0.875em (14px), a child element with a font-size of 0.75em is equivalent to 10.5px, not 12px.

em values are relative to a parent's font-size

An alternative to em is the rem unit. This unit behaves exactly the same, with the exception that it is relative only to the base font-size value:


    body {
      font-size: 100%;
    }
    section {
      font-size: 0.875rem; /* 14px = 16px * 0.875 */
    }
      section p {
        font-size: 0.75rem; /* 12px = 16px * 0.75 */
      }
        

rem values are relative to the root font-size

oldIEIEWebkitFirefoxiOSAndroid
line-height

While font-size defines the amount of vertical space a line of text should occupy, the line-height property is used to set the vertical space between multiple lines. In typesetting terms, line-height is equivalent to leading. In CSS terms, it is the value used to determine the amount of space above and below an in-line box. It accepts the following values:


    body {
      font-size: 100%; /* browser default of 16px */
      line-height: 1.5; /* 24px = 16px * 1.5 */
      /* each line will have 4px of negative space above and below */
    }
        

percentage and em values have poor inheritance behaviour.
Use a unitless number instead

font-weight

A font's weight is defined by keyword or value, and only applies if the current family supports multiple weights, otherwise the closest available weight is used:

font shortcut

The font property is a shortcut property combining all of the above properties into one:


    body {
      /* style(opt) weight(opt) variant(opt) size(opt)/line-height(opt) family */
      font: italic bold small-caps 100%/1.5 sans-serif;
    }
        

text-* property group

The text-* group of properties deals with the styling and placement of individual characters, words, and paragraphs:

text-overflow

Text that breaks outside of it's container can be truncated by setting text-overflow to either clip (cut text off) or ellipsis (replace trailing letters with '...'):


    h2.title {
      white-space: nowrap; /* prevent line from wrapping */
      overflow: hidden; /* REQUIRED */
      -o-text-overflow: ellipsis;
      text-overflow: ellipsis;
    }
          

This is really inconveniently long title

text-shadow

One or several (separated by commas) drop shadows can be applied to text with the text-shadow property:


    span.shadow {
      color: white;
      /* offset-x offset-y blur-radius colour */
      text-shadow: 0px 1px 1px black;
    }
          

shadow text

text-shadow does not require vendor prefixes (amazingly)

oldIEIEWebkitFirefoxiOSAndroid

rhythm and scale

Typography is more than just selecting a font family, size, and styling. A page of text is a composition of words, sentences, and paragraphs that form a visual rhythm and tempo. Controlling the layout and sizing of elements should therefore conform to some sort of rule-based order.

baselines and grids

One way to compose an ordered visual tempo is possible through the use of a combination of grid and baseline:

Grid

In a grid-based system, horizontal tempo is established by dividing the page width into evenly sized columns and gutters. There are several approaches possible, and many grid systems exist out there, but at it's most basic, column widths are set with a specific width value, and column placement is set with a specific margin-left value, pushing an element to the right in alignment with other elements in that column:


    body {
      font-size: 100%;
      width: 960px;
    }
    /* column width of 60px and gutters of 20px */
    .col1 { margin-left: 10px; }
    .col2 { margin-left: 90px; }
    ...
    .colSpan1 { width: 60px; }
    .colSpan2 { width: 140px; }
    ...
        
Baseline

In a strict grid-based system, vertical tempo can be enforced by the use of a baseline value to evenly space elements vertically in the page. Using this 'magic' value, it's possible to define sizing and spacing combinations that conform to this layout for headings, images, and all other content. Naturally, a baseline value equivalent to the base line-height makes an ideal starting point:


    body {
      font-size: 100%; /* browser default of 16px */
      line-height: 1.5; /* 24px = 16px * 1.5 */
      /* 24px is our magic baseline number */
    }
    h1 {
      font-size: 2em; /* 32px = 16px * 2 */
      margin: 0;
      padding: 0.75em 0;
      /* total height = line-height + padding-top + padding-bottom */
      /* 72px = (32px * 1.5) + ((0.75 * 16px) * 2) */
    }
        

when enforcing a baseline grid, it's often best to use padding rather than margin to enforce spacing in order to avoid margin collapsing

modular scale

Another approach to rule-based layout order is the creation of a modular scale of meaningful, resonant numbers that can be used for sizing, spacing, and dimensioning of elements. Inspired by work in The Elements of Typographic Style, modular scales are often based on a significant ratio, from the golden section (1:1.618), to musical scales (the perfect fourth 4:3, the perfect fifth 3:2, etc).

There are several tools available for generating modular scales (typograph, modularscale.com), and lots of nerdy, explanations on why you should be doing so.

Colours

Several CSS properties accept colour values, including color, background-color, and border-color. Although hex colour is the most common way, several colour formats are valid:

Backgrounds

Remembering that each element is a rectangular box, we can style our content by filling an element's background. CSS allows us to fill an element with a background colour and/or one or more images (including generated gradients). There are several background-* properties available to control how an element's background appears:

background-image

The background-image property attaches one or more images to an element's background area. Multiple backgrounds are simple separated by a comma:


    div.box {
      background-image: url('cat.jpg'), url('dog.jpg');
      background-repeat: no-repeat;
      background-position: top left, bottom right;
    }
          

When using multiple background-images, the z-order is reversed, with the first image on top

oldIE (multiple bg)IEWebkitFirefoxiOSAndroid

gradients

CSS3 makes it possible to generate gradient images for use in the background-image property. Gradients come in both linear and radial flavours:


    div.box {
      /* requires vendor prefixed versions */
      background-image: linear-gradient(to bottom right, blue, white);
    }

          

as the syntax is still under development, it's advisable to use a syntax generator or preprocessor to cover all the variations

oldIEIEWebkitFirefoxiOSAndroid

There are a number of impressive background patterns that can be generated with gradients.

sprite sheets

Sprite sheets are a great way to reduce the number of http requests by combining a number of images into one file. This enables the same file to used for multiple element backgrounds:


    div.circle {
      background-image: url('sprite.png');
      width: 50px;
      height: 50px;
    }
    #blackCircle {
      background-position: -10px -10px;
    }
    #greenCircle {
      background-position: -110px -10px;
    }

          

be sure to use a logical layout grid in your .psd, and remember to leave enough transparent area around each image

inline

In certain circumstances (when not using a sprite sheet, for example) it may be desirable to embed an image directly in CSS. This saves making an additional http request, and is ideal for small icons:


    div.box {
      background-image: url('data:image/png;base64,R0lGODlhDwALANUAACYpK////
        7KztEhLTJKUlU5QUv7+/mNlZy8yNCksLWttbjo8PmFjZJCRkk9RU7W2t9rb29jY2Zqbn
        udnpmam0tNT9/f30dKS01QUb/AwUBCRCksLkBDRUFERqanqP39/S8xM/X19ebn59bX13
        V3eNnZ2uDh4Xh6e42PkCwvMWhqbPz8/Jyen/Hx8X+Bgvj4+O3t7js+QK+wsa2urwAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAAPAAsAAA
        ZUQIBwOKwciMIOgjiAvThIhakRE0YCAcuAmFgFQiQVFltCygzYzxgrYAwL63jANQQR5A
        EDJqXZDCFyFEIXLDMSEyJxGUQFI3ItBEhCDigCDx4nC0hBADs=');
    }

          

open terminal and use the following command to copy the generated data to the clipboard:
openssl base64 < path/to/file | tr -d '\n' | pbcopy

background-position

The positioning of background images is specified by the following values:


    div.box {
      background-image: url('cat.jpg');
      background-position: 50% 50%;
      background-repeat: no-repeat;
      background-color: black;
    }
          

centering a background image behaves as expected: 50% or center places the image in the middle of the background automatically

background-size

The background-size property enables resizing of background images, and is specified by the following values:


    div.box {
      background-image: url('cat.jpg');
      background-size: cover;
    }
          

it's possible to simulate background-size: cover on oldIE by using the following filter: filter: "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='myBackground.jpg', sizingMethod='scale')";

oldIEIEWebkitFirefoxiOSAndroid

border-radius

The border-radius property allows us to modify an element's rectangular bounding box by adding rounded corners:


    div.box {
      -webkit-border-radius:10px;
      -moz-border-radius:10px;
      -o-border-radius:10px;
      -ms-border-radius:10px;
      border-radius:10px;
    }
    div.circle {
      -webkit-border-radius:25px;
      -moz-border-radius:25px;
      -o-border-radius:25px;
      -ms-border-radius:25px;
      border-radius:25px;
    }
          

border-radius is a shortcut property, so it's also possible to set the radius on individual corners:
border-top-left-radius, border-top-right-radius, border-bottom-right-radius, border-bottom-left-radius

oldIEIEWebkitFirefoxiOSAndroid

box-shadow

The box-shadow property makes it possible to add one or more drop shadow effects to the outside or inside of an element's bounding box:


    div.box {
      /* inset(opt) offset-x offset-y blur-radius(opt) spread-radius(opt) colour */
      -webkit-box-shadow: 0 2px 2px 1px rgba(0,0,0,0.5);
      -moz-box-shadow:0 2px 2px 1px rgba(0,0,0,0.5);
      -o-box-shadow:0 2px 2px 1px rgba(0,0,0,0.5);
      -ms-box-shadow:0 2px 2px 1px rgba(0,0,0,0.5);
      box-shadow:0 2px 2px 1px rgba(0,0,0,0.5);
    }
          

When using multiple shadows, the z-order is reversed, with the first shadow on top

oldIEIEWebkitFirefoxiOSAndroid

Generated Content

With the goal of keeping presentational markup out of our html, sometimes it's necessary to generate content directly inside of CSS. The :before and :after pseudo-elements allow us do just that by allowing us to define new content and styling on any container element:


    h2.title:after {
      content: ''; /* can be text content or image url() */
      display: block;
      position: absolute;
      bottom: 10px;
      left: 25%;
      width: 50%;
      height: 2px;
      background-color: blue;
    }
          

some title

generated content cannot (currently) take advantage of css-transitions

oldIE (:after)IEWebkitFirefoxiOSAndroid

Take a look at all the fancy things you can do with these pseudo-elements: totally, cool!

Transitions

CSS transitions allow property changes to be applied over time. Not all properties can be transitioned, but, in general, colours and properties with numeric values can all be changed over time. Transitions are defined with the following properties:

To enable transitions on a selector, the transition-* properties must be defined up front. When a transitioned property's value is changed later on, the property will then animate for the specified duration:


    div.rollMe {
      background-color: blue;
      /* vender prefixes required */
      transition-property: background-color;
      transition-duration: 500ms;
      transition-timing-function: ease-out;
    }
    div.rollMe:hover {
      background-color: yellow;
    }
          

The transition property is a shortcut property combining all of the above properties into one:


    a {
      /* property duration timing-function delay */
      -webkit-transition: all 500ms ease 100ms;
      -moz-transition: all 500ms ease 100ms;
      -o-transition: all 500ms ease 100ms;
      transition: all 500ms ease 100ms;
    }
        

as long as transitions are only for sexiness sake, there is generally no need to provide a javascript fallback for IE

oldIEIEWebkitFirefoxiOSAndroid

Transformations

CSS transforms modify the coordinate space of affected content without disrupting the normal page flow. Transforms enable rotation, scaling, skewing, and translation.

There are two properties used to define a transformation:


    div.rotateMe {
      background-color: blue;
      /* vender prefixes required */
      transform-origin: 50% 50%/
    }
    div.rotateMe:hover {
      /* vender prefixes required */
      transform: rotate(45deg);
    }
          

3D transforms are also possible on certain platforms

oldIEIEWebkitFirefoxiOSAndroid

Media Queries

Media queries allow us to limit style scope based on the current media's features (width, height, colour, pixel-density, etc.). This allows us to target styles for specific ranges of device. We have already seen that media queries in html can be used to load different style sheets, but it's also possible to use media query statements directly in CSS as well:


    /* big screen */
    @media screen and (min-width: 1200px) { /* styles here */ }
    /* medium screen */
    @media screen and (min-width: 700px)
      and (max-wdith: 1199px) { /* styles here */ }
    /* small screen */
    @media screen and (max-width: 699px) { /* styles here */ }
    /* smart phone */
    @media screen and (min-device-width: 320px)
      and (max-device-width: 480px) { /* styles here */ }
    /* tablet: landscape */
    @media screen and (min-device-width: 768px)
      and (max-device-width: 1024px)
      and (orientation: landscape) { /* styles here */ }
    /* high pixel density device */
    @media screen and (-webkit-min-device-pixel-ratio: 2),
      screen and (min-device-pixel-ratio: 2) { /* styles here */ }
        

a fluid layout with adjustments at small/medium/large sizes will be the most device friendly approach: targeting specific pixel sizes may not cover all possible devices

oldIEIEWebkitFirefoxiOSAndroid

Preprocessors

CSS is rich with features, but because it's a standardized language, change can come slowly, and when it does come, it is often burdened with experimental prefixes (and more typing). As a result, there are many tools available that treat CSS as a compile target. These preprocessors can simplify development by improving syntax and other shortcuts, then generate CSS on command. Some of the features available can include:

Some of the most popular preprocessors include Stylus, Less, and Sass.

all preprocessors rely on an underlying programming environment (Node.js, Ruby, etc), and are generally not for the terminal shy

Debugging

The best way to debug CSS is directly in the browser. Modern browsers all have excellent debugging tools built in, just right-click an element and 'inspect' it.

debugger

From within the inspector panel it's possible to see which styles are currently being applied, and edit those styles in real-time, including adding new ones.

do yourself a favour and learn to love the debugging inspector

60