# Part 1: Selectors, Specificity, and the Cascade

## Introduction

CSS (Cascading Style Sheets) is what I pick up immediately after writing HTML. The two are inseparable in practice — the markup gives structure, CSS gives it visual form. But CSS has subtleties that take time to internalise. The cascade, specificity, and inheritance explain why a style you wrote seems to have no effect, or why removing one rule breaks three unrelated things. Once those mechanics click, CSS stops being frustrating and becomes predictable.

This part covers how CSS works at the engine level, every selector type I use day-to-day, and how the browser resolves conflicts between competing rules.

***

## How to Apply CSS

There are three ways to attach CSS to an HTML document.

### External Stylesheet (preferred)

```html
<link rel="stylesheet" href="styles.css" />
```

The stylesheet is a separate `.css` file, cached by the browser across pages, and easy to maintain. This is what I use for every project.

### `<style>` Element

```html
<head>
  <style>
    body {
      font-family: sans-serif;
    }
  </style>
</head>
```

Useful for page-specific overrides or critical above-the-fold styles to avoid a render-blocking request.

### Inline Styles (avoid for general use)

```html
<p style="color: red; font-weight: bold;">Warning</p>
```

Inline styles have the highest specificity short of `!important`, making them difficult to override. They are appropriate when CSS is generated dynamically (e.g., a JavaScript-driven colour value), not for general styling.

***

## CSS Rule Anatomy

```css
selector {
  property: value;
  property: value;
}
```

```css
h2 {
  font-size: 1.5rem;
  font-weight: 600;
  margin-bottom: 0.75rem;
}
```

* **Selector** — targets the element(s) to style
* **Declaration block** — `{ ... }` contains one or more declarations
* **Declaration** — a `property: value` pair ending with `;`

***

## Selectors

### Type Selector

Targets all elements of a given tag name.

```css
p {
  line-height: 1.6;
}

code {
  font-family: 'JetBrains Mono', monospace;
}
```

### Class Selector

Targets elements with a specific `class` attribute value. The most common selector in everyday CSS.

```css
.card {
  background: #fff;
  border: 1px solid #e2e8f0;
  border-radius: 0.5rem;
  padding: 1.5rem;
}

.badge--success {
  background: #c6f6d5;
  color: #276749;
}
```

```html
<div class="card">...</div>
<span class="badge badge--success">Active</span>
```

A single element can have multiple classes separated by spaces.

### ID Selector

Targets a single element with a specific `id`.

```css
#main-content {
  max-width: 860px;
  margin: 0 auto;
}
```

I use ID selectors sparingly in CSS — their specificity is much higher than class selectors, making them hard to override. IDs are better reserved for JavaScript targeting and fragment links.

### Universal Selector

Matches every element.

```css
* {
  box-sizing: border-box;
}
```

The most common use: applying `box-sizing: border-box` globally. In isolation it is fine; avoid using it for broad style rules as it matches everything in the document.

### Attribute Selector

Targets elements based on the presence or value of attributes.

```css
/* Has the attribute */
[disabled] {
  opacity: 0.5;
  cursor: not-allowed;
}

/* Exact value match */
[type="submit"] {
  background: #3b82f6;
  color: #fff;
}

/* Contains word */
[class~="btn"] { }

/* Starts with */
[href^="https"] { }

/* Ends with */
[href$=".pdf"]::after {
  content: " (PDF)";
}

/* Contains substring */
[href*="github.com"] { }
```

### Pseudo-Class Selectors

Pseudo-classes target elements in a specific state.

```css
/* User interaction */
a:hover    { text-decoration: underline; }
a:focus    { outline: 2px solid #3b82f6; }
a:visited  { color: #7c3aed; }
a:active   { color: #1d4ed8; }

/* Form state */
input:focus   { border-color: #3b82f6; }
input:valid   { border-color: #38a169; }
input:invalid { border-color: #e53e3e; }
input:disabled { opacity: 0.5; cursor: not-allowed; }
input:checked  { accent-color: #3b82f6; }

/* Structural */
li:first-child  { font-weight: bold; }
li:last-child   { border-bottom: none; }
li:nth-child(2) { background: #f7fafc; }
li:nth-child(odd)  { background: #f7fafc; }
li:nth-child(even) { background: #fff; }

p:not(.intro) { color: #4a5568; }
```

### Pseudo-Element Selectors

Pseudo-elements create virtual sub-elements for styling.

```css
/* First line of a paragraph */
p::first-line {
  font-weight: bold;
}

/* First letter */
p::first-letter {
  font-size: 2rem;
  float: left;
  margin-right: 0.25rem;
}

/* Content before/after element */
.required-label::after {
  content: " *";
  color: #e53e3e;
}

[href$=".pdf"]::after {
  content: " ↗";
}

/* Text selection colour */
::selection {
  background: #bee3f8;
  color: #1a365d;
}
```

The double-colon `::` is the CSS3 syntax for pseudo-elements. Single colon `:` works too for historical reasons, but `::` is the modern standard.

### Combinator Selectors

Combinators select elements based on their relationship to other elements.

```css
/* Descendant: any nav inside header (any depth) */
header nav { }

/* Child: direct children only */
ul > li {
  list-style: none;
}

/* Adjacent sibling: h2 immediately followed by p */
h2 + p {
  margin-top: 0;
}

/* General sibling: all p after h2 at same level */
h2 ~ p {
  color: #4a5568;
}
```

***

## Specificity

When multiple rules target the same element and the same property, specificity determines which value wins.

### How Specificity is Calculated

Specificity is a three-number score `(A, B, C)`:

| Selector type                                                   | Contributes to |
| --------------------------------------------------------------- | -------------- |
| Inline style (`style="..."`)                                    | A              |
| ID (`#id`)                                                      | A              |
| Class (`.class`), pseudo-class (`:hover`), attribute (`[type]`) | B              |
| Type (`p`, `h2`), pseudo-element (`::before`)                   | C              |
| Universal (`*`), combinators ( , `>`, `+`, `~`)                 | Nothing        |

Higher A beats lower A regardless of B and C; A ties compare B; B ties compare C.

### Examples

```css
p               /* (0, 0, 1) */
.card           /* (0, 1, 0) */
#main           /* (1, 0, 0) — wins over any class or type */
.card p         /* (0, 1, 1) */
.card .title    /* (0, 2, 0) */
#main .card p   /* (1, 1, 1) */
```

```css
/* Specificity (0, 1, 0) */
.warning {
  color: orange;
}

/* Specificity (0, 0, 1) — loses to .warning */
p {
  color: black;
}
```

For a `<p class="warning">`, the text is orange because `.warning` has higher specificity.

### `!important`

```css
.override {
  color: red !important;
}
```

`!important` overrides the entire specificity system. It should be used as a last resort — browser resets, utility classes, or third-party overrides. Once `!important` appears in a codebase, the only way to override it is with another `!important`, creating an escalating mess.

***

## The Cascade

The cascade is the algorithm the browser uses to determine which value applies when multiple declarations target the same property on the same element.

The cascade considers three factors, in priority order:

### 1. Origin and Importance

| Origin                         | Normal | `!important` |
| ------------------------------ | ------ | ------------ |
| User agent (browser defaults)  | Lowest | High         |
| User styles (browser settings) | Medium | Higher       |
| Author styles (your CSS)       | High   | Highest      |

Your CSS overrides browser defaults, which is why `<button>` looks different once you style it.

### 2. Specificity

Higher specificity wins when origins are the same and neither uses `!important`.

### 3. Order of Appearance

When two rules have the same origin and specificity, the **last one wins**.

```css
p { color: blue; }
p { color: green; }  /* green wins — same specificity, later in file */
```

This is why the order of `<link>` tags and `@import` declarations matters.

***

## Inheritance

Some CSS properties inherit their value from a parent element automatically; others do not.

**Inherited by default** (typography-related): `color`, `font-family`, `font-size`, `font-weight`, `font-style`, `line-height`, `letter-spacing`, `text-align`, `text-transform`, `visibility`, `cursor`

**Not inherited by default** (box/layout-related): `margin`, `padding`, `border`, `background`, `width`, `height`, `display`, `position`, `overflow`

```html
<div style="color: steelblue; font-family: Georgia, serif;">
  <p>This paragraph inherits color and font-family.</p>
  <p>So does this one.</p>
</div>
```

### Controlling Inheritance

```css
/* Force inheritance */
.child {
  border: inherit;
}

/* Reset to browser default */
.child {
  color: initial;
}

/* Use whatever the parent provides for this property */
.child {
  color: unset;
}

/* Reset to browsing-context default (like initial, but inheritable properties use inherit) */
.child {
  all: revert;
}
```

***

## CSS Reset and Normalisation

Browsers ship with their own default styles (the user-agent stylesheet). `<h1>` has a large font size and margin. `<ul>` has left padding and bullets. `<button>` has a border and background. These defaults differ slightly between browsers.

### My Minimal Reset

This is the reset I paste into every project's `styles.css`:

```css
*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  font-size: 16px;
  -webkit-text-size-adjust: 100%;
}

body {
  font-family: system-ui, -apple-system, sans-serif;
  line-height: 1.5;
  color: #1a202c;
  background: #fff;
}

img,
video,
svg {
  display: block;
  max-width: 100%;
}

input,
button,
textarea,
select {
  font: inherit;
}

p,
h1, h2, h3, h4, h5, h6 {
  overflow-wrap: break-word;
}
```

Key decisions here:

* `box-sizing: border-box` — padding and border are included in element width/height, not added to it. This is the model that matches how most developers think about sizing.
* `margin: 0; padding: 0` — removes browser spacing so I start from a known baseline.
* `font: inherit` on form elements — browsers default form elements to their own font, which often does not match the page font.
* `max-width: 100%` on media — prevents images from overflowing their container.

***

## The `:root` Selector and Global Variables

The `:root` pseudo-class targets the document root element (`<html>`). It is where I define CSS custom properties (variables) that apply across the entire page.

```css
:root {
  --color-primary: #3b82f6;
  --color-text: #1a202c;
  --color-muted: #718096;
  --font-body: system-ui, -apple-system, sans-serif;
  --font-mono: 'JetBrains Mono', 'Fira Code', monospace;
  --spacing-sm: 0.5rem;
  --spacing-md: 1rem;
  --spacing-lg: 2rem;
  --border-radius: 0.375rem;
}
```

Custom properties are covered in depth in Part 5, but defining them at `:root` is a pattern worth establishing from the start.

***

## Summary

| Concept                  | Key Point                                             |
| ------------------------ | ----------------------------------------------------- |
| Type selector            | Targets all elements of that tag                      |
| Class selector           | Most common — reusable, composable                    |
| ID selector              | High specificity — use sparingly in CSS               |
| Attribute selector       | Target by attribute presence or value                 |
| Pseudo-class             | Element state (`:hover`, `:focus`, `:nth-child`)      |
| Pseudo-element           | Virtual sub-elements (`::before`, `::after`)          |
| Combinators              | Structural relationships (descendant, child, sibling) |
| Specificity              | `(id, class/pseudo-class/attr, type)` — higher wins   |
| `!important`             | Overrides specificity — use as last resort            |
| Cascade order            | Origin → specificity → source order                   |
| Inheritance              | Typography inherits; box model does not               |
| `box-sizing: border-box` | Apply globally — makes sizing intuitive               |

***

## Up Next

[Part 2](https://blog.htunnthuthu.com/getting-started/programming/css-101/css-101-part-2) covers the box model, display modes, and positioning — the foundation of how elements take up and share space on a page.
