CSS Selectors and Specificity

Week 4: Tuesday Morning Session

The Power of Selection

Welcome to our deep dive into CSS selectors and specificity! Today we're exploring one of the most fundamental and powerful aspects of CSS - how to precisely target HTML elements for styling. Mastering selectors is like gaining a superpower that allows you to manipulate any part of your webpage with surgical precision.

By the end of this session, you'll understand not just how to select elements, but also how the browser decides which styles to apply when rules conflict - a concept known as specificity.

File Organization

As we continue our CSS journey, let's maintain good organization:

Understanding CSS Selectors

CSS selectors are patterns that match HTML elements on a webpage. They act as the bridge between your HTML document and the style rules you want to apply, telling the browser exactly which elements should receive specific styles.

The Anatomy of a CSS Rule

Before diving into selectors, let's quickly review how a CSS rule is structured:

selector {
    property: value;
    another-property: value;
}

The selector is what determines which elements the rule applies to. The better you understand selectors, the more control you have over your styling.

Selector Analogy: Fishing in the DOM

Think of CSS selectors like different fishing techniques in the ocean of your HTML document:

Just as different fishing situations call for different techniques, different styling needs call for different selectors.

Basic Selectors

Let's explore the fundamental selector types that form the backbone of CSS targeting.

Universal Selector (*)

The universal selector matches any element type. It's the most broad selector available.

* {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

Real-world use: Commonly used for CSS resets or to apply box-sizing consistently across all elements. Think of it as issuing a general order that applies to every single element on the page.

Performance note: Use with caution as it affects every element and can impact performance on very large documents.

Type/Element Selector

Selects all elements of the specified type.

h1 {
    font-size: 2em;
    color: navy;
}

p {
    line-height: 1.6;
    margin-bottom: 1em;
}

Real-world example: Setting base styles for text elements is like establishing a dress code for particular roles in a company. All employees in accounting (all paragraph elements) follow the same basic guidelines.

Class Selector (.)

Selects all elements with the given class attribute. Uses a period (.) followed by the class name.

.highlight {
    background-color: yellow;
    font-weight: bold;
}

.card {
    border: 1px solid #ddd;
    border-radius: 4px;
    padding: 1rem;
}

HTML usage:

<p class="highlight">This paragraph is highlighted.</p>
<div class="card">This is a card component.</div>

Multiple classes: HTML elements can have multiple classes, separated by spaces:

<div class="card highlight featured">
    This has three classes applied.
</div>

Real-world analogy: Classes are like clothing tags. A person (HTML element) can wear multiple tags (classes) like "formal", "blue", and "striped". Each tag/class can associate the person/element with different style rules.

ID Selector (#)

Selects the element with the specific ID attribute. Uses a hash (#) followed by the ID name.

#header {
    background-color: #333;
    color: white;
    padding: 1rem;
}

#main-content {
    max-width: 800px;
    margin: 0 auto;
}

HTML usage:

<header id="header">My Website</header>
<main id="main-content">
    Page content goes here.
</main>

Important rules for IDs:

Real-world analogy: An ID is like a Social Security number or passport number - it must be unique to a single individual, and each person has exactly one. In web terms, it's like a building's street address - there's only one 123 Main Street in a city.

Attribute Selector ([])

Selects elements based on the presence or value of attributes. Uses square brackets.

/* Selects all elements with a title attribute */
[title] {
    cursor: help;
}

/* Selects inputs with type="text" */
input[type="text"] {
    border: 1px solid #ddd;
    padding: 0.5rem;
}

/* Selects links that open in a new window */
a[target="_blank"] {
    padding-right: 20px;
    background: url(external-link-icon.png) no-repeat right;
}

Attribute selectors variations:

Real-world example: E-commerce sites often use attribute selectors to style product listings with specific data attributes, like [data-category="electronics"]. It's similar to a database query where you filter records based on specific field values.

Combinator Selectors

Combinator selectors create relationships between elements, allowing you to target elements based on their position in the document relative to other elements.

Descendant Selector (space)

Selects all elements that are descendants (children, grandchildren, etc.) of a specified element.

/* Targets all paragraphs inside articles */
article p {
    font-size: 16px;
    line-height: 1.6;
}

/* Targets all list items inside navigation */
nav li {
    display: inline-block;
    margin-right: 1rem;
}

HTML structure:

<article>
    <h2>Article Title</h2>
    <p>This paragraph will be styled by the rule.</p>
    <div>
        <p>This nested paragraph will also be styled.</p>
    </div>
</article>
<p>This paragraph outside the article will NOT be styled.</p>

Family tree analogy: The descendant selector is like referring to "all the descendants of the Johnson family" - it includes children, grandchildren, great-grandchildren, and so on, regardless of how many generations deep.

Child Selector (>)

Selects elements that are direct children of a specified element.

/* Targets only direct child paragraphs */
article > p {
    font-weight: bold;
}

/* Targets only direct list items in unordered lists */
ul > li {
    list-style-type: square;
}

HTML structure:

<article>
    <p>This paragraph is a direct child and WILL be styled.</p>
    <div>
        <p>This paragraph is a grandchild and will NOT be styled.</p>
    </div>
</article>

Family analogy: The child selector is like referring only to "the children of David and Sarah" - it includes only the direct children, not grandchildren or further descendants.

Adjacent Sibling Selector (+)

Selects an element that is directly after another specific element, when both share the same parent.

/* Targets paragraphs immediately following headings */
h2 + p {
    font-size: 1.2em;
    font-weight: bold;
}

/* Targets divs immediately following a figure */
figure + div {
    margin-top: 1rem;
}

HTML structure:

<article>
    <h2>Section Title</h2>
    <p>This paragraph immediately follows h2 and WILL be styled.</p>
    <p>This second paragraph will NOT be styled.</p>
</article>

Sibling analogy: This is like referring to "the person sitting immediately to the right of John" at a dinner table. It targets exactly one element that comes right after the reference element.

General Sibling Selector (~)

Selects elements that follow another specific element and share the same parent.

/* Targets all paragraphs that follow an h2 */
h2 ~ p {
    margin-left: 1rem;
}

/* Targets all list items after a highlighted item */
li.highlighted ~ li {
    color: #777;
}

HTML structure:

<article>
    <h2>Section Title</h2>
    <p>This paragraph follows h2 and WILL be styled.</p>
    <div>Some other content</div>
    <p>This paragraph also follows h2 and WILL be styled.</p>
</article>

Sibling analogy: This is like referring to "everyone sitting to the right of John" at a dinner table. It targets all appropriate elements that come after the reference element, no matter how many other elements are in between.

Real-World Applications of Combinators

Pseudo-Classes

Pseudo-classes select elements based on states, positions, or conditions that aren't explicitly defined in the HTML. They start with a colon (:).

State-Based Pseudo-Classes

/* Link states */
a:link {
    color: blue;
}
a:visited {
    color: purple;
}
a:hover {
    color: red;
    text-decoration: none;
}
a:active {
    color: orange;
}

Common user interaction pseudo-classes:

Form-Related Pseudo-Classes

/* Style all required form fields */
input:required {
    border-left: 4px solid red;
}

/* Style fields with validation errors */
input:invalid {
    background-color: #ffdddd;
}

/* Style fields with valid input */
input:valid {
    background-color: #ddffdd;
}

Structural Pseudo-Classes

These select elements based on their position within a parent.

/* First child element */
li:first-child {
    font-weight: bold;
}

/* Last child element */
li:last-child {
    border-bottom: none;
}

/* Every odd-numbered child */
tr:nth-child(odd) {
    background-color: #f2f2f2;
}

/* Every even-numbered child */
tr:nth-child(even) {
    background-color: #fff;
}

/* Specific positions */
li:nth-child(3) {
    color: red; /* Only the 3rd list item */
}

/* Patterns using formulas like (an+b) */
li:nth-child(3n+1) {
    /* Selects 1st, 4th, 7th... items */
    font-weight: bold;
}

Type-Based Structural Pseudo-Classes

Similar to the above, but counting only elements of the specified type.

/* First paragraph in its parent */
p:first-of-type {
    font-size: 1.2em;
}

/* Last heading in its parent */
h2:last-of-type {
    margin-bottom: 2rem;
}

/* Every other paragraph */
p:nth-of-type(odd) {
    background-color: #f9f9f9;
}

Negation Pseudo-Class

The :not() pseudo-class selects all elements that do not match the selector provided as an argument.

/* All inputs except submit buttons */
input:not([type="submit"]) {
    border: 1px solid #ddd;
}

/* All paragraphs except those with class "note" */
p:not(.note) {
    color: #333;
}

/* All list items except the first one */
li:not(:first-child) {
    border-top: 1px solid #eee;
}

Real-world application: The negation pseudo-class is particularly useful for creating exceptions to general rules. For example, a news website might style all articles similarly but want to exclude featured articles: article:not(.featured).

Other Useful Pseudo-Classes

Real-world analogies:

Pseudo-classes are like applying roles or conditions to people that aren't permanent traits:

Pseudo-Elements

Pseudo-elements allow you to style specific parts of an element. They start with a double colon (::) in modern CSS, though a single colon also works for backward compatibility.

Common Pseudo-Elements

::before and ::after

Creates a pseudo-element that is the first/last child of the selected element. Often used with the content property to insert generated content.

/* Add quotation marks around blockquotes */
blockquote::before {
    content: """;
    font-size: 3em;
    color: #ccc;
    position: absolute;
    left: -0.5em;
}
blockquote::after {
    content: """;
    font-size: 3em;
    color: #ccc;
    position: absolute;
    right: -0.5em;
}

/* Add icons before links */
a.external::before {
    content: "🔗 ";
}
a.download::before {
    content: "📥 ";
}
::first-letter and ::first-line

Styles the first letter or first line of a block-level element.

/* Create a drop cap effect */
p.intro::first-letter {
    font-size: 3em;
    font-weight: bold;
    float: left;
    margin-right: 0.1em;
    line-height: 0.8;
}

/* Emphasize the first line of a paragraph */
p::first-line {
    font-weight: bold;
    color: #555;
}
::selection

Styles the portion of an element that is selected by the user.

/* Custom text selection color */
::selection {
    background-color: #ffb7b7;
    color: #333;
}
::placeholder

Styles the placeholder text of form elements.

input::placeholder {
    color: #aaa;
    font-style: italic;
}

Creative Uses for Pseudo-Elements

Decorative Elements
/* Add a ribbon banner to a heading */
h2.ribbon {
    position: relative;
    padding: 0.5em 1em;
}
h2.ribbon::before {
    content: "";
    position: absolute;
    top: 0;
    left: -10px;
    width: 10px;
    height: 100%;
    background-color: #a00;
    border-top-left-radius: 5px;
    border-bottom-left-radius: 5px;
}
Tooltip Effects
/* Create a custom tooltip */
.tooltip {
    position: relative;
    cursor: help;
}
.tooltip::after {
    content: attr(data-tooltip);
    position: absolute;
    bottom: 125%;
    left: 50%;
    transform: translateX(-50%);
    padding: 0.5em;
    background-color: #333;
    color: white;
    border-radius: 4px;
    white-space: nowrap;
    visibility: hidden;
    opacity: 0;
    transition: opacity 0.3s;
}
.tooltip:hover::after {
    visibility: visible;
    opacity: 1;
}

Corresponding HTML:

<span class="tooltip" data-tooltip="This is helpful information">?</span>
Custom Counters
/* Auto-numbering sections */
body {
    counter-reset: section;
}
h2 {
    counter-increment: section;
}
h2::before {
    content: "Section " counter(section) ": ";
    font-weight: normal;
    color: #555;
}

Real-world analogy: Pseudo-elements are like accessories or decorations that you add to a basic outfit. The outfit (HTML element) exists on its own, but you can add a scarf (::before) and a hat (::after) to enhance it without changing the fundamental clothing.

Combining Selectors

You can combine multiple selectors to create more precise targeting. This is like using multiple filters simultaneously to narrow down exactly what you want.

Selector Lists (Grouping)

Apply the same styles to multiple selectors by separating them with commas.

/* Apply the same styles to multiple headings */
h1, h2, h3 {
    font-family: 'Georgia', serif;
    color: #333;
}

/* Group elements with similar styling needs */
.error, .warning, .alert {
    padding: 10px;
    border-radius: 4px;
    margin-bottom: 1rem;
}

Compound Selectors (Chaining)

Combine multiple selectors without separation to target elements that match ALL the selectors.

/* Target paragraphs with a specific class */
p.intro {
    font-size: 1.2em;
    font-weight: bold;
}

/* Target specific inputs */
input.error[type="text"] {
    border-color: red;
    background-color: #fff0f0;
}

This targets only elements that match ALL conditions - elements that are paragraphs AND have the class "intro".

Descendant and Child Combinations

/* Style list items differently in navigation */
nav ul li {
    display: inline-block;
}

/* Style only direct children of a specific section */
.features > h3 {
    color: #0066cc;
}

Complex Selector Examples

/* Target hovered links within the navigation */
nav a:hover {
    background-color: #f0f0f0;
}

/* Target checked radio buttons with a specific class */
input[type="radio"].preference:checked {
    outline: 2px solid blue;
}

/* Target the first paragraph after each heading in an article */
article h2 + p {
    font-size: 1.1em;
    font-weight: 500;
}

/* Target all paragraphs except the first one */
p:not(:first-of-type) {
    margin-top: 1em;
}

Real-World Use Cases

Form Styling
/* Style required inputs */
form input:required {
    border-left: 4px solid #cc0000;
}

/* Style invalid inputs that have been interacted with */
input:invalid:not(:focus):not(:placeholder-shown) {
    background-color: #fff0f0;
    border-color: #ff0000;
}

/* Style the labels of checked checkboxes */
input[type="checkbox"]:checked + label {
    font-weight: bold;
}
Navigation Styling
/* Style the active navigation item */
nav .active {
    background-color: #333;
    color: white;
}

/* Style dropdown menu items on hover */
nav li:hover > ul {
    display: block;
}
nav li:hover > a {
    background-color: #f0f0f0;
}
Content Layout
/* Style alternating rows */
.stripe-list li:nth-child(odd) {
    background-color: #f9f9f9;
}

/* Style the first paragraph of each section */
section > p:first-of-type {
    font-size: 1.1em;
}

Real-world analogy: Combining selectors is like law enforcement using multiple criteria to identify a specific person - "we're looking for someone who is tall AND has brown hair AND is wearing a blue shirt AND driving a red car." Each additional criterion narrows down the matches until you've precisely targeted exactly what you want.

Understanding CSS Specificity

Specificity is how browsers decide which CSS rules to apply when multiple rules could affect the same element. When styles conflict, the more specific selector wins.

The Specificity Hierarchy

Specificity is calculated as a four-part value (a,b,c,d), where:

  1. a: Inline styles (highest priority)
  2. b: Number of ID selectors
  3. c: Number of class selectors, attribute selectors, and pseudo-classes
  4. d: Number of element selectors and pseudo-elements

Calculating Specificity

Let's look at some examples:

/* Specificity: 0,0,0,1 */
p {
    color: black;
}

/* Specificity: 0,0,1,0 */
.text {
    color: red;
}

/* Specificity: 0,1,0,0 */
#header {
    color: blue;
}

/* Specificity: 1,0,0,0 */
<p style="color: green;">Inline style</p>

/* Specificity: 0,0,1,1 */
p.text {
    color: purple;
}

/* Specificity: 0,1,0,1 */
#sidebar h2 {
    color: yellow;
}

/* Specificity: 0,0,2,1 */
.main .title span {
    color: orange;
}

Specificity Battle Examples

When multiple rules target the same element, the one with higher specificity wins:

<p class="text" id="unique">What color will I be?</p>

/* These rules all target the paragraph */
p { color: black; }                 /* 0,0,0,1 */
.text { color: red; }               /* 0,0,1,0 */
p.text { color: purple; }           /* 0,0,1,1 */
#unique { color: blue; }            /* 0,1,0,0 */
body #unique { color: green; }      /* 0,1,0,1 */

/* The paragraph will be green because body #unique has the highest specificity */

The !important Exception

The !important flag overrides normal specificity rules. It should be used sparingly as it disrupts the natural cascade.

p {
    color: red !important; /* This will override even higher specificity */
}

#unique {
    color: blue; /* This would normally win due to higher specificity */
}

With the !important flag, the paragraph would be red despite the ID selector having higher specificity.

Real-World Analogy: The Authority Hierarchy

Think of specificity like a hierarchy of authority in an organization:

Specificity Challenges and Best Practices

Common Specificity Problems
Specificity Best Practices
Analyzing Specificity: A Real Example
<nav id="main-nav">
    <ul class="menu">
        <li class="menu-item current">
            <a href="/">Home</a>
        </li>
    </ul>
</nav>

/* Different ways to target the link, from least to most specific */
a { color: blue; }                                /* 0,0,0,1 */
.menu a { color: red; }                           /* 0,0,1,1 */
.menu-item a { color: green; }                    /* 0,0,1,1 */
.menu-item.current a { color: purple; }           /* 0,0,2,1 */
nav a { color: yellow; }                          /* 0,0,0,2 */
#main-nav a { color: orange; }                    /* 0,1,0,1 */
#main-nav .menu-item.current a { color: black; }  /* 0,1,2,1 */

In this example, the link will be black because #main-nav .menu-item.current a has the highest specificity (0,1,2,1).

Organizing CSS with Specificity in Mind

Understanding specificity helps you organize your CSS for maintainability and scalability.

The Inverted Triangle CSS Architecture (ITCSS)

ITCSS organizes CSS by ascending specificity and scope:

  1. Settings: Variables and configuration (no actual CSS output)
  2. Tools: Mixins and functions (no actual CSS output)
  3. Generic: Reset/normalize styles, box-sizing (very low specificity)
  4. Elements: Bare element selectors (low specificity)
  5. Objects: Class-based structural patterns (medium specificity)
  6. Components: Specific UI components (medium-high specificity)
  7. Utilities: Helper classes with focused purpose, often with !important (highest specificity)

BEM (Block Element Modifier) Naming Convention

BEM is a naming convention that helps manage specificity by keeping it consistently low while making selectors meaningful:

/* BEM example */
.card { }                     /* Block */
.card__image { }              /* Element (part of a card) */
.card__title { }              /* Element */
.card__button { }             /* Element */
.card--featured { }           /* Modifier (variant of card) */
.card__button--primary { }    /* Modifier (variant of button) */

BEM keeps specificity consistent (typically 0,0,1,0 for each selector) while providing clear structure.

Practical Organization Example

/* styles/main.css */

/* 1. Generic/Reset - lowest specificity */
* {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

/* 2. Element defaults - low specificity */
body {
    font-family: 'Roboto', sans-serif;
    line-height: 1.6;
    color: #333;
}

h1, h2, h3 {
    margin-bottom: 0.5em;
}

a {
    color: #0066cc;
    text-decoration: none;
}

/* 3. Layout objects - medium specificity */
.container {
    max-width: 1200px;
    margin: 0 auto;
    padding: 0 15px;
}

.grid {
    display: grid;
    gap: 20px;
}

/* 4. Components - medium-high specificity */
.card {
    border: 1px solid #ddd;
    border-radius: 4px;
    padding: 1rem;
}

.card__title {
    font-size: 1.25rem;
    margin-bottom: 0.5rem;
}

.card__image {
    width: 100%;
    height: auto;
}

.button {
    display: inline-block;
    padding: 0.5rem 1rem;
    background-color: #0066cc;
    color: white;
    border-radius: 4px;
}

.button--secondary {
    background-color: #777;
}

/* 5. Utilities - highest specificity */
.text-center {
    text-align: center !important;
}

.mt-1 {
    margin-top: 1rem !important;
}

.hidden {
    display: none !important;
}

Real-world application: Large projects like Bootstrap, Foundation, and Tailwind CSS use carefully managed specificity systems. Bootstrap uses a mix of element and class selectors with moderate specificity, while Tailwind uses utility classes exclusively, each with the same low level of specificity.

Practical Selector and Specificity Challenges

Let's explore some common real-world challenges and how to solve them with the right selectors and specificity management.

Challenge 1: Styling Links Differently in Different Contexts

/* Base styles for all links */
a {
    color: #0066cc;
    text-decoration: none;
}

/* Navigation links */
.main-nav a {
    color: #333;
    font-weight: 500;
}

/* Footer links */
.footer a {
    color: #fff;
    text-decoration: underline;
}

/* Special case for CTA links */
.cta-link {
    display: inline-block;
    padding: 0.5em 1em;
    background-color: #ff6600;
    color: white;
    border-radius: 4px;
    font-weight: bold;
}

Challenge 2: Handling Third-Party Widgets

Sometimes you need to override styles from third-party components like social media widgets or embedded forms.

/* Targeting a specific third-party widget */
.twitter-feed .tweet {
    border: none !important;
    box-shadow: 0 2px 5px rgba(0,0,0,0.1);
    padding: 1rem !important;
}

/* Creating a scoped environment to prevent conflicts */
.my-custom-form .form-control {
    /* These styles only affect .form-control within .my-custom-form */
    border: 1px solid #ddd;
    padding: 0.5rem;
    border-radius: 4px;
}

Challenge 3: Creating a Modular Component System

Building a system where components can be nested without specificity conflicts.

/* Card component */
.card {
    border: 1px solid #ddd;
    border-radius: 4px;
    padding: 1rem;
}

/* Alert component that might appear inside or outside a card */
.alert {
    padding: 0.75rem;
    border-radius: 4px;
    margin-bottom: 1rem;
}

.alert--warning {
    background-color: #fff3cd;
    border: 1px solid #ffecb5;
}

/* Both components can exist independently or be nested
without specificity issues because we use classes with
consistent specificity levels */

Challenge 4: Styling Form Elements Consistently

/* Base styles for all inputs */
input, select, textarea {
    border: 1px solid #ddd;
    padding: 0.5rem;
    border-radius: 4px;
    font-family: inherit;
    font-size: 1rem;
}

/* Styles for specific input types */
input[type="checkbox"], input[type="radio"] {
    width: auto;
    margin-right: 0.5rem;
}

/* State-based styling */
input:focus, select:focus, textarea:focus {
    border-color: #0066cc;
    outline: none;
    box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.2);
}

/* Feedback states */
.input-valid {
    border-color: #28a745 !important;
}

.input-invalid {
    border-color: #dc3545 !important;
}

Debugging Specificity Issues

Specificity problems are a common source of CSS frustration. Here's how to diagnose and solve them.

Common Specificity Problems

Using Browser Dev Tools

Browser developer tools are essential for debugging specificity issues:

  1. Right-click the element and select "Inspect" or "Inspect Element"
  2. Look at the Styles panel to see all styles affecting the element
  3. Crossed-out properties indicate overridden styles
  4. The order in the panel shows the cascade and specificity in action
  5. You can temporarily disable rules to see their impact

Solving Specificity Issues

Approach 1: Simplify Existing Selectors
/* Instead of this */
#sidebar .widget h3.widget-title {
    color: blue;
}

/* Use this */
.widget-title {
    color: blue;
}
Approach 2: Use More Specific Class Names
/* Instead of increasing selector specificity */
.sidebar .widget .title {
    color: blue;
}

/* Use a more specific class name */
.sidebar-widget-title {
    color: blue;
}
Approach 3: Apply the Styles Closer to the Element
/* When necessary, apply classes directly */
<h3 class="widget-title blue-text">Widget Title</h3>

.blue-text {
    color: blue;
}
Approach 4: Use CSS Custom Properties for Flexibility
/* Set default at a low specificity */
:root {
    --heading-color: black;
}

/* Component sets its own value */
.widget {
    --heading-color: blue;
}

/* Use the variable in your rules */
h3 {
    color: var(--heading-color);
}

This approach uses inheritance rather than specificity to manage style variations.

Hands-On Exercise: Selector Challenge

Let's apply what we've learned about selectors and specificity with a practical exercise.

Exercise Setup

Create two files:

HTML Structure

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CSS Selector Practice</title>
    <link rel="stylesheet" href="/styles/selectors_practice.css">
</head>
<body>
    <header id="main-header">
        <h1>CSS Selector Challenge</h1>
        <nav>
            <ul>
                <li><a href="#" class="active">Home</a></li>
                <li><a href="#">About</a></li>
                <li><a href="#">Services</a></li>
                <li><a href="#">Contact</a></li>
            </ul>
        </nav>
    </header>
    
    <main>
        <section class="intro">
            <h2>Welcome to the Selector Challenge</h2>
            <p>This exercise will help you practice CSS selectors and understand specificity.</p>
            <p>Try to solve each challenge using the most appropriate selectors.</p>
        </section>
        
        <section class="cards">
            <h2>Featured Cards</h2>
            <div class="card">
                <h3 class="card-title">Card One</h3>
                <p>This is the first card's content.</p>
                <a href="#" class="btn">Learn More</a>
            </div>
            <div class="card featured">
                <h3 class="card-title">Card Two</h3>
                <p>This is a featured card with special styling.</p>
                <a href="#" class="btn">Learn More</a>
            </div>
            <div class="card">
                <h3 class="card-title">Card Three</h3>
                <p>This is the third card's content.</p>
                <a href="#" class="btn">Learn More</a>
            </div>
        </section>
        
        <section class="form-section">
            <h2>Contact Form</h2>
            <form id="contact-form">
                <div class="form-group">
                    <label for="name">Name:</label>
                    <input type="text" id="name" required>
                </div>
                <div class="form-group">
                    <label for="email">Email:</label>
                    <input type="email" id="email" required>
                </div>
                <div class="form-group">
                    <label for="message">Message:</label>
                    <textarea id="message" rows="4"></textarea>
                </div>
                <div class="form-group">
                    <label>
                        <input type="checkbox" name="subscribe"> Subscribe to newsletter
                    </label>
                </div>
                <button type="submit" class="btn btn-primary">Send Message</button>
            </form>
        </section>
        
        <section class="list-section">
            <h2>Sample List</h2>
            <ul class="custom-list">
                <li>First Item</li>
                <li class="highlighted">Second Item (Highlighted)</li>
                <li>Third Item</li>
                <li>Fourth Item</li>
                <li>Fifth Item</li>
            </ul>
        </section>
    </main>
    
    <footer>
        <p>© 2025 CSS Selector Practice. All rights reserved.</p>
        <div class="footer-links">
            <a href="#">Privacy Policy</a>
            <a href="#">Terms of Service</a>
            <a href="#">Contact Us</a>
        </div>
    </footer>
</body>
</html>

CSS Challenges

In your selectors_practice.css file, implement the following styling using the most appropriate selectors:

  1. Style the body with a font-family of Arial or sans-serif, a background color of #f5f5f5, and a line-height of 1.6
  2. Make all heading elements (h1, h2, h3) use the color #333
  3. Style the main header with a dark background (#222) and white text
  4. Make the navigation links white with no underline, and add a bottom border when hovered
  5. Style the active navigation link differently (hint: it has a class)
  6. Make the first paragraph in the intro section larger and bold
  7. Style all cards with a white background, borders, and some padding
  8. Make the featured card stand out with a different border color and background
  9. Style the "Learn More" links to look like buttons
  10. Make all form inputs have consistent styling, with special focus states
  11. Style required form fields differently (hint: use attribute selectors)
  12. Create zebra-striping for the list items (alternating background colors)
  13. Make the highlighted list item stand out
  14. Style the list items to show a checkmark (✓) before each item using a pseudo-element
  15. Style the footer links to be separated by pipes (|) using pseudo-elements

Solution Approach

For each challenge, think about:

Further Resources and Next Steps

Documentation and References

Interactive Learning

CSS Architecture Patterns

Topics to Explore Next

Today's Assignment: Selector Mastery

Now it's time to apply what you've learned to a real project.

Assignment Requirements:

  1. Create a new CSS file called styles/advanced_selectors.css
  2. Create a corresponding HTML file called advanced_selectors.html
  3. Implement a styled webpage that demonstrates at least 10 different types of selectors, including:
    • At least one example of each basic selector type (element, class, ID)
    • At least two combinator selectors (descendant, child, adjacent, or general sibling)
    • At least three pseudo-classes
    • At least one pseudo-element
    • At least one attribute selector
  4. Include a section that demonstrates specificity by showing several rules that target the same element
  5. Comment your CSS to explain what each selector does and why you chose it
  6. Create a "selector key" at the bottom of your page that explains each selector's syntax

Bonus challenges:

Submit your completed assignment by pushing both your HTML and CSS files to your course repository.

Wrapping Up

Congratulations! You've now delved into one of the most important aspects of CSS - selectors and specificity. These concepts form the foundation for everything else you'll do with CSS.

Key takeaways from today's session:

As you continue your CSS journey, you'll find yourself using these concepts constantly. Mastering selectors and specificity will save you countless hours of debugging and make your stylesheets more efficient and maintainable.

In this afternoon's session, we'll explore CSS positioning, display properties, and layout techniques that build upon what we've learned today.

Any questions before we wrap up?