Episode 1 — Fundamentals / 1.6 — CSS Core Fundamentals

1.6.a — CSS Syntax & Selectors

In one sentence: CSS rules are selector + declaration block pairs that tell the browser which elements to style and how — and the selector you choose determines reach, specificity, and maintainability.

Navigation: ← 1.6 Overview · 1.6.b — Specificity & Cascade →


1. Anatomy of a CSS rule

selector {
  property: value;   /* ← declaration */
  property: value;
}
PartRole
SelectorTargets element(s) in the DOM
Declaration block{} containing one or more declarations
Declarationproperty: value; — what to change and to what

2. Where CSS lives

MethodSyntaxTrade-off
External stylesheet<link rel="stylesheet" href="…">Best for production — cacheable, reusable
<style> block<style>…</style> in <head>Useful for critical CSS; not cacheable separately
Inline stylestyle="color: red"Highest specificity (except !important); hard to maintain

Best practice: external stylesheets for almost everything; inline styles only when dynamically computed via JS.


3. Selector types

Simple selectors

SelectorTargetsExample
Element (type)All elements of that typep { } — every <p>
ClassElements with that class.card { }<div class="card">
IDThe unique element with that ID#hero { }<section id="hero">
UniversalEvery element* { }
AttributeElements with a matching attribute[type="email"] { }

Grouping selector

Comma-separate selectors to apply the same styles:

h1, h2, h3 {
  font-family: inherit;
}

Combinator selectors

CombinatorNameMeaningExample
(space)DescendantAny nested child (any depth)nav a { }
>ChildDirect children onlyul > li { }
+Adjacent siblingImmediately next siblingh2 + p { }
~General siblingAny following siblingh2 ~ p { }

Pseudo-classes (state / position)

Pseudo-classMeaning
:hoverMouse is over the element
:focusElement has keyboard/programmatic focus
:focus-visibleFocus visible only when keyboard-driven (preferred for focus styles)
:activeElement is being activated (clicked/tapped)
:first-childFirst child of its parent
:last-childLast child of its parent
:nth-child(n)Positional selection (odd, even, 3n+1, etc.)
:not(selector)Negation — excludes matches
:is(selector)Matches any in the list (forgiving)
:has(selector)Parent selector — selects elements that contain a match

Pseudo-elements (generated content / parts)

Pseudo-elementCreates
::beforeContent before element's children
::afterContent after element's children
::placeholderPlaceholder text styling
::selectionUser text selection highlight

4. The parent selector: :has()

:has() is the long-awaited parent selector — it selects an element based on what it contains:

/* Style a card differently when it contains an image */
.card:has(img) {
  padding: 0;
}

/* Style a label when its sibling input is invalid */
label:has(+ input:invalid) {
  color: red;
}

Power and caution: :has() inverts the selector direction — the browser must look down the tree to match. Avoid deeply nested :has() chains on large DOMs for performance reasons.


5. Attribute selectors (detail)

SyntaxMeaning
[attr]Has the attribute (any value)
[attr="val"]Exact match
[attr^="val"]Starts with
[attr$="val"]Ends with
[attr*="val"]Contains substring
[attr~="val"]Contains word (space-separated list)

Useful for targeting form states ([disabled], [required]) or link types ([href^="https://"]).


6. Key takeaways

  1. Classes are the workhorse — reusable, low specificity, composable.
  2. IDs are unique and high-specificity — prefer classes for styling; save IDs for JS hooks and aria-labelledby.
  3. Combinators express relationships — descendant, child, sibling.
  4. :has() is the parent selector — selects based on contents.
  5. Pseudo-classes target state; pseudo-elements create virtual content.

Explain-It Challenge

Explain without notes:

  1. The difference between descendant ( ) and child (>) combinators with an example.
  2. When you would use :has() instead of adding a class with JavaScript.
  3. Why class selectors are generally preferred over ID selectors for styling.

Navigation: ← 1.6 Overview · 1.6.b — Specificity & Cascade →