CSS
CSS (Cascading Style Sheets) describes how elements should be presented, not what they are. It operates on the DOM tree produced by HTML parsing. CSS is declarative: you describe desired outcomes, and the browser decides how to achieve them. The complexity of CSS comes from rule interaction, not syntax. Understanding CSS means understanding how rules are resolved.
The CSS processing pipeline (mental model)
When CSS is applied, the browser performs these conceptual steps:
- Parse CSS into the CSSOM
- Match selectors against DOM elements
- Resolve the cascade (which rule wins)
- Compute final values (computed styles)
- Apply layout algorithms
- Paint and composite
Most bugs come from misunderstanding when and why a value is chosen.
The cascade (why CSS behaves the way it does)
CSS is designed so that many rules can apply to the same element at the same time. This is not a mistake; it is a core design goal. Without a deterministic conflict-resolution system, styling large documents would be impossible. The cascade defines how conflicts are resolved, not whether conflicts are allowed. When two rules both match an element, the cascade decides which one wins.
Importance (!important)
Rules marked with !important override normal rules, regardless of specificity or order.
Example:
.button { color: blue;}
.button { color: red !important;}Result:
color:red wins, even though both selectors are equal.
Key points:
!importantjumps to the top of the priority stack.- Multiple
!importantrules still compete using the remaining cascade steps. - It should be reserved for exceptional cases, not routine styling.
Why it is dangerous:
- It bypasses the natural conflict resolution of CSS.
- It makes future overrides harder, often requiring more !important.
- It flattens the cascade into a brittle hierarchy.
Origin (where the rule comes from)
CSS rules come from different sources, called origins.
Ordered from weakest to strongest:
- User agent styles (browser defaults)
- User styles (user-defined preferences)
- Author styles (your application’s CSS)
Example:
- Browsers give
a default font size.
- Your stylesheet overrides that size.
- The user may override both for accessibility reasons.
Key points:
- Author styles usually win over browser defaults.
- Accessibility tools rely on user styles being respected.
- The origin layer exists to balance control between browser, user, and author.
This layer is rarely visible in day-to-day work, but it explains why browser defaults are easily overridden.
Specificity (how precise the selector is)
Specificity determines how targeted a selector is.
Simplified ranking (weak → strong):
- Type selectors (
p) - Class selectors (
.card) - Attribute selectors (
[disabled]) - Pseudo-classes (
:hover) - ID selectors (
#main)
Example:
p {color: black;}
.article p {color: gray;}Result:
.article pwins because it is more specific.
Key points:
- Specificity compares selectors component by component, not by intuition.
- A single ID selector outweighs many class selectors.
- More specific selectors override less specific ones, even if they appear earlier.
Design implication:
- High specificity makes styles hard to override later.
- Low specificity keeps styles flexible and composable.
Source order (last rule wins)
If all previous steps are equal, the rule defined later wins.
Example:
.card {background: white;}
.card {background: gray;}Result:
- The second rule applies.
Key points:
- CSS is read top-to-bottom.
- This allows intentional overrides without increasing specificity.
- Source order is the final tie-breaker, not the primary mechanism.
Good CSS often relies on source order instead of specificity escalation.
Putting it all together (mental model)
When multiple rules match an element, the browser asks:
- Is one rule !important?
- Which rule comes from the stronger origin?
- Which selector is more specific?
- Which rule appears later?
The first difference encountered decides the winner.
Why CSS conflicts are normal
CSS assumes:
- Components will overlap
- Rules will collide
- Styles will be reused and extended
The cascade is how CSS scales without requiring global coordination.
Fighting the cascade leads to:
- Over-specific selectors
- Excessive !important
- Fragile stylesheets
Designing with the cascade leads to:
- Predictable overrides
- Reusable components
- Maintainable systems
Practical guidance
- Prefer source order over specificity
- Prefer specificity over !important
- Use !important only when escaping external constraints
- Treat specificity like technical debt
Key takeaway:
- The cascade is not a problem to solve; it is the solution CSS provides.
Inheritance (what flows down the tree)
Some CSS properties inherit values from parent elements automatically.
Common inherited properties:
colorfont-familyfont-sizeline-height
Common non-inherited properties:
marginpaddingborderwidth,height
Inheritance explains why setting styles high in the DOM is powerful and efficient.
The box model (fundamental to layout)
Every element is a rectangular box composed of:
- Content
- Padding
- Border
- Margin
Key properties:
box-sizing: content-box(default)box-sizing: border-box(recommended)
With border-box:
- Width and height include padding and border.
- Layout becomes predictable.
Misunderstanding the box model causes sizing bugs and overflow issues.
Display types (how elements participate in layout)
The display property defines an element’s layout behavior.
Common values:
block→ new line, full widthinline→ flows with text, no box sizinginline-block→ inline flow with box modelnone→ removed from layout entirely
Advanced:
flexgridtable
Changing display often changes layout more than any other property.
Positioning (coordinate systems)
CSS positioning controls how elements are placed relative to others.
Types:
static(default)relative(offset from itself)absolute(removed from flow, positioned relative to nearest positioned ancestor)fixed(relative to viewport)sticky(hybrid scroll-based behavior)
Key insight:
- Positioned elements establish new containing blocks.
absolutedoes not mean “relative to the page”.
Flexbox (one-dimensional layout)
Flexbox is designed for one axis at a time (row or column).
Core concepts:
- Flex container vs flex items
- Main axis vs cross axis
- Free space distribution
Key properties:
display: flexflex-directionjustify-contentalign-itemsflex-grow,flex-shrink,flex-basis
Flexbox excels at alignment, spacing, and dynamic sizing.
Grid (two-dimensional layout)
Grid is designed for rows and columns simultaneously.
Core concepts:
- Explicit vs implicit grid
- Tracks, lines, and areas
- Fractional units (
fr)
Key properties:
display: gridgrid-template-columnsgrid-template-rowsgrid-template-areasgap
Grid enables layouts that were previously very complex or impossible.
Flow layout (default behavior)
Normal flow is how elements lay out without special positioning.
Characteristics:
- Blocks stack vertically
- Inline content wraps horizontally
- Margins collapse vertically
Margin collapsing:
- Adjacent vertical margins may merge
- Does not apply to flex/grid containers
Many “mysterious” spacing bugs are margin-collapsing effects.
Sizing units (relative vs absolute)
CSS supports multiple unit systems.
Absolute:
px(not truly physical pixels)
Relative:
%(relative to containing block)em(relative to font size of element)rem(relative to root font size)vw,vh(viewport-relative)
Design principle:
- Prefer relative units for scalable layouts.
- Use
remfor consistent sizing.
Colors, backgrounds, and borders
CSS supports:
- Named colors
- Hex, RGB, HSL
- Transparency via alpha channels
Backgrounds:
- Can be layered
- Can be images or gradients
- Controlled via background-size, position, repeat
Borders:
- Part of the box model
- Affect layout unless box-sizing is adjusted
Text and typography
Typography properties strongly affect readability.
Key properties:
font-familyfont-sizeline-heightfont-weightletter-spacing
Best practice:
- Set base typography on the root (
htmlorbody) - Let inheritance propagate styles naturally
Stacking context and z-index (often misunderstood)
Stacking contexts define painting order.
Created by:
- Positioned elements with z-index
- Elements with opacity < 1
- Transforms, filters, etc.
Rules:
- z-index only works within the same stacking context
- Higher z-index does not escape its context
Most z-index bugs are stacking-context bugs.
Transitions and animations
CSS can animate property changes declaratively.
Transitions:
- Animate between states
- Triggered by property changes
Animations:
- Keyframe-based
- Run independently once started
Performance note:
- Transform and opacity animations are cheapest
- Layout-affecting animations cause jank
CSS and performance
CSS affects performance through:
- Selector complexity
- Layout invalidation
- Paint cost
- Compositing behavior
Guidelines:
- Avoid deeply nested selectors
- Minimize layout-triggering changes
- Prefer transform-based animations
CSS is part of the rendering pipeline, not just decoration.
Common CSS failure modes
- Fighting the cascade instead of designing with it
- Over-specific selectors
- Layout built with hacks instead of proper layout systems
- Excessive z-index escalation
- Using CSS to encode application logic
Mental checklist for CSS
- Does this rule need high specificity?
- Is this layout one-dimensional or two-dimensional?
- Am I triggering layout or just compositing?
- Is this structure robust to content changes?
- Can inheritance do this for me?