Video by Dr. Chuck on CSS Basics Part 1: A beginner-friendly video explaining the fundamentals of CSS.
Video by Dr. Chuck on CSS Basics Part 2: A continuation of the CSS basics, covering more advanced topics.
Video by Dr. Chuck on CSS Basics Part 3: The third part of the CSS basics series, focusing on practical applications.
Video by Dr. Chuck on CSS Specificity Explained: A detailed explanation of CSS specificity and how it affects style application.
w3schools HTML playground: online HTML editor to practice HTML/CSS.
jsfiddle.net: Online editor for HTML, CSS, and JavaScript with live preview.
codepen.io: Social development environment for front-end designers and developers.
replit.com: Online IDE supporting multiple programming languages, including HTML/CSS/JS.
Inline CSS (avoid except for dynamic styles):
<p style="color: blue; font-size: 16px;">Text</p>
Internal CSS:
<head>
<style>
p {
color: blue;
font-size: 16px;
}
</style>
</head>
External CSS (best practice):
<head>
<link rel="stylesheet" href="css/style.css">
</head>
/* style.css */
p {
color: blue;
font-size: 16px;
}
Try the following (admittedly badly designed) page with and without CSS: CSS Zen Garden
Without CSS, the content is still accessible, but the visual presentation is poor.
Maybe important for visual impairments?

selector {
property: value;
}
For all selectors, CSS rules apply
The property is what you want to change
Think of it as a paintbrush for HTML elements
Element Selector:
p {
color: black;
}
h1 {
font-size: 32px;
}
Class Selector:
.highlight {
background-color: yellow;
}
.btn {
padding: 10px 20px;
border-radius: 5px;
}
<p class="highlight">Highlighted text</p>
<button class="btn">Click Me</button>
ID Selector:
#header {
background-color: navy;
}
#main-content {
padding: 20px;
}
<div id="header">Header Content</div>
<div id="main-content">Main Content</div>
Universal Selector:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
Multiple sources of styles: browser defaults, user styles, author styles
Specificity hierarchy: inline > ID > class > element
Concept: The more specific the selector, the higher its priority
Concept: Later rules override earlier ones if they have the same specificity
<div>: Block-level container for grouping elements<span>: Inline container for grouping text or elements<div class="container">
<h1>Title</h1>
<p>This is a <span class="highlight">highlighted</span> word.</p>
</div>
spand and div are often used together with CSS to style specific parts of a webpage.
Concept: span and div have no inherent visual effect; they are designed to be styled with CSS.
Concept: this is so because other older elements had specific meanings and visual effects (like <b>, <i>, <u>, etc.)
# means ID selector. Find element with that ID.
. means class selector. Find all elements with that class.
No prefix means element selector. Find all elements of that type.
Explanation of CSS Specificity: A video explaining how CSS specificity works.
Example of specificity:
/* Element selector */
p {
color: black; /* specificity: 1 */
}
/* Class selector */
.highlight {
color: blue; /* specificity: 10 */
}
/* ID selector */
#main {
color: red; /* specificity: 100 */
}
red, blue, green, etc.#RRGGBB or #RGBrgb(255, 0, 0)rgba(255, 0, 0, 0.5) (with alpha for transparency)hsl(0, 100%, 50%)hsla(0, 100%, 50%, 0.5) (with alpha for transparency)/* Named color */
color: red;
/* Hexadecimal */
color: #FF0000;
/* RGB */
color: rgb(255, 0, 0);
/* RGBA */
color: rgba(255, 0, 0, 0.5);
/* HSL */
color: hsl(0, 100%, 50%);
/* HSLA */
color: hsla(0, 100%, 50%, 0.5);
font-family: Specifies the font type.font-size: Specifies the size of the font.font-weight: Specifies the weight (boldness) of the font.font-style: Specifies the style (normal, italic, oblique) of the font./* Font family */
font-family: Arial, Helvetica, sans-serif;
font-family: 'Times New Roman', serif;
font-family: 'Courier New', monospace;
/* Font size */
font-size: 16px;
font-size: 1.2em; /* relative to parent */
font-size: 1.2rem; /* relative to root */
/* Font weight */
font-weight: normal;
font-weight: bold;
font-weight: 700;
/* Font style */
font-style: italic;
font-style: oblique;
/* Shorthand */
font: italic bold 16px/1.5 Arial, sans-serif;
body {
font-family: 'Roboto', sans-serif;
}
font-family: 'Open Sans', Arial, sans-serif;
/* Link states */
a:link { color: blue; }
a:visited { color: purple; }
a:hover { color: red; }
a:active { color: orange; }
<nav> tag is to define a section of navigation links in an HTML document.nav a {
text-decoration: none;
padding: 10px 15px;
color: white;
background-color: #333;
}
nav a:hover {
background-color: #555;
}
em, rem, %, pxpx: Pixels, absolute unit.em: Relative to the font-size of the parent element.rem: Relative to the font-size of the root element (<html>).%: Relative to the parent element’s size./* Pixels (most common) */
font-size: 16px;
/* em - relative to parent font-size */
font-size: 1.5em; /* 1.5 times parent */
/* rem - relative to root (html) font-size */
font-size: 1.5rem;
/* Percentage */
width: 50%;
font-size: 120%;
/* Viewport units */
width: 50vw; /* 50% of viewport width */
height: 100vh; /* 100% of viewport height */
font-size: 5vmin; /* 5% of smaller dimension */
What if we styled a page without CSS?
Video by Dr. Chuck on Styling without CSS: A video demonstrating the drawbacks of styling a webpage without CSS.
<!DOCTYPE html>
<html>
<head>
<title>Styled Page without CSS</title>
</head>
<body>
<h1><font color="blue" size="7">Welcome to My Page</font></h1>
<p><font color="green" size="4">This is a paragraph with inline font styling.</font></p>
<a href="#" style="color: red; font-size: 20px;">This is a styled link</a>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>Styled Page with CSS</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h1 class="title">Welcome to My Page</h1>
<p class="paragraph">This is a paragraph with CSS styling.</p>
<a href="#" class="styled-link">This is a styled link</a>
</body>
</html>
/* styles.css */
.title {
color: blue;
font-size: 3em;
}
.paragraph {
color: green;
font-size: 1.5em;
}
.styled-link {
color: red;
font-size: 1.25em;
}
Use the following tools to practice CSS:
CSS Diner: An interactive game to learn CSS selectors.
CSS Battle: A platform to practice CSS by replicating target designs with minimal code.
Use the playgrounds mentioned earlier (JSFiddle, CodePen, Replit) to experiment with CSS code snippets (see above).
w3schools HTML playground: online HTML editor to practice HTML/CSS.
jsfiddle.net: Online editor for HTML, CSS, and JavaScript with live preview.
codepen.io: Social development environment for front-end designers and developers.
replit.com: Online IDE supporting multiple programming languages, including HTML/CSS/JS.
Code to practice:
Let us try this without CSS first:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CSS Practice</title>
/* No CSS yet */
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header id="main-header">
<h1 class="title">Welcome to CSS Practice</h1>
</header>
<main>
<section class="content">
<h2>Section Title</h2>
<p>This is a paragraph to practice CSS styling.</p>
<a href="#" class="link">This is a link</a>
</section>
</main>
<footer id="main-footer">
<p>© 2024 CSS Practice</p>
</footer>
</body>
</html>
Here is a detailed breakdown of this HTML practical:
<html lang="en">
The lang="en" attribute specifies English as the document’s language. This helps screen readers pronounce content correctly and assists search engines with language-specific indexing.
<meta charset="UTF-8">
UTF-8 encoding supports all international characters and symbols. Without this, special characters might display as garbled text. Always include this as the first element in <head>.
<meta name="viewport" content="width=device-width, initial-scale=1.0">
This is crucial for responsive design. It tells mobile browsers to set the page width to match the device’s screen width rather than defaulting to a desktop viewport (typically 980px). The initial-scale=1.0 sets the initial zoom level to 100%.
<link rel="stylesheet" href="styles.css">
This links an external CSS file. The rel="stylesheet" attribute defines the relationship between the HTML and the linked file. External stylesheets are preferred because they separate content from presentation and allow multiple pages to share styles.
<header id="main-header">
The semantic <header> element indicates introductory content. The id="main-header" provides a unique identifier, useful for:
#main-header { ... })<h1 class="title">Welcome to CSS Practice</h1>
The class="title" allows CSS styling via .title { ... }.
Concept: Unlike IDs, classes can be reused multiple times on a page, making them ideal for styling patterns that repeat.
<main>
The <main> element represents the dominant content of the page. There should be only one <main> per page, and it shouldn’t be nested inside <article>, <aside>, <footer>, <header>, or <nav> elements.
<section class="content">
The <section> element groups related content thematically. It typically includes a heading. The class="content" allows for styling and could be reused if you have multiple content sections.
<a href="#" class="link">This is a link</a>
The href="#" creates a placeholder link that goes nowhere (useful in prototypes). In production, this would contain an actual URL. The class="link" allows custom link styling beyond default browser styles.
<footer id="main-footer">
<p>© 2026 CSS Practice</p>
</footer>
The <footer> element contains concluding information. The © is an HTML entity that renders as ©. Using entities ensures special characters display correctly across all browsers.
Semantic HTML: This code uses meaningful tags (<header>, <main>, <section>, <footer>) instead of generic <div> elements. This improves accessibility, SEO, and code readability.
IDs vs Classes: IDs (#) are unique identifiers for styling or JavaScript; classes (.) are reusable styling hooks. Use IDs sparingly and classes frequently.
Separation of Concerns: HTML handles structure, CSS (in the external file) handles presentation. This makes maintenance easier and improves performance through caching.
Accessibility Foundation: Proper semantic markup and language attributes create a foundation for screen readers and assistive technologies.
styles.css and add the following styles:/* styles.css */
/* Basic Element Selector */
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
background-color: #f4f4f4;
}
/* ID Selector */
header#main-header {
background-color: #333;
color: white;
padding: 10px 0;
text-align: center;
}
/* Class Selector */
h1.title {
font-size: 2.5em;
}
section.content {
padding: 20px;
}
/* Link Styling */
a.link {
color: blue;
text-decoration: none;
}
/* Link Hover Effect */
a.link:hover {
text-decoration: underline;
background-color: gray;
}
/* Footer Styling */
footer#main-footer {
background-color: #333;
color: white;
text-align: center;
padding: 10px 0;
position: fixed;
width: 100%;
bottom: 0;
}
body selector styles the entire page with a font, margin, padding, and background color.header#main-header selector styles the header with a background color, text color, padding, and center alignment.h1.title selector increases the font size of the main title.section.content selector adds padding to the content section.a.link selector styles links with color and removes underlines.a.link:hover selector adds an underline on hover for better interactivity.footer#main-footer selector styles the footer similarly to the header and fixes it to the bottom of the viewport.body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
background-color: #f4f4f4;
}
What it does: Targets every <body> element (there is only one per page).
Key Properties Explained:
font-family: Arial, sans-serif; — Sets the default font for the entire page. Arial is tried first; if unavailable, the browser uses its default sans-serif font. This is called a “font stack.”
margin: 0; padding: 0; — Removes default browser spacing around the body. Browsers add their own margins/padding, so this “CSS reset” technique gives you a clean starting point.
background-color: #f4f4f4; — Sets a light gray background. The # indicates a hexadecimal color code (RGB values in hex format).
Teaching Point: Element selectors have low specificity and apply broadly. Properties set here cascade down to child elements unless overridden.
header#main-header {
background-color: #333;
color: white;
padding: 10px 0;
text-align: center;
}
Selector Syntax: header#main-header combines an element selector with an ID selector. This targets a <header> element that has id="main-header".
Note for Students: You could write just #main-header since IDs are unique, but specifying header#main-header makes the code more readable and slightly increases specificity.
Properties Explained:
background-color: #333; — Dark gray (almost black) background. #333 is shorthand for #333333.
color: white; — Sets text color to white. You can use color names, hex codes, RGB, or HSL values.
padding: 10px 0; — Adds 10 pixels of space inside the element on top and bottom, 0 on left and right. Format is top/bottom left/right.
text-align: center; — Centers all inline content (text, inline elements) horizontally.
Teaching Point: IDs have high specificity, making them powerful but potentially problematic if overused. Better to use classes for styling.
h1.title {
font-size: 2.5em;
}
Selector Syntax: h1.title targets <h1> elements with class="title". Like the ID example, this is more specific than just .title.
Property Explained:
font-size: 2.5em; — Sets font size to 2.5 times the inherited font size.em units are relative to the parent element’s font size. If the body font is 16px (browser default), this heading becomes 40px (16 × 2.5).Teaching Point: Relative units (em, rem, %) are better for responsive design than fixed units (px). rem units are relative to the root (<html>) element, while em units compound with nesting.
Exercise: Move the code block to above the ID selector and see how specificity affects the applied styles! What do you think will happen?
Question: Why does the class selector win over the ID selector?
Answer:
Great question! Now let me explain what’s actually happening with this cleaner version of your CSS.
The class selector does NOT “win over” the ID selector. They’re not competing at all because they target different elements!
<header id="main-header">
<h1 class="title">Welcome to HTML!</h1>
</header>
header#main-header → Targets the <header> elementh1.title → Targets the <h1> element (which is INSIDE the header)<header> element gets:header#main-header {
background-color: #333333; /* ← Applied to header */
color: red; /* ← Applied to header */
padding: 10px 0; /* ← Applied to header */
text-align: center; /* ← Applied to header */
}
<h1> element gets:h1.title {
font-size: 1em; /* ← Applied to h1 */
color: green; /* ← Applied to h1 */
}
<h1> Green and Not Red?This is about inheritance vs. direct styling:
<header> gets color: red applied to it<h1> would inherit the red color from its parent headerh1.title rule directly targets the <h1> with color: green┌─────────────────────────────────┐
│ header#main-header │
│ color: red (applied directly) │
│ │
│ ┌─────────────────────────┐ │
│ │ h1.title │ │
│ │ color: green │ │ ← Direct style WINS
│ │ (applied directly) │ │ over inherited red
│ └─────────────────────────┘ │
└─────────────────────────────────┘
Let me be very clear:
“The class selector (.title) beats the ID selector (#main-header)”
“The h1 has its own direct style that overrides what it would inherit from its parent”
Specificity would matter in this scenario:
/* Both target the SAME <h1> element */
h1.title {
color: green; /* Specificity: 0,0,1,1 */
}
header#main-header h1 {
color: blue; /* Specificity: 0,1,0,2 - WINS! */
}
/* Result: h1 would be BLUE (higher specificity) */
In this case, the second rule wins because:
<h1> element0,1,0,2 (1 ID + 1 element + 1 element) beats 0,0,1,1 (1 class + 1 element)When multiple styles could apply, CSS uses this order:
In your case:
h1.title { color: green } is a direct style on the <h1>header#main-header { color: red } would be inherited by the <h1>What you’re seeing in the browser:
┌──────────────────────────────────────┐
│ HEADER (dark background, red text) │ ← header#main-header styles
│ │
│ Welcome to HTML! (green, small) │ ← h1.title styles (direct)
│ │
└──────────────────────────────────────┘
If you removed the h1.title rule, THEN the h1 would inherit red:
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
background-color: #f4f4f4;
}
header#main-header{
background-color: #333333;
color: red;
padding: 10px 0;
text-align: center;
}
/* No h1.title rule anymore */
Now the h1 would be red because it would inherit from the header.
| What You Might Think | What’s Actually Happening |
|---|---|
| “Class beats ID” | No! They target different elements |
| “Lower specificity wins” | No! Direct styling beats inheritance |
| “There’s a conflict” | No! Each element gets its own styles |
The real rule: When an element has a direct style AND would inherit a style for the same property, the direct style always wins, regardless of the specificity of the parent’s rule.
Remove the color: green from h1.title:
h1.title {
font-size: 1em;
/* color: green ← Comment this out */
}
What happens? The h1 will now be red because it inherits from header#main-header.
Then add it back:
h1.title {
font-size: 1em;
color: green; /* ← Uncomment */
}
What happens? The h1 is green again because the direct style overrides the inherited red.
Specificity is CSS’s way of deciding which rule wins when multiple rules target the exact same element and set the same property.
Think of it as a scoring system where each type of selector gets points, and the rule with the highest score wins.
Specificity is calculated as a four-part number: a,b,c,d
| Position | What It Counts | Points | Example |
|---|---|---|---|
| a | Inline styles | 1,0,0,0 | <h1 style="color: red;"> |
| b | IDs | 0,1,0,0 | #main-header |
| c | Classes, attributes, pseudo-classes | 0,0,1,0 | .title, [type="text"], :hover |
| d | Elements, pseudo-elements | 0,0,0,1 | h1, div, ::before |
Higher numbers in earlier positions always win, like reading a number from left to right.
Let us analyze both selectors step-by-step:
h1.titleh1.title {
color: green;
}
What’s in this selector?
h1 → 1 element.title → 1 classSpecificity calculation:
.title)h1)Total: 0,0,1,1
header#main-header h1header#main-header h1 {
color: blue;
}
What’s in this selector?
header → 1 element#main-header → 1 IDh1 → 1 elementSpecificity calculation:
#main-header)header + h1)Total: 0,1,0,2
0,1,0,2 Beat 0,0,1,1?Compare the numbers position by position, from left to right:
a b c d
↓ ↓ ↓ ↓
1: 0, 0, 1, 1 (h1.title)
2: 0, 1, 0, 2 (header#main-header h1)
↑ ↑
│ │
│ └─ Position b: 1 > 0 — Selector 2 WINS!
│
└─ Position a: 0 = 0 (tie, move to next position)
The comparison stops at position b because we found a difference:
The remaining positions (c and d) don’t even matter once we find a difference in an earlier position.
Think of specificity like money in different currencies:
Position a (Inline) = $1,000,000
Position b (IDs) = $1,000
Position c (Classes) = $1
Position d (Elements) = $0.01
One ID ($1,000) is worth more than 1,000 classes ($1 each)!
/* 11 classes = 0,0,11,0 */
.a.b.c.d.e.f.g.h.i.j.k {
color: red;
}
/* 1 ID beats all those classes! = 0,1,0,0 */
#main-header {
color: blue; /* ← WINS! */
}
Even though the first rule has 11 classes, the second rule wins because 1 ID beats any number of classes.
<header id="main-header">
<h1 class="title">Welcome to HTML!</h1>
</header>
/* Selector 1: Specificity 0,0,1,1 */
h1.title {
color: green;
}
/* Selector 2: Specificity 0,1,0,2 */
header#main-header h1 {
color: blue;
}
<h1> elementcolorh1.title = 0,0,1,1header#main-header h1 = 0,1,0,2color: blueResult: The <h1> text is blue, not green!
/* Specificity: 0,0,0,3 (3 elements) */
header main h1 {
color: red;
}
/* Specificity: 0,0,1,0 (1 class) - WINS! */
.title {
color: blue;
}
Winner: .title (blue) — 1 class beats any number of elements
/* Specificity: 0,0,5,0 (5 classes) */
.a.b.c.d.e {
color: red;
}
/* Specificity: 0,1,0,0 (1 ID) - WINS! */
#main-header {
color: blue;
}
Winner: #main-header (blue) — 1 ID beats any number of classes
/* Specificity: 0,0,1,1 (1 class + 1 element) */
h1.title {
color: green;
}
/* Specificity: 0,0,2,1 (2 classes + 1 element) - WINS! */
h1.title.main {
color: blue;
}
/* Specificity: 0,1,0,0 (1 ID) - WINS OVER ALL! */
#heading {
color: red;
}
Winner: #heading (red) — The ID beats everything else
When two rules have exactly the same specificity, the last one in the CSS file wins (this is the “cascade” part of CSS):
/* Both have specificity: 0,0,1,0 */
.title {
color: green; /* Defined first */
}
.title {
color: blue; /* Defined last - WINS! */
}
Result: Blue text (last rule wins when specificity is tied)
/* This is NOT specificity 0,0,1,1 */
/* It's 0,1,0,2 because you count EVERY part */
header#main-header h1 {
color: blue;
}
header = 1 element#main-header = 1 IDh1 = 1 element* Has Zero Specificity/* Specificity: 0,0,0,0 */
* {
color: red;
}
/* Specificity: 0,0,0,1 - WINS! */
p {
color: blue;
}
/* The >, +, ~, and space combinators add ZERO specificity */
/* Specificity: 0,0,0,2 (just 2 elements) */
header > h1 {
color: blue;
}
!important ExceptionThere’s one thing that overrides specificity: !important
/* Specificity: 0,0,1,1 */
h1.title {
color: green !important; /* ← WINS despite lower specificity! */
}
/* Specificity: 0,1,0,2 (higher!) */
header#main-header h1 {
color: blue;
}
Result: Green text (because of !important)
⚠️ Warning: Avoid using !important unless absolutely necessary. It makes CSS very hard to maintain because it breaks the normal specificity rules.
/* Good: Low specificity, easy to override */
.title {
color: blue;
}
/* Bad: High specificity, hard to override */
body header#main-header div.container h1.title {
color: blue;
}
<!-- Bad: Highest specificity, hard to override -->
<h1 style="color: red;">Title</h1>
<!-- Good: Use classes instead -->
<h1 class="title">Title</h1>
Open Chrome/Firefox DevTools (F12) → Inspect element → See which rules are being applied and which are crossed out due to lower specificity
Specificity is calculated as: (inline, IDs, classes, elements)
Your example:
h1.title = 0,0,1,1 (1 class, 1 element)header#main-header h1 = 0,1,0,2 (1 ID, 2 elements)Winner: header#main-header h1 because the ID in position b makes it more specific than any combination of classes and elements.
The golden rule: Compare specificity left to right. The first position with a higher number wins, and all other positions become irrelevant.
section.content {
padding: 20px;
}
Property Explained:
padding: 20px; — Adds 20 pixels of space inside the element on all four sides. This is shorthand for padding: 20px 20px 20px 20px; (top, right, bottom, left).Box Model Connection: Padding creates space between content and border. The order is: content → padding → border → margin (moving outward).
a.link {
color: blue;
text-decoration: none;
}
Properties Explained:
color: blue; — Changes link text color from the browser default (usually blue, but varies).
text-decoration: none; — Removes the default underline from links. This is common in modern web design.
Teaching Point: Links have several states (pseudo-classes) that can be styled independently: :link, :visited, :hover, :active, :focus.
a.link:hover {
text-decoration: underline;
}
Selector Syntax: The :hover pseudo-class targets elements when the user’s cursor is over them.
What Happens: When users hover over links with class="link", the underline reappears, providing visual feedback that the element is interactive.
Teaching Point: Pseudo-classes select elements based on their state, not their position in the HTML. Common pseudo-classes include :hover, :focus, :active, :first-child, :nth-child(), and :not().
Accessibility Note: Hover effects don’t work on touchscreens. For accessibility, ensure interactive elements are still usable without hover states.
footer#main-footer {
background-color: #333;
color: white;
text-align: center;
padding: 10px 0;
position: fixed;
width: 100%;
bottom: 0;
}
New Properties:
position: fixed; — Removes the element from normal document flow and positions it relative to the viewport (browser window). It stays in place even when the page scrolls.
width: 100%; — Makes the footer span the full width of the viewport.
bottom: 0; — Anchors the footer to the bottom of the viewport. You could also use top, left, or right with fixed positioning.
Important Teaching Point: Fixed positioning has consequences:
padding-bottom to the <body> or <main> equal to the footer’s height to prevent content from being hiddenCommon Student Mistake: Forgetting that fixed elements need explicit dimensions or positioning values. Without width: 100%, this footer might not span the full width.
Understanding which styles “win” when multiple rules target the same element:
style="" attribute): 1,0,0,0Example from this file:
header#main-header has specificity 0,1,0,1 (1 ID + 1 element).content has specificity 0,0,1,0 (1 class)body has specificity 0,0,0,1 (1 element)Higher specificity wins. If specificity is equal, the last rule in the CSS file wins (the “cascade”).
Modify this CSS to:
.content for depthstatic or relative instead of fixed@media queries to change font sizes on smaller screenssection { padding: 50px; } and observe why it doesn’t override section.contentsection.content p to practice descendant selectorstransition: text-decoration 0.3s;For the corresponding styles.css file, practice:
:hover, :active on the link)Descendant Selector (space):
/* All p elements inside div */
div p {
color: blue;
}
Child Selector (>):
/* Only direct children */
div > p {
font-weight: bold;
}
Adjacent Sibling (+):
/* p immediately after h2 */
h2 + p {
margin-top: 0;
}
General Sibling (~):
/* All p elements after h2 */
h2 ~ p {
color: gray;
}
Explanations and examples of how each combinator works.
A descendant selector uses a space between two selectors to target elements that are inside (nested within) other elements, at any level of depth.
/* General pattern */
ancestor descendant {
property: value;
}
The space means: “Find all descendant elements that are somewhere inside an ancestor element.”
/* All p elements inside div */
div p {
color: blue;
}
<p> (paragraph) elements<div> element<div>
<p>This paragraph is blue!</p> ← Matches! (direct child)
</div>
<div>
<section>
<p>This paragraph is also blue!</p> ← Matches! (grandchild)
</section>
</div>
<div>
<article>
<section>
<aside>
<p>Still blue!</p> ← Matches! (great-great-grandchild)
</aside>
</section>
</article>
</div>
<div>
<p>Blue paragraph 1</p> ← Matches!
<p>Blue paragraph 2</p> ← Matches!
<section>
<p>Blue paragraph 3</p> ← Matches!
</section>
</div>
<p>This is NOT blue</p> ← Doesn't match (not inside a div)
<div>
<p>This IS blue</p> ← Matches!
</div>
<p>This is NOT blue either</p> ← Doesn't match
<section>
<p>This is NOT blue</p> ← Doesn't match (inside section, not div)
</section>
<div>
<p>This IS blue</p> ← Matches!
</div>
Here is a full HTML/CSS demonstration:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Descendant Selector Demo</title>
<style>
/* All p elements inside div */
div p {
color: blue;
font-weight: bold;
}
</style>
</head>
<body>
<h1>Descendant Selector Example</h1>
<!-- This paragraph is NOT inside a div -->
<p>I am BLACK text (default colour)</p>
<!-- These paragraphs ARE inside a div -->
<div>
<p>I am BLUE and BOLD (direct child of div)</p>
<section>
<p>I am also BLUE and BOLD (grandchild of div)</p>
</section>
<article>
<aside>
<p>Me too! BLUE and BOLD (great-grandchild of div)</p>
</aside>
</article>
</div>
<!-- This paragraph is also NOT inside a div -->
<p>I am BLACK text again</p>
<!-- Another div with paragraphs -->
<div>
<p>I am BLUE and BOLD</p>
<p>I am BLUE and BOLD</p>
</div>
</body>
</html>
/* p elements inside section elements inside article elements */
article section p {
color: green;
}
Matching HTML:
<article>
<section>
<p>I am GREEN!</p> ← Matches!
</section>
</article>
<article>
<p>I am NOT green</p> ← Doesn't match (not inside a section)
</article>
<section>
<p>I am NOT green</p> ← Doesn't match (not inside an article)
</section>
/* p elements inside elements with class "content" */
.content p {
color: purple;
line-height: 1.6;
}
Matching HTML:
<div class="content">
<p>I am PURPLE!</p> ← Matches!
<section>
<p>I am also PURPLE!</p> ← Matches!
</section>
</div>
<div class="sidebar">
<p>I am NOT purple</p> ← Doesn't match (not in .content)
</div>
<section class="content">
<p>I am PURPLE!</p> ← Matches! (class works on any element)
</section>
/* Links inside the element with id="main-header" */
#main-header a {
color: white;
text-decoration: none;
}
Matching HTML:
<header id="main-header">
<nav>
<a href="#">Home</a> ← WHITE, no underline
<a href="#">About</a> ← WHITE, no underline
</nav>
</header>
<footer>
<a href="#">Contact</a> ← Default link color (not in #main-header)
</footer>
/* Different rules for different descendants */
div p {
color: blue;
}
div h2 {
color: red;
}
div a {
color: green;
}
HTML Result:
<div>
<h2>This heading is RED</h2>
<p>This paragraph is BLUE</p>
<a href="#">This link is GREEN</a>
</div>
div p {
color: blue;
}
Matches <p> at any depth inside <div>
div > p {
color: blue;
}
Matches <p> that are direct children only
<div>
<p>Paragraph 1</p> ← Both match
<section>
<p>Paragraph 2</p> ← Only descendant selector matches
</section>
</div>
With div p (descendant): Both paragraphs are blue
With div > p (child): Only Paragraph 1 is blue
/* Style only links inside the navigation */
nav a {
color: white;
text-decoration: none;
padding: 10px 15px;
}
nav a:hover {
background-color: rgba(255, 255, 255, 0.2);
}
<nav>
<a href="#">Home</a> ← Styled
<a href="#">About</a> ← Styled
<a href="#">Contact</a> ← Styled
</nav>
<footer>
<a href="#">Privacy</a> ← NOT styled (not in nav)
</footer>
/* Style paragraphs only inside articles */
article p {
font-size: 16px;
line-height: 1.8;
margin-bottom: 15px;
}
article h2 {
color: #333;
margin-top: 30px;
}
<article>
<h2>Article Title</h2> ← Styled
<p>First paragraph...</p> ← Styled
<p>Second paragraph...</p> ← Styled
</article>
<aside>
<p>Sidebar content</p> ← NOT styled (not in article)
</aside>
/* Style only inputs inside forms */
form input {
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
}
form label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
<form>
<label>Name:</label> ← Styled
<input type="text"> ← Styled
<label>Email:</label> ← Styled
<input type="email"> ← Styled
</form>
<div>
<input type="text"> ← NOT styled (not in form)
</div>
Remember: Add up the specificity of all parts
div p {
color: blue;
}
Specificity: 0,0,0,2
div = 1 elementp = 1 element#main-header nav a {
color: white;
}
Specificity: 0,1,0,2
#main-header = 1 IDnav = 1 elementa = 1 element.content article p {
color: blue;
}
Specificity: 0,0,1,2
.content = 1 classarticle = 1 elementp = 1 element/* Wrong - this targets div elements with class "p" */
div.p {
color: blue;
}
/* Correct - this targets p elements inside div */
div p {
color: blue;
}
/* Bad - unnecessarily long and hard to override */
body main section.content article div p {
color: blue;
}
/* Good - simple and maintainable */
article p {
color: blue;
}
Rule of thumb: Keep descendant selectors as short as possible while still being specific enough.
/* Instead of this: */
div p {
color: blue;
}
/* Consider using a class for better control: */
.article-text {
color: blue;
}
For this HTML which paragraphs will be blue?
<!DOCTYPE html>
<html>
<head>
<style>
div p {
color: blue;
}
</style>
</head>
<body>
<p>Paragraph 1</p>
<div>
<p>Paragraph 2</p>
<section>
<p>Paragraph 3</p>
</section>
</div>
<section>
<p>Paragraph 4</p>
</section>
<div>
<article>
<p>Paragraph 5</p>
</article>
</div>
</body>
</html>
Answer: Paragraphs 2, 3, and 5 will be blue (all are inside <div> elements at some level).
Key Points:
/* Has attribute */
input[required] {
border: 2px solid red;
}
/* Exact value */
input[type="email"] {
background-color: lightyellow;
}
/* Contains value */
a[href*="example"] {
color: green;
}
/* Starts with */
a[href^="https"] {
padding-left: 20px;
}
/* Ends with */
a[href$=".pdf"] {
color: red;
}
/* Link states */
a:link { color: blue; }
a:visited { color: purple; }
a:hover { color: red; }
a:active { color: orange; }
/* Form states */
input:focus {
outline: 2px solid blue;
}
input:disabled {
background-color: #eee;
}
input:checked + label {
font-weight: bold;
}
/* Structural */
li:first-child {
font-weight: bold;
}
li:last-child {
border-bottom: none;
}
li:nth-child(odd) {
background-color: #f0f0f0;
}
li:nth-child(3n) {
color: red;
}
p:not(.special) {
color: gray;
}
/* First line/letter */
p::first-line {
font-weight: bold;
}
p::first-letter {
font-size: 2em;
float: left;
}
/* Before/After */
.quote::before {
content: """;
font-size: 2em;
}
.quote::after {
content: """;
font-size: 2em;
}
/* Selection */
::selection {
background-color: yellow;
color: black;
}
Color Values:
/* Named colors */
color: red;
/* Hexadecimal */
color: #FF0000;
color: #F00; /* shorthand */
/* RGB */
color: rgb(255, 0, 0);
/* RGBA (with transparency) */
color: rgba(255, 0, 0, 0.5);
/* HSL */
color: hsl(0, 100%, 50%);
/* HSLA */
color: hsla(0, 100%, 50%, 0.5);
Background Properties:
.element {
background-color: #f0f0f0;
background-image: url('bg.jpg');
background-repeat: no-repeat;
background-position: center center;
background-size: cover;
background-attachment: fixed;
/* Shorthand */
background: #f0f0f0 url('bg.jpg') no-repeat center/cover;
}
/* Multiple backgrounds */
.hero {
background:
url('overlay.png'),
url('photo.jpg');
background-size: cover, cover;
}
/* Gradients */
.gradient {
background: linear-gradient(to right, red, blue);
background: linear-gradient(45deg, red, yellow, blue);
background: radial-gradient(circle, red, blue);
}
Font Properties:
.text {
/* Font family */
font-family: Arial, Helvetica, sans-serif;
font-family: 'Times New Roman', serif;
font-family: 'Courier New', monospace;
/* Font size */
font-size: 16px;
font-size: 1.2em; /* relative to parent */
font-size: 1.2rem; /* relative to root */
/* Font weight */
font-weight: normal;
font-weight: bold;
font-weight: 700;
/* Font style */
font-style: italic;
font-style: oblique;
/* Shorthand */
font: italic bold 16px/1.5 Arial, sans-serif;
}
Text Properties:
.paragraph {
/* Alignment */
text-align: left;
text-align: center;
text-align: right;
text-align: justify;
/* Decoration */
text-decoration: underline;
text-decoration: line-through;
text-decoration: none;
/* Transform */
text-transform: uppercase;
text-transform: lowercase;
text-transform: capitalize;
/* Spacing */
letter-spacing: 2px;
word-spacing: 5px;
line-height: 1.6;
/* Indent */
text-indent: 50px;
/* Shadow */
text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
}
Web Fonts:
<!-- Google Fonts -->
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet">
body {
font-family: 'Roboto', sans-serif;
}
Absolute Units:
/* Pixels (most common) */
font-size: 16px;
/* Points (print) */
font-size: 12pt;
/* Inches, cm, mm (rarely used) */
width: 2in;
Relative Units:
/* em - relative to parent font-size */
font-size: 1.5em; /* 1.5 times parent */
/* rem - relative to root (html) font-size */
font-size: 1.5rem;
/* Percentage */
width: 50%;
font-size: 120%;
/* Viewport units */
width: 50vw; /* 50% of viewport width */
height: 100vh; /* 100% of viewport height */
font-size: 5vmin; /* 5% of smaller dimension */
Every element is a rectangular box with:
.box {
/* Content area */
width: 300px;
height: 200px;
/* Padding (inside) */
padding: 20px;
padding: 10px 20px; /* vertical horizontal */
padding: 10px 20px 30px 40px; /* top right bottom left */
/* Border */
border: 2px solid black;
border-width: 2px;
border-style: solid;
border-color: black;
border-radius: 10px;
/* Margin (outside) */
margin: 20px;
margin: 10px auto; /* center horizontally */
/* Box-sizing */
box-sizing: border-box; /* includes padding and border in width */
}
Content-box (default):
.box {
width: 300px;
padding: 20px;
border: 5px solid black;
/* Actual width = 300 + 40 + 10 = 350px */
}
Border-box (recommended):
* {
box-sizing: border-box;
}
.box {
width: 300px;
padding: 20px;
border: 5px solid black;
/* Actual width = 300px (includes padding and border) */
}
/* Block elements (full width) */
div {
display: block;
}
/* Inline elements (only content width) */
span {
display: inline;
}
/* Inline-block (inline but can have width/height) */
.button {
display: inline-block;
width: 200px;
padding: 10px;
}
/* Hide element */
.hidden {
display: none;
}
/* Flex and Grid (next week) */
.container {
display: flex;
display: grid;
}
/* Hide but keep space */
.invisible {
visibility: hidden;
}
/* Hide completely */
.gone {
display: none;
}
/* Transparent */
.see-through {
opacity: 0.5;
}
Static (default):
.element {
position: static; /* Normal flow */
}
Relative:
.element {
position: relative;
top: 20px; /* Move down from normal position */
left: 10px; /* Move right from normal position */
}
Absolute:
.parent {
position: relative;
}
.child {
position: absolute;
top: 0;
right: 0; /* Position relative to parent */
}
Fixed:
.navbar {
position: fixed;
top: 0;
left: 0;
width: 100%;
z-index: 1000; /* Stack order */
}
Sticky:
.sidebar {
position: sticky;
top: 20px; /* Sticks when scrolling */
}
.layer1 {
position: relative;
z-index: 1;
}
.layer2 {
position: relative;
z-index: 2; /* Appears on top */
}
.modal {
position: fixed;
z-index: 9999; /* Very top */
}
.sidebar {
float: left;
width: 30%;
}
.main {
float: right;
width: 68%;
}
.clearfix::after {
content: "";
display: table;
clear: both;
}
nav bar with fixed position at top
code example here:
<nav>
<a href="#">Home</a>
<a href="#">About</a>
<a href="#">Contact</a>
</nav>
nav {
position: fixed;
top: 0;
width: 100%;
background-color: #333;
color: white;
padding: 10px 0;
text-align: center;
z-index: 1000;
}
🛠️ Teaching Tools & Platforms
Live coding in VS Code + Live Server (set up and demo CSS changes in real time).
Online editors like CodePen/JSFiddle for student experimentation.
Weekly small projects (e.g., style a resume, build a responsive navbar).
By the end of the activity, students will:
You will create and publish a single-page website on
github.io, styled using CSS. Choose a theme:
- XKCD-style comic page
- Star Wars opening crawl
- Retro terminal / hacker page
- Your own fun theme
Your page must be online by the end of the session.
Create a GitHub account (if needed).
Create a new repository called:
username.github.io
Add two files:
index.htmlstyle.cssEnable GitHub Pages → Settings → Pages → Deploy from main branch
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>My Fun Webpage</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<header>
<h1>Welcome to My Page</h1>
<p>A long time ago, in a browser far, far away…</p>
</header>
<main>
<section>
<h2>About</h2>
<p>This page is styled entirely with CSS.</p>
</section>
</main>
</body>
</html>
Students must:
body {
background: black;
color: yellow;
font-family: 'Arial', sans-serif;
overflow: hidden;
}
main {
width: 60%;
margin: auto;
font-size: 1.5em;
text-align: justify;
animation: crawl 20s linear infinite;
}
@keyframes crawl {
from { transform: translateY(100%); }
to { transform: translateY(-200%); }
}
body {
font-family: "Comic Sans MS", cursive;
background: white;
color: black;
}
h1 {
border-bottom: 2px solid black;
}
section {
max-width: 600px;
margin: auto;
}
Vote for:
🏆 Small prizes or bragging rights recommended.
Create a themed website hosted on GitHub Pages that uses CSS to express a narrative or aesthetic.
You may work individually or in pairs.
Your site must include:
header, main, footer or similar)section, nav, article)At least:
Use of:
One of:
username.github.io| Criterion | Marks |
|---|---|
| CSS correctness & clarity | 30 |
| Visual creativity & theme | 25 |
| HTML structure | 20 |
| GitHub Pages deployment | 15 |
| Code readability | 10 |
| Total | 100 |