Fall 2026
  • Discord
  • Gradescope
  • Syllabus

On this page

  • A rule
  • Selectors
  • Combinators, and the document tree
  • Counting matches
  • The cascade
  • Properties for the project

CSS

Last class our pages worked but were plain: black text, white background, the browser’s default font. HTML says what each piece of content is rather than how it should look. Colors, fonts, spacing, and layout are specified in a separate language called CSS, short for Cascading Style Sheets.

For most of the web, appearance is part of the product, and the people who dismiss front-end work tend to be the ones who cannot do it.

CommitStrip comic: a developer insists nobody needs a front-end developer, then produces an unstyled mess of div and br tags.

We will cover enough CSS to style your first project, focusing on selectors. Later in the term, the same selectors will identify which elements to extract when we scrape web pages.

A rule

A CSS rule has two parts: a selector that chooses which elements the rule applies to, and a declaration block in curly braces that says what to do to them. The simplest rule turns the text of every paragraph teal:

p {
    color: teal;
}

p is the selector, and it chooses every <p> element on the page. Inside the braces, color: teal; is one declaration, setting the color property to the value teal. Every declaration is a property: value; pair, and a block can contain several declarations, each ended by a semicolon. The rule applies to every paragraph on the page.

CSS can be written inline on a single element, in a <style> block in the page’s <head>, or in a separate file shared by every page. Use a separate file. Put your rules in a file called style.css and link it from the <head> of each HTML page:

<head>
    <title>My First Page</title>
    <link rel="stylesheet" href="style.css">
</head>

The <link> element pulls style.css into the page, so one edit to that file restyles every page that links it. Your first project will require exactly this setup.

Selectors

A type selector, such as p or h1, selects every element of that type. The class and id attributes let you select a smaller set of elements.

A class is a reusable label you can put on any number of elements. You add it in the HTML with the class attribute, and you select it in CSS with a dot:

<p class="bold">This paragraph is bold.</p>
<span class="bold">So is this span.</span>

Select that class in CSS:

.bold {
    font-weight: bold;
}

The .bold selector matches every element whose class is bold, regardless of its tag, so the paragraph and the span both go bold. Use classes whenever a style applies to a group of elements.

An id names one element and must be unique on the page. You add it with the id attribute and select it with a hash:

<h1 id="top">Welcome</h1>

Select that id in CSS:

#top {
    color: teal;
}

The #top selector matches the single element with that id. A class marks a category (“all the warnings”), while an id names one element (“the site header”).

Combinators, and the document tree

Selectors can also choose an element by its relationship to others. The browser represents nested elements as a family tree:

<body>
    <h1>Lorem <span class="bold">Ipsum</span></h1>
    <p class="bold">dolor sit amet</p>
</body>

Drawn as a tree, its structure is:

Tree diagram: a body element with two children, an h1 and a p that are siblings of each other; the h1 has a span child, which is a descendant of body.

<body> is the parent of both <h1> and <p>; those two are siblings because they share a parent; the <span> is a child of <h1> and a descendant of <body> (a child, or a child’s child, or deeper). Four combinators select elements by these relationships:

  • h1 span selects a descendant (note the space): every <span> somewhere inside an <h1>, at any depth.
  • h1 > span selects a child: every <span> that is a direct child of an <h1>, one level down.
  • h1 + p selects an adjacent sibling: the <p> that comes immediately after an <h1>, sharing a parent.
  • h1 ~ p selects a general sibling: every <p> that comes after an <h1> under the same parent.

body span matches our <span> because it is a descendant of <body>, while body > span matches nothing because the <span> is a child of <h1> rather than <body>.

You can group selectors with a comma to give several the same rule: h1, h2, p { color: teal; } styles all three, and you can select by any attribute in square brackets, like [src="cat.jpg"] for the image with that source. p .bold (a descendant selector) and p, .bold (two grouped selectors) differ only by a comma but select different elements.

Counting matches

The quiz asks you to count how many elements a selector matches in a chunk of HTML. Use the browser’s developer tools to check the count. Open any page’s developer tools with F12, go to the Console, and run:

document.querySelectorAll('h1 ~ p')

The browser returns the list of elements that the selector matches on the current page. Predict the count first, then run the selector and check your answer. The quiz provides a page of HTML and asks how many elements each selector matches. Work through the two problems in the practice quiz, writing down your counts before checking the answers. The answers were computed by running each selector against the page, so investigate any disagreement. The real quiz reuses the HTML from Problem 2.

The cascade

When two rules set the same property on the same element, the cascade determines which one applies.

CommitStrip comic: a developer explains that 'cascading' means rules have a priority order and weight, while a colleague ignores specificity and overrides everything with !important.

The cascade resolves conflicts by specificity: a more specific selector takes precedence over a less specific one. An id selector takes precedence over a class selector, and a class selector takes precedence over a type selector, because naming one element is more specific than naming a category, which is more specific than naming every tag. When two selectors tie on specificity, the one written later in the file takes precedence. Given p { color: black; } and #top { color: teal; }, the element with id top is teal because the id is more specific.

The !important annotation forces a declaration to apply regardless of specificity. Prefer to fix the selector’s specificity because repeated overrides make a stylesheet difficult to reason about.

Properties for the project

Project 0 needs a few more properties. Set text and background colors with color and background-color, and react to the mouse with the :hover pseudo-class, which selects an element only while the pointer is over it:

a {
    color: teal;
}
a:hover {
    background-color: #f2d6d9;
}

Links are teal and get a pale red background while the pointer is over them. A @media rule makes a page adapt to phones by applying nested rules only when a condition holds, such as a narrow screen:

@media (max-width: 600px) {
    body {
        font-size: 14px;
    }
}

On a screen 600 pixels wide or narrower, the text shrinks; on anything wider, this block does nothing. This is a basic example of responsive design, and your project rubric asks for one such rule. Look up other properties in the CSS cheatsheet or Shay Howe’s Getting to Know CSS.

Before starting Python, put HTML and CSS together in Project 0 and study for the selector quiz on paper, the way you will take it.