Simple CSS. Again
satya - 8/17/2025, 2:23:54 PM
To understand CSS in the context of next.js
To understand CSS in the context of next.js
satya - 8/17/2025, 2:45:53 PM
Project structure
my-app/
app/
globals.css
layout.tsx
page.tsx
components/
Button.tsx
Button.module.css
LinkText.tsx
LinkText.module.css
Field.tsx
Field.module.css
SimpleList.tsx
SimpleList.module.css
satya - 8/17/2025, 2:48:45 PM
A typical global.css
/* 1) CSS Reset-ish (small, modern) */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html:focus-within { scroll-behavior: smooth; }
body { min-height: 100vh; text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased; }
img, picture, video, canvas, svg { display: block; max-width: 100%; }
input, button, textarea, select { font: inherit; }
/* 2) Theme tokens (colors, spacing, radius, shadows) */
:root {
/* colors */
--color-bg: #0b1220; /* page background */
--color-surface: #121a2b; /* cards, sections */
--color-border: #2b3752; /* subtle borders */
--color-text: #e5eaf3; /* primary text */
--color-muted: #a7b1c5; /* secondary text */
--color-link: #6ea8fe; /* links */
--color-primary: #5b8cff; /* brand */
--color-primary-700: #3f6ff0; /* brand darker */
--color-danger: #ff6b6b;
--color-success: #5bd6a1;
/* spacing & radius */
--space-1: 0.25rem; /* 4px */
--space-2: 0.5rem; /* 8px */
--space-3: 0.75rem; /* 12px */
--space-4: 1rem; /* 16px */
--space-6: 1.5rem; /* 24px */
--radius-sm: 6px;
--radius-md: 10px;
--shadow-1: 0 1px 2px rgba(0,0,0,.12), 0 3px 8px rgba(0,0,0,.14);
}
/* 3) Base typography and layout */
html, body { color: var(--color-text); background: var(--color-bg); }
body { font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI,
Roboto, "Helvetica Neue", Arial, "Noto Sans", "Apple Color Emoji",
"Segoe UI Emoji"; line-height: 1.6; }
main { max-width: 900px; margin: 0 auto; padding: var(--space-6); }
h1 { font-size: clamp(1.6rem, 3vw, 2.2rem); margin-bottom: var(--space-4); }
h2 { font-size: clamp(1.3rem, 2.5vw, 1.6rem); margin-top: var(--space-6); margin-bottom: var(--space-2); }
p + p { margin-top: var(--space-2); }
/* 4) Links */
a { color: var(--color-link); text-decoration: none; }
a:hover { text-decoration: underline; }
/* 5) Focus styles (keyboard a11y) */
:where(a, button, input, select, textarea, summary):focus-visible {
outline: 2px solid var(--color-primary);
outline-offset: 2px;
}
/* 6) Containers */
.section { background: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
box-shadow: var(--shadow-1); padding: var(--space-6); }
.muted { color: var(--color-muted); }
/* 7) Small utilities */
.stack > * + * { margin-top: var(--space-2); } /* vertical rhythm */
.row { display: flex; gap: var(--space-2); align-items: center; }
satya - 8/17/2025, 3:06:43 PM
Psuedo elements: Some examples
- ::before ? insert (before content)
- ::after ? insert (after content)
- ::first-line ? typography (first line)
- ::first-letter ? dropcap (first letter)
- ::marker ? list (bullet/number)
- ::selection ? highlight (user selection)
satya - 8/17/2025, 3:07:42 PM
Psuedo classes: Some examples
- :hover ? hover effect
- :active ? clicked state
- :focus ? focused by keyboard/tab
- :visited ? visited link
- :first-child ? first element in a parent
satya - 8/17/2025, 3:14:13 PM
Standalone psuedo classes
- :root ? the root element (in HTML, <html>)
- :any-link ? any link (:link or :visited)
- :link ? unvisited links
- :visited ? visited links
- :fullscreen ? the element in fullscreen mode
- :scope ? the scoping element (defaults to :root)
- :target ? element pointed to by the URL fragment
- :defined ? custom elements that have been defined
satya - 8/17/2025, 3:15:13 PM
what are they about?
- They describe a global state or a unique property of an element, not relative to another selector
- describes a special structural role or global condition
satya - 8/17/2025, 3:15:39 PM
Attached pseudo-classes (always come after a selector)
- :hover ? when mouse is over the element
- :focus ? when element has keyboard/mouse focus
- :active ? while the element is being clicked
- :first-child / :last-child ? first/last child of parent
- :nth-child(n) / :nth-of-type(n) ? element in a certain position
- :only-child / :only-of-type ? element that?s the only one
- :checked ? checkboxes/radios when checked
- :disabled / :enabled ? form controls
- :empty ? element with no children
satya - 8/17/2025, 3:16:42 PM
what are they about?
- They describe a state or position relative to a specific element
- state of an element relative to siblings or interaction
satya - 8/17/2025, 3:28:23 PM
The focus psudeo classes
- :focus ? Matches the element that itself has focus (e.g., an input, button, or link the user clicked or tabbed into).
- :focus-within ? Matches an element if it OR any of its descendants has focus. Useful for styling parent containers when a child is active.
- :focus = ?this element has focus.?
- :focus-within = ?this element or something inside it has focus.?
satya - 8/17/2025, 3:35:08 PM
The Selectors...
- Universal (*): Selects all elements.
- Descendant (A B): B inside A (any depth).
- Child (A > B): B is a direct child of A.
- Adjacent sibling (A + B): B immediately follows A.
- General sibling (A ~ B): B is any sibling after A.
- Selector list (A, B): A or B (applies to both).
- Functional pseudo-class :is(A, B, C): Matches any of the selectors inside (shorter code).
- Functional pseudo-class :where(A, B, C): Like :is(), but adds zero specificity.
- Attribute [attr]: Elements with the attribute.
- Attribute [attr="value"]: Attribute equals value.
- Attribute [attr~="value"]: Attribute contains value in a space-separated list.
- Attribute [attr|="value"]: Attribute starts with value (or value-? with hyphen).
- Attribute [attr^="value"]: Attribute starts with value (prefix match).
- Attribute [attr$="value"]: Attribute ends with value (suffix match).
- Attribute [attr*="value"]: Attribute contains value (substring match).
satya - 8/17/2025, 5:07:15 PM
The where...
:where(a, button, input, select, textarea, summary):focus-visible {
outline: 2px solid var(--color-primary);
outline-offset: 2px;
}
is equivalent to
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible {
outline: 2px solid var(--color-primary);
outline-offset: 2px;
}
satya - 8/17/2025, 5:18:23 PM
One rule, Coming later in the source over-rides the previous
One rule, Coming later in the source over-rides the previous
satya - 8/17/2025, 5:28:45 PM
Same element and it various states like hover...
- Specificity:
- button:hover ? (0,0,1,1)
- button ? (0,0,0,1)
- with where....
- :where(button):hover ? (0,0,1,0)
- button ? (0,0,0,1)
- with classes...
- :where(button):hover { background: black; }
- /* (0,0,1,0) ? base hover */
- .btn { background: gray; }
- /* (0,0,1,0) ? same specificity, later wins */
satya - 8/17/2025, 5:29:56 PM
Cheatsheet to understand where and specificity
- Plain element later vs :where(button):hover ? hover still wins
- Class later vs :where(button):hover ? class can win on tie (later source order)
- Plain element later vs button:hover ? hover wins (more specific)
- Class later vs button:hover ? hover still wins (more specific)
satya - 8/17/2025, 5:34:36 PM
Class alone vs neutralized
.btn { ? } /* specificity: (0,0,1,0) */
:where(.btn) { ? } /* specificity: (0,0,0,0) */
satya - 8/17/2025, 5:35:23 PM
Inutively....
- classes (and IDs) increase specificity normally.
- Inside :where(...), they don?t. Only the parts outside :where contribute.
satya - 8/17/2025, 5:39:49 PM
Understand this example better....
/* Base focus ring: virtual/soft */
:where(a, button):focus-visible { outline: 2px solid var(--ring); }
/* Component override: easy to take over */
.btn { outline: none; } /* same specificity, later wins */
satya - 8/17/2025, 5:40:56 PM
Analogy: the where
- May be there is another analogy (may not be exact) ...
- In OO programming by indicating that something is a virtual method....
- you are saying...safe enough to override.... as opposed to another method that you can override but stayed unmentioned....the where being the former, giving the allowance
satya - 8/17/2025, 5:48:51 PM
In the example above....
- The weakness of where...though intentional allowed a component to take over the whole button...
- If it chooses....to
satya - 8/17/2025, 5:50:39 PM
So how do I summarize?
- go with the OO analogy
- follows the "is" in terms of ease (not specificity)
- allows to set baselines or resets (as they are called)
- Simpler syntax as opposed to comma separated classes or elements
satya - 8/17/2025, 5:53:37 PM
Here is a list of selectors
/* Elements */
html /* root element */
body /* document body */
main /* main content */
header /* page/section header */
footer /* page/section footer */
h1 /* heading level 1 */
p /* paragraph */
a /* link */
img /* image */
button /* button */
input /* form input */
select /* select box */
textarea /* multi-line input */
ul /* unordered list */
li /* list item */
/* Classes & IDs */
.card /* class */
.card.primary /* class with modifier */
#app /* id */
/* Attribute selectors */
input[type="text"] /* exact match */
a[target="_blank"] /* opens new tab */
a[href^="https://"] /* starts with */
a[href$=".pdf"] /* ends with */
a[href*="docs"] /* contains */
input[aria-invalid="true" i] /* case-insensitive match */
/* Pseudo-classes (state & UI) */
a:hover /* mouse over */
button:active /* active press */
input:focus /* focused */
:focus-visible /* keyboard-visible focus */
:focus-within /* element containing a focused descendant */
:disabled /* disabled controls */
:enabled /* enabled controls */
:checked /* checked checkbox/radio */
:indeterminate /* tri-state checkbox */
:required /* required input */
:optional /* optional input */
:read-only /* readonly input */
:placeholder-shown /* input shows placeholder */
:valid /* passes validation */
:invalid /* fails validation */
:target /* URL fragment target */
/* Structural pseudo-classes */
:first-child /* first child of parent */
:last-child /* last child of parent */
:only-child /* only child of parent */
:nth-child(2) /* 2nd child */
:nth-child(odd) /* odd children */
:nth-child(3n+1) /* every 3rd, starting at 1 */
:nth-of-type(2) /* 2nd element of same type */
:is(h1, h2, h3) /* match any of these, normal specificity */
:where(h1, h2, h3) /* match any of these, zero specificity */
:not(.active) /* not matching .active */
:has(> img) /* element that has a direct child img */
/* Pseudo-elements */
::before /* generated content before */
::after /* generated content after */
::placeholder /* placeholder text styling */
::selection /* selected text (non-inherited) */
::marker /* list item marker/bullet */
::file-selector-button /* file input button */
::backdrop /* backdrop of a modal dialog */
/* Document/root */
:root /* top-level element (html) */
:scope /* current query scope */
/* Combinators */
article p /* descendant (p anywhere inside article) */
article > p /* direct child */
h2 + p /* adjacent sibling (p immediately after h2) */
h2 ~ p /* general siblings (any p after h2) */
/* Grouping */
h1, h2, h3 /* group multiple selectors */
/* Common patterns (handy) */
nav :is(a, button):focus-visible /* shared focus ring targets */
:where(article, aside) :where(h1, h2, h3) /* low-specificity typography base */
.card :not(:last-child) /* all children except last */
main :has(> .error) /* main that contains a direct .error child */
satya - 8/18/2025, 5:52:42 PM
Order of understanding
- Understand selectors
- That includes elements, classes, pseudo classes and pseudo elements
- ------------ the root
- Understand :root
- Understand custom properties, var()
- Understand :is, :where
- --------- others
- Resets
- Tokens
- Containers like sections, stacks, rows
- -------------------Now
- Take a look at a large functional global.css
- Read the global.css with that knowledge