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
: list of specific names or a generic font typefont-size
: absolute or relative sizefont-style
: italic version (normal | italic
)font-weight
: lightness or boldnessfont-variant
: small-caps (normal | small-caps
)
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
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:
normal
: browser default value (roughly 1.2)number
: unitless number to be multiplied by an element's font size (recommended)length
: specific size in pxpercentage
: relative to element's font size
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:
normal
: default weight (equivalent to400
)bold
: bold weight (equivalent to700
)lighter
: one weight lighter than parent elementbolder
: one weight bolder than parent element100
,200
,300
,400
: light weights (default tonormal
if no lighter weights available)600
,700
,800
,900
: bold weights (default tobold
if no other bold weights available)
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-align
: text alignment in parent container (left | center | right | justify
)text-decoration
: line drawn over, under, or through (none | underline | overline | linethrough
)text-indent
: shift the first line of a paragraph from the edge of the container (negative values possible)text-overflow
: how overflowed text is displayedtext-shadow
: drop shadow applied to text and it'stext-decoration
text-transform
: text capitalization (none | capitalize | uppercase | lowercase
)letter-spacing
: spacing between letters (length indicates increase/decrease in addition to the default value)
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;
}
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)
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:
- keyword (
red
,blue
,green
, etc): output varies by platform, but often useful for quick and dirty debugging - hex (
#ff9933
or#f93
): each colour channel (r, g, b) expressed in hexadecimal notation - rgb (
rgb(0,128,255)
): each colour channel from 0-255 expressed in functional notation - hsl (
hsl(0,50%,25%)
): a hue angle from 0-360, followed by saturation and lightness percentage values from 0-100%, expressed in functional notationoldIEIEWebkitFirefoxiOSAndroid - rgba (
rgba(0,128,255,0.5)
): each colour channel from 0-255, plus an additional alpha value from 0-1, expressed in functional notationoldIEIEWebkitFirefoxiOSAndroid - hsla (
hsla(0,50%,25%,0.5)
): a hue angle from 0-360, followed by saturation and lightness percentage values from 0-100%, plus an additional alpha value from 0-1, expressed in functional notationoldIEIEWebkitFirefoxiOSAndroid - transparent (
transparent
): no colour (useful for resetting previously applied colour)
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-color
: a valid colour value (hex, rbg, rgba, hsl, hsla)background-image
: one or more image urls (or gradients)background-position
: initial position of each imagebackground-repeat
: how each image repeats horizontally and vertically (no-repeat | repeat
)background-attachment
: fix/scroll image with the viewport (scroll | fixed | local
)background-size
: size of image
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
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
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:
- percentages: size of the background, minus the size of the image (0% =
top
/left
, 50% =center
, 100% =bottom
/right
) - lengths: px/em/etc placement from the
left
andtop
- keywords:
top
,right
,bottom
,left
,center
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:
- percentage: relative to background area (horizontal and vertical)
- lengths: px/em/etc value (horizontal and vertical)
- keywords:
contain
(fill background with letterboxing) orcover
(fill background with cropping)
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')";
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
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
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
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:
transition-property
: the property to transition (none | all | property name
)transition-duration
: the duration in seconds(s) or milliseconds(ms)transition-timing-function
: the function used to determine how intermediate values are computed (ease | linear | ease-in | ease-out | ease-in-out | cubic bezier formula
)transition-delay
: the delay in seconds(s) or milliseconds(ms)
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;
}
- In general, there are three ways to change a property:
- selector pseudo class (
:hover
,:focus
, etc) - adding/removing an element's class with javascript
- modifying an element's css property directly with javascript
as long as transitions are only for sexiness sake, there is generally no need to provide a javascript fallback for IE
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:
transform-origin
: position of origin (percentage | length | top | right | bottom | left
)transform
: a space separated list of transforms to apply (none | transform function [rotate | scale | scaleX | scaleY | skewX | skewY | translate | translateX | translateY | matrix]
)
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
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
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:
- clean syntax (no brackets or semicolons)
- nested rules
- reusable variables
- reusable functions
- vendor prefixing
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.

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