An intro to CSS

CSS stands for Cascading Style Sheets

CSS is the standard language/format for styling web pages, which specifies what the page’s HTML will look like in the browser.

In our ongoing analogy, CSS is the skin of the web. Just like HTML, at its most basic it is still just text, in a file, on a computer. It can live inside HTML documents themselves, but is more commonly seen on its own with the extension .css

CSS came after HTML, first proposed by H√•kon Wium¬†Lie in¬†1994‚ÄĒwho was working with our friend Tim at CERN and wanted more control over the¬†presentation of¬†web pages. (Tim was against the idea, thinking it should be up to¬†each user.) It‚Äôs had three major revisions that have grown the vocabulary:

For the past decade or so, features have been added incrementally by¬†browsers ‚Äúwithin‚ÄĚ the CSS¬†3 ‚Äústandard.‚ÄĚ That‚Äôs how it goes, these¬†days.

The change in relationship between generator and consumer of information is going to take some getting used to. […] That said, I’ll comment that style sheets constitute a wormhole into unspeakable universes. People start thinking they’ll just set up a little file in SGML or something else, and soon it grows [uncontrollable].

James D. Mason

Where CSS lives

Before we get into CSS itself, let’s talk about how it is incorporated with HTML. There are three ways it can be added:

  1. Inline on HTML tags themselves
  2. Via <style> elements in HTML documents
  3. As separate/external .css files, via <link> elements

1.‚ÄÉInline with style=

This is the most straightforward way to add styles, directly as attributes in HTML tags:

<p style="color: red;">This text will be red!</p>

Seams obvious. However this has some downsides‚ÄĒimagine you want to¬†style all of¬†your paragraphs in¬†the¬†same way, and¬†with multiple properties:

<p style="color: red; font-family: sans-serif;">This text will be red!</p>
<p style="color: red; font-family: sans-serif;">I’d also like this to be red.</p>
<p style="color: red; font-family: sans-serif;">And they are all sans-serif, too.</p>

It makes it hard to¬†read, and¬†hard to¬†change and maintain‚ÄĒyou‚Äôd have to¬†update every single instance. (In¬†software, we‚Äôd refer to¬†this as brittle‚ÄĒmeaning it is easy to¬†break.)

2.‚ÄÉAlong comes <style>

So the next way that was added to the standard was using a special HTML element, <style>, that wraps blocks of CSS that then apply to an entire document. They go up in the <head> of our HTML documents.

The rules are written written with selectors‚ÄĒmore on¬†those, below. But importantly, we can now control styling of¬†all the paragraphs easily, at¬†once.

<!doctype html>
		<title>Page title</title>
			p {
				color: red;
				font-family: sans-serif;
		<p>This is a paragraph.</p>
		<p>This is another paragraph.</p>
		<p>This is third paragraph.</p>

3.‚ÄÉExternal with <link>

So this is already much better, allowing us to style whole pages easily and consistently. But what about when we have multiple pages?

If you wanted a whole site to use the same styles, you’d have to duplicate the <style> tag over and over, updating it everywhere whenever it changes. Still brittle. So along comes the <link> element.

<!doctype html>
		<title>Page title</title>
		<link href="style.css" rel="stylesheet">
		<p>This is a paragraph.</p>
		<p>This is another paragraph.</p>
		<p>This is third paragraph.</p>

And then in¬†a¬†separate style.css file (in this case, in¬†the same directory as our HTML file), we can have the same rules as before‚ÄĒno need for the outside wrapping <style> tag.

This will apply to any page that we add the <link> to, and updating the styles will now change the color of the paragraphs for our entire web site.

p {
	color: red;
	font-family: sans-serif;

We‚Äôll talk more about specificity later, but it is worth noting that the inline approach will usually take precedent over other methods‚ÄĒunder the ‚Äúclosest, then¬†lowest‚ÄĚ logic.

Separation of Concerns

Separation of Concerns is the ideology that code should be split up into sections that are responsible for a single behavior. In the case of websites, HTML, CSS, and JS can be seen as content, form, and function. (Or in our analogy: skeleton, skin, and muscles.) It’s often easier to reason about the website’s code if you keep the code for those three behaviors in separate files.

CSS rules

Even though it is used to style HTML elements, the syntax of CSS is very different. CSS rules are made up of selectors, used to target certain elements, and then the declarations that you want to apply to them.

The curly brackets { } (also known as mustaches or handlebars, for their shape) enclose all the declarations you want to apply to a given selector. These declarations are in turn made up of properties and values.

Properties are always separated from their corresponding values by a colon :, and each declaration line has to end in a semicolon ;. (It’s just how it is.) Also, there are no spaces between values and their units (like 20px)!

There are many, many CSS properties. (Here¬†is¬†a¬†shorter ‚Äúcommon‚Ä̬†list.) We‚Äôll go over¬†some in¬†our exercise, but look through these¬†to¬†become more familiar.


Just like HTML, CSS does not care about capitalization, extra white space, or line breaks. Folks generally use tabs/indenting to indicate hierarchy, but again it is just whatever makes it easier for you!

Capitalization does matter when using ID or classes as selectors, which have to match the HTML to target correctly. Like with HTML, it’s easiest just to be consistent and stick to lowercase.

p {
	color: red;

/* Is the same as… */


Basic selectors

Selectors are used to target certain HTML elements within the page. These can get pretty complicated, but we’ll look at the three simplest and most common methods to start:

  1. Elements
  2. Classes
  3. ID

1. By element type

If you want to change the styles for all instances of a given HTML element, you drop the < > from the tag for an element selector. These are called type selectors:

Note that CSS has different /* comment syntax */, too.

2. With a class

But maybe you don’t want to style all of the paragraphs. You can then use a class to target specific instances. They are added as an attribute on the element you want to target:

The value here is our class name, which we write in CSS by prefixing with a . as with .highlight and .faded.

You can use these over and over, on¬†any kind of¬†element. And individual elements can have multiple classes, too. Class names can be whatever you want‚ÄĒthere are whole methodologies about what to¬†call these things. They are the most common way to¬†target things in¬†CSS.

We’ll talk about how conflicting rules are handled, below.

3. With an ID

You can also use an¬†id, which is a¬†kind of¬†special attribute that can only be used once in¬†an HTML document. These are useful thus useful for targeting singular things‚ÄĒlike your navigation, the document title, specific headings, etc:

These are prefixed by # in CSS, as with #title and #introduction. They can also be used as link destinations.

Fancy selectors

Combinations and groups

You can use combinations of¬†the above elements, classes, and¬†ID to¬†be even more specific‚ÄĒhowever, this likely means you just need to¬†rethink your HTML structure. (We‚Äôll unpack specificity, below.)

More commonly, you might apply declarations to multiple selectors, called group selectors, with a comma-delineated selector list:

With specific attributes

You can use the various attributes as selectors, too. These are usually very similar to using classes, but can help you differentiate things like internal and external links, for example:


These are special selectors, added to element, class, or id which target unique states or instances of HTML elements. You’ll often see these used to target link states:

:hover also works on any element, not just links!

Other common examples have to do with counts and positions:


Slightly different the various pseudo-elements, which let you style a particular part of an element.

You’ll most often see these as ::before and ::after, which let us insert things around text.

Note the difference in : for pseudo-selectors and :: for pseudo-elements.

Finally, combinators

Last, you will often want to¬†target something based on¬†its relationship to¬†other elements‚ÄĒits siblings or its parents.

For this, CSS has combinators, which let you relate all the various selectors we’ve learned about here together:

Importantly, combinators can only target elements top-down, meaning that it can only ‚Äúsee‚ÄĚ elements before and above themselves‚ÄĒmeaning their previous (older?) siblings or their parents. This directionality somewhat corresponds with the cascade, which we‚Äôll talk about¬†shortly.

:has() will change this!

For many, many years folks have wanted a¬†‚Äúparent selector‚ÄĚ in¬†CSS‚ÄĒmeaning a¬†way to¬†apply a¬†style to¬†a¬†parent/container based on¬†one of¬†its children. This¬†has not been possible before, as we mentioned above.

CSS has finally added the :has() pseudo-class, just in the past year. It will allow us to write much simpler, logical styles:

div:has(p) { background-color: red; }

Safari and Chrome both added support‚ÄĒbut Firefox is¬†still notably absent. Someday!


The first three targeting methods (element, .class, #id) are listed in increasing order of specificity, meaning that a class trumps an element rule, and an ID trumps a class. IDs are thus more specific than classes, which are more specific than element selectors. (And you shouldn’t really use them, but inline styles beat them all.)

Take this example:

You could write a¬†long book (and many people have) about CSS specificity‚ÄĒthe myriad of¬†ways that some CSS rules take precedent over others. It is often one the more frustrating parts (especially when working with legacy code that is poorly considered).

Suffice it to say it’s complicated. The easiest way to avoid specificity problems is generally to stay at the same level throughout your HTML, usually by just using classes throughout.

Oh right, the cascade

We haven‚Äôt even talked about that first C‚ÄČ! Remember, it¬†stands for cascading.

This means that when there is a¬†tie (like two classes applying the same property), the lowest rule wins‚ÄĒliterally the one further down within a¬†CSS document, or¬†within a¬†style tag. If you have multiple CSS documents with <link> element, the lower linked document will take precedence:

And inheritance

To add even more confusion, some CSS properties set on¬†a¬†parent also apply to¬†their children‚ÄĒsuch as color or font-family. Most spacing/layout properties, like width and margin do not. (More on¬†those, next week.)

This allows you to quickly set some properties globally, without having many brittle/redundant rules, as we did before:

All the children inherit the body styles. Ah, finally, sans-serif.

Color and type properties

Alright, so all this has been about targeting elements‚ÄĒwhat about actually styling them? Let‚Äôs introduce a¬†few quick properties to¬†get us started.


Besides the basic examples above, color can be specified in a few different ways:

There are 147 named CSS colors! tomato is a favorite.

Named colors are quick to work with when you know a few, but hsla offers a more intuitive way to adjust and work with colors.

These can also all be applied to background-color (and border, but we’ll talk about that next week).


Then perhaps most importantly, you’ll always be customizing your typography. Remember, the web is text all the way down:

With great power comes great responsibility.

Web font licensing is a¬†Whole Big Thing‚ÄĒso let‚Äôs start out by making use of¬†Google Fonts, which offers many open-source typefaces nicely packaged for web use. You can select families and weights there to¬†easily include in¬†your pages, as in¬†the example above.

Other type properties!

Once you’ve got a font-family in, there are additional properties to control the typography:

For now, you can just specify units in px to match Figma. We’ll talk about other absolute and relative units soon.


As we talked about last week, browsers have their own, built-in way that they display HTML elements. These user-agent styles are specific, somewhat, to each platform and each browser.

This is the ‚Äúlook‚ÄĚ we have been seeing when we write plain HTML without any CSS‚ÄĒusually Times New Roman, with blue links, and¬†small spacing between¬†elements.

Often, when you are working towards your own design, you will find yourself fighting against these built-in styles. So many designers/front-end folk instead start with resets‚ÄĒa¬†semi-standard collection of¬†CSS rules that ‚Äúzero¬†out‚ÄĚ the browser‚Äôs built-in styles.

This means you have to write everything yourself, but you have more control and aren’t building on unknown foundations. And things should be (more) consistent, across browsers and platforms.

Here is a simple, modern one for your <head>:

<link href="https://typography-interaction-2324.github.io/assets/reset.css" rel="stylesheet">

This is what we use here for our course site!

The author of HTML documents has no influence over the presentation. Indeed, if conflicts arise the user should have the last word, but one should also allow the author to attach style hints. The last point has especially been a source of much frustration among professions that are used to be in control of paper-based publishing. This proposal tries to soften the tension between the author and the reader.

Håkon Wium Lie