CSS Fundamentals & Selectors
Checking access...
CSS (Cascading Style Sheets) controls the visual presentation of HTML. Where HTML provides structure and meaning, CSS provides color, layout, typography, and animation.
How CSS Works
CSS applies styles to HTML elements by selecting them and declaring property-value pairs:
selector { property: value;}Example:
h1 { color: blue; font-size: 32px;}This selects all <h1> elements and makes their text blue and 32 pixels tall.
Three Ways to Add CSS
1. Inline CSS (Avoid)
Apply styles directly to an element using the style attribute:
<h1 style="color: blue; font-size: 32px;">Blue Heading</h1>Problems: Mixes content with presentation, impossible to reuse, hard to maintain.
2. Internal CSS (Good for single pages)
Use a <style> tag in the <head>:
<head> <style> h1 { color: blue; } p { font-size: 16px; } </style></head>Better than inline because styles are reusable across the page, but only applies to one HTML file.
3. External CSS (Best practice)
Create a separate .css file and link it in <head>:
<head> <link rel="stylesheet" href="styles.css"></head>h1 { color: blue; }p { font-size: 16px; }Best because:
- One stylesheet controls all pages on your site
- Browsers cache the CSS file (faster subsequent loads)
- Clean separation of content (HTML) and presentation (CSS)
CSS Selectors
Selectors determine which elements get styled.
Element (Type) Selector
Selects all elements of a given type:
h1 { color: navy; }p { line-height: 1.6; }a { text-decoration: none; }Class Selector
Selects all elements with a specific class attribute. Classes are reusable:
<p class="highlight">This paragraph is highlighted.</p><p>This one is not.</p><p class="highlight">This one is highlighted too.</p>.highlight { background-color: yellow; padding: 4px;}Naming: Use kebab-case for class names: .main-content, .nav-link, .error-message.
ID Selector
Selects a single element with a specific ID. IDs must be unique per page:
<header id="site-header"> <h1>My Site</h1></header>#site-header { background: #333; color: white;}Tip
Prefer classes over IDs for styling. IDs have very high specificity and are hard to override. Reserve IDs for JavaScript targeting and anchor links.
Attribute Selector
Selects elements based on attributes or attribute values:
/* Elements with a specific attribute */[disabled] { opacity: 0.5; }
/* Exact attribute value */input[type="email"] { border-color: blue; }
/* Attribute starts with value */a[href^="https"] { color: green; }
/* Attribute ends with value */a[href$=".pdf"] { color: red; }
/* Attribute contains value anywhere */a[href*="example"] { font-weight: bold; }Combinator Selectors
Combinators define relationships between elements:
/* Descendant (space) — any nested level */article p { color: gray; }
/* Child (>) — direct children only */ul > li { list-style: square; }
/* Adjacent sibling (+) — immediately following */h2 + p { font-weight: bold; }
/* General sibling (~) — any following sibling */h2 ~ p { color: darkgray; }Pseudo-Classes
Pseudo-classes select elements based on state or position:
/* Interactive states */a:hover { color: red; }a:focus { outline: 2px solid blue; }a:active { color: orange; }a:visited { color: purple; }
/* Structural */li:first-child { font-weight: bold; }li:last-child { border-bottom: none; }li:nth-child(odd) { background: #f5f5f5; }li:nth-child(3n) { margin-bottom: 20px; } /* every 3rd */
/* Form states */input:required { border-color: red; }input:disabled { background: #eee; }input:checked + label { font-weight: bold; }
/* Negation */button:not(.primary) { background: gray; }Pseudo-Elements
Pseudo-elements style specific parts of an element:
/* First letter of a paragraph */p::first-letter { font-size: 200%; font-weight: bold; }
/* First line of a paragraph */p::first-line { text-transform: uppercase; }
/* Before/after an element (often used for icons) */.note::before { content: "Note: "; font-weight: bold; }.external-link::after { content: " ↗"; }Specificity
When two selectors target the same element, specificity determines which wins. The browser calculates a score:
/* Specificity: 0-0-1 (element) */p { color: black; }
/* Specificity: 0-1-0 (class) */.text { color: blue; }
/* Specificity: 1-0-0 (ID) */#special { color: green; }
/* Specificity: 0-1-1 (class + element) */p.text { color: red; }
/* Specificity: 0-2-0 (two classes) */.text.special { color: purple; }Specificity Hierarchy
!important ← ALWAYS avoid (breaks the cascade)Inline styles ← AvoidIDs ← 1-0-0Classes, attributes, pseudo-classes ← 0-1-0Elements, pseudo-elements ← 0-0-1Specificity is calculated as a three-part score: (IDs, Classes, Elements):
| Selector | Score |
|---|---|
* | 0,0,0 |
p | 0,0,1 |
.text | 0,1,0 |
p.text | 0,1,1 |
#header | 1,0,0 |
#header .nav a | 1,1,1 |
style="color:red" | inline wins |
Caution
Never use !important in production CSS. It breaks the natural cascade and makes future overrides impossible. If you need !important, your specificity structure needs fixing.
The Cascade
CSS stands for Cascading Style Sheets. When multiple rules apply, the cascade resolves conflicts using three factors (in order):
- Importance & Origin —
!important> normal styles, author styles > browser defaults - Specificity — Higher specificity wins
- Source Order — Later rules override earlier ones at the same specificity
/* Both have equal specificity (0,0,1) */p { color: red; }p { color: blue; } /* This wins — it comes last */Inheritance
Some CSS properties are inherited from parent to child elements:
/* Inherited by all child elements */body { color: #333; /* All text in the page inherits this */ font-family: Arial; /* All text in the page inherits this */ line-height: 1.6; /* All text in the page inherits this */}
/* Inherited properties: color, font-*, line-height, text-align, visibility *//* NOT inherited: margin, padding, border, background, width, height, display */You can control inheritance explicitly:
.child { color: inherit; /* Force inheritance from parent */ color: initial; /* Reset to browser default */ color: unset; /* inherit if inherited property, initial if not */}Try It Yourself
Create an HTML page with:
- An external CSS stylesheet linked in
<head> - Style
<h1>with an element selector (blue, 36px) - Add a class
.cardwith padding, border, and background - Add an ID
#herowith a background color - Use a descendant selector to style
<p>inside.card - Use
:hoveron links to change color - Use
::beforeto add an icon before all.externallinks - Experiment with specificity — create two rules targeting the same element and see which wins
Key Takeaways
- External CSS is the best approach — link one
.cssfile from all pages - Class selectors (
.class) are the most versatile — prefer them over ID selectors for styling - Specificity determines which rule wins: IDs > Classes > Elements
- The cascade resolves conflicts by importance, specificity, then source order
- Some properties (color, font) are inherited; others (margin, padding) are not
- Never use
!important— it breaks the cascade and makes maintenance impossible - Pseudo-classes (
:hover,:nth-child) style states; pseudo-elements (::before,::after) style sub-parts