CSS interviews test layout mastery, browser rendering knowledge, specificity rules, modern layout systems (Flexbox, Grid), animations, and performance. This guide covers the 50 most common questions — with concise answers and ready-to-use examples.
Quick reference
| Topic | Most asked questions |
|---|---|
| Box model | content-box vs border-box, margin collapse |
| Selectors | specificity calculation, :is(), :where() |
| Display & position | inline vs block, stacking context, z-index |
| Flexbox | main/cross axis, flex-grow/shrink/basis, align vs justify |
| Grid | template areas, auto-fill vs auto-fit, minmax() |
| Responsive | media queries, fluid typography, container queries |
| Animations | transition vs animation, will-change, @keyframes |
| Modern CSS | custom properties, :has(), @layer, subgrid |
Box model
1. What is the CSS box model?
Every element is a rectangular box with four layers: content → padding → border → margin (outside to inside: margin, border, padding, content).
.box {
width: 200px;
padding: 20px;
border: 2px solid #333;
margin: 10px;
}
| Layer | Description |
|---|---|
| Content | Where text/images are rendered (width/height target this by default) |
| Padding | Space between content and border; inherits background |
| Border | Rendered on top of padding |
| Margin | Space outside the border; transparent (no background) |
2. What is the difference between box-sizing: content-box and border-box?
content-box (default): width applies to the content area only. Padding and border are added on top, making the rendered element wider than width.
border-box: width includes content + padding + border. The content area shrinks to fit.
/* content-box: rendered width = 200 + 20*2 + 2*2 = 244px */
.a { box-sizing: content-box; width: 200px; padding: 20px; border: 2px solid; }
/* border-box: rendered width = exactly 200px */
.b { box-sizing: border-box; width: 200px; padding: 20px; border: 2px solid; }
/* Modern reset — apply globally */
*, *::before, *::after { box-sizing: border-box; }
Rule: always use border-box globally. It makes layout math predictable.
3. What is margin collapse?
Vertical margins between adjacent block elements collapse to the larger of the two — they don't add together.
<p style="margin-bottom: 20px;">First</p>
<p style="margin-top: 30px;">Second</p>
<!-- gap between them = 30px, NOT 50px -->
Collapse does not happen when:
- Elements use
display: flexorgrid - A parent has padding, border, or
overflowother thanvisible - Between parent and first/last child (the child's margin "escapes" — use padding on parent instead)
4. What is the difference between padding and margin?
| Property | Space | Background | Collapses? | Clickable area |
|---|---|---|---|---|
| Padding | Inside the border | Yes (inherits) | No | Yes |
| Margin | Outside the border | No (transparent) | Yes (vertical) | No |
Use padding to add internal breathing room; use margin to push elements apart.
Selectors & Specificity
5. How is CSS specificity calculated?
Specificity is a three-number score [a, b, c] where higher beats lower (left-to-right comparison):
| Selector type | Score |
|---|---|
Inline style (style="...") |
[1, 0, 0] |
ID selector (#id) |
[0, 1, 0] |
Class, attribute, pseudo-class (.class, [attr], :hover) |
[0, 0, 1] |
Element, pseudo-element (div, ::before) |
[0, 0, 1] (counts separately as type selectors) |
Universal selector *, combinators, :where() |
[0, 0, 0] |
#nav .item:hover /* [0, 1, 1] = wins over .item:hover [0, 0, 1] */
div.item /* [0, 0, 2] — one element + one class */
!important overrides all specificity but creates maintenance problems — avoid it.
6. What is the difference between :nth-child() and :nth-of-type()?
:nth-child(n)counts all siblings and then checks if the matched element has the correct type.:nth-of-type(n)counts only siblings of the same type.
<div>
<p>A</p> <!-- p:nth-child(1) AND p:nth-of-type(1) -->
<span>B</span>
<p>C</p> <!-- p:nth-child(3) but p:nth-of-type(2) -->
</div>
p:nth-child(2) { color: red; } /* matches nothing — 2nd child is <span> */
p:nth-of-type(2) { color: blue; } /* matches "C" */
7. What does the cascade mean in CSS?
The cascade determines which rule wins when multiple rules target the same element and property. Priority order (highest to lowest):
!importantrules (then specificity among those)- Author styles (highest specificity wins; equal specificity → last rule wins)
- User-agent (browser) styles
Cascade layers (@layer) let you explicitly control this order without fighting specificity.
8. What are :is(), :where(), and :has()?
/* :is() — matches any of the listed selectors; takes specificity of the most specific */
:is(h1, h2, h3) { margin-top: 1.5rem; }
/* :where() — same grouping but ZERO specificity (great for resets) */
:where(h1, h2, h3) { margin-top: 1.5rem; }
/* :has() — "parent selector" — matches elements that CONTAIN the argument */
/* Card with an image gets different padding */
.card:has(img) { padding: 0; }
/* Label before an invalid input */
label:has(+ input:invalid) { color: red; }
| Pseudo | Specificity | Main use |
|---|---|---|
:is() |
Highest of list | Grouping with normal specificity |
:where() |
Zero | Resets, base styles |
:has() |
Argument's specificity | Conditional parent/sibling styling |
Display & Positioning
9. What is the difference between display: inline, block, and inline-block?
| Value | Line break | Width/Height settable | Horizontal margin/padding |
|---|---|---|---|
inline |
No | No | Yes (horizontal only; vertical doesn't push other lines) |
block |
Yes (takes full width) | Yes | Yes |
inline-block |
No | Yes | Yes (both directions) |
10. What is a stacking context?
A stacking context is an element that forms an independent rendering layer. Elements inside it are stacked relative to each other, not to the outside document.
Triggers (common):
positionother thanstatic+z-indexnotautoopacity< 1transform,filter,clip-path,maskisolation: isolatewill-changewith certain properties
/* Without isolation: inner z-index "bleeds" outside */
.modal { z-index: 100; }
/* With isolation: children's z-index is scoped */
.container { isolation: isolate; }
11. How does position work?
| Value | Reference point | Removed from flow? |
|---|---|---|
static |
Normal flow (default) | No |
relative |
Its own normal-flow position | No |
absolute |
Nearest position ≠ static ancestor |
Yes |
fixed |
Viewport | Yes |
sticky |
Normal flow until threshold, then viewport | No |
/* Classic centering with absolute */
.parent { position: relative; }
.child { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); }
12. What is z-index and when does it not work?
z-index controls stacking order within a stacking context. It only works on elements with position other than static (or on flex/grid items).
Common gotcha: if a parent has z-index set, children can never visually escape it — a child with z-index: 9999 will still be beneath a sibling stacking context with z-index: 1.
Flexbox
13. What is the Flexbox axis model?
Flexbox has two axes:
- Main axis — direction of flex item flow (set by
flex-direction) - Cross axis — perpendicular to main axis
.container {
display: flex;
flex-direction: row; /* main = horizontal, cross = vertical */
}
justify-content aligns items along the main axis.align-items aligns items along the cross axis.
14. What is the difference between flex-grow, flex-shrink, and flex-basis?
.item { flex: 1 1 200px; }
/* grow shrink basis */
| Property | Default | Meaning |
|---|---|---|
flex-grow |
0 | How much free space the item takes (ratio) |
flex-shrink |
1 | How much the item shrinks when there's no space |
flex-basis |
auto |
Initial size before growing/shrinking |
Common shortcuts:
flex: 1; /* 1 1 0% — grow equally, shrink, start from 0 */
flex: auto; /* 1 1 auto — grow equally, shrink, use content size */
flex: none; /* 0 0 auto — fixed size, won't grow or shrink */
15. What is the difference between align-content and align-items?
align-itemsaligns items within a single row (on the cross axis)align-contentaligns rows within the container — only matters when there are multiple lines (flex-wrap: wrap)
.container {
display: flex;
flex-wrap: wrap;
height: 400px;
align-items: center; /* centers items within each row */
align-content: center; /* centers the group of rows in the container */
}
16. How do you center an element with Flexbox?
.parent {
display: flex;
justify-content: center; /* horizontal */
align-items: center; /* vertical */
}
Or using margin: auto on the child:
.child { margin: auto; } /* auto margin absorbs all free space in both axes */
17. What does flex-wrap do?
By default (nowrap), flex items shrink to fit on one line. With wrap, items move to a new line when they overflow.
.container {
display: flex;
flex-wrap: wrap; /* wrap to new lines */
gap: 1rem;
}
.item { flex: 1 1 200px; } /* at least 200px wide, grows to fill */
18. What is gap in Flexbox?
gap (formerly grid-gap) sets spacing between flex items — much simpler than margin hacks.
.container {
display: flex;
gap: 16px; /* same in both directions */
gap: 16px 8px; /* row-gap column-gap */
}
Unlike margin, gap does not add space at the outer edges.
CSS Grid
19. What is the difference between grid-template-columns and grid-auto-columns?
grid-template-columnsdefines the explicit grid — columns you name up front.grid-auto-columnsdefines the size of implicit columns — created when items overflow the explicit grid.
.grid {
display: grid;
grid-template-columns: 200px 1fr; /* 2 explicit columns */
grid-auto-columns: 100px; /* any extra columns = 100px */
}
20. What is the difference between auto-fill and auto-fit?
Both create as many columns as fit, but differ when items don't fill all columns:
/* auto-fill: keeps empty columns, doesn't stretch */
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
/* auto-fit: collapses empty columns, stretching existing items */
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
Use auto-fit for responsive cards that stretch to fill the row; auto-fill when you want consistent column widths.
21. What is minmax() and why is it useful?
minmax(min, max) sets a size range for a grid track. It's essential for responsive layouts.
/* Columns are at least 200px wide, can grow to fill space */
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
/* Row is at least 80px, expands to fit content */
grid-template-rows: minmax(80px, auto);
22. How do you create a two-column layout with CSS Grid?
.layout {
display: grid;
grid-template-columns: 250px 1fr; /* sidebar + main */
gap: 2rem;
}
/* Named template areas */
.layout {
grid-template-areas:
"sidebar main"
"sidebar main";
}
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
23. What is subgrid?
subgrid lets a nested grid inherit its parent's track sizes, enabling alignment across nested components.
.parent {
display: grid;
grid-template-columns: 1fr 2fr 1fr;
}
.child {
grid-column: 1 / -1; /* spans all parent columns */
display: grid;
grid-template-columns: subgrid; /* inherits parent's 3 columns */
}
Without subgrid, nested grids define their own tracks independently, making alignment across components difficult.
Responsive design
24. How do media queries work?
Media queries apply styles conditionally based on viewport size, resolution, orientation, or other media features.
/* Mobile first: base styles → add complexity for larger screens */
.card { flex-direction: column; }
@media (min-width: 768px) {
.card { flex-direction: row; }
}
/* Target specific range */
@media (min-width: 600px) and (max-width: 1024px) {
.sidebar { display: none; }
}
/* Prefer dark mode */
@media (prefers-color-scheme: dark) {
body { background: #111; color: #eee; }
}
25. What are container queries?
Container queries apply styles based on the parent container's size rather than the viewport — enabling truly reusable components.
.card-wrapper {
container-type: inline-size; /* enables container queries */
container-name: card;
}
@container card (min-width: 400px) {
.card { flex-direction: row; }
}
Unlike media queries, the same component can use different layouts depending on where it's placed on the page.
26. What is fluid typography?
Fluid typography scales text smoothly between a minimum and maximum size using clamp().
/* min: 1rem, preferred: 2.5vw, max: 1.5rem */
h1 { font-size: clamp(1rem, 2.5vw, 1.5rem); }
clamp(min, preferred, max) avoids needing multiple breakpoints for font sizes.
27. What is the viewport unit and when would you use it?
| Unit | Meaning |
|---|---|
vw |
1% of viewport width |
vh |
1% of viewport height |
svh |
1% of small viewport height (excludes mobile browser chrome) |
dvh |
1% of dynamic viewport height (updates as chrome shows/hides) |
vmin |
1% of the smaller dimension |
vmax |
1% of the larger dimension |
Use dvh for full-screen mobile layouts (avoids the classic iOS "100vh too tall" bug).
Animations & transitions
28. What is the difference between transition and animation?
| Feature | transition |
animation |
|---|---|---|
| Trigger | State change (hover, class toggle) | Runs automatically or on class |
| Keyframes | No (start → end only) | Yes (@keyframes) |
| Loop | No | Yes (animation-iteration-count) |
| Direction | No | Yes (alternate, reverse) |
| JavaScript control | Via class toggle | Via animation-play-state |
/* Transition — two states */
.btn { background: blue; transition: background 0.3s ease; }
.btn:hover { background: darkblue; }
/* Animation — full control */
@keyframes pulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.05); }
}
.btn { animation: pulse 1.5s ease-in-out infinite; }
29. What is will-change and when should you use it?
will-change hints to the browser that a property will animate, allowing GPU layer promotion in advance.
/* Use just before the animation, not permanently */
.element { will-change: transform, opacity; }
Caution: using it on everything wastes GPU memory. Apply it conditionally (via JS on hover/focus) and remove it after the animation.
30. What CSS properties can be animated cheaply?
Only transform and opacity can animate without triggering layout or paint — they run entirely on the GPU compositor thread.
| Expensive (causes layout/paint) | Cheap (compositor only) |
|---|---|
width, height, top, left |
transform: translateX() |
margin, padding |
transform: scale() |
background-color |
opacity |
box-shadow |
filter (most cases) |
Always prefer transform: translate() over animating left/top.
31. How does animation-fill-mode work?
Controls element style before/after the animation runs.
| Value | Before animation | After animation |
|---|---|---|
none |
Original styles | Original styles |
forwards |
Original styles | Last keyframe |
backwards |
First keyframe | Original styles |
both |
First keyframe | Last keyframe |
.fade-in {
animation: fadeIn 0.5s ease forwards; /* stays visible after */
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
CSS custom properties (variables)
32. How do CSS custom properties work?
Custom properties (CSS variables) store reusable values. They cascade and inherit like regular properties.
:root {
--color-primary: #3b82f6;
--spacing-base: 8px;
}
.btn {
background: var(--color-primary);
padding: calc(var(--spacing-base) * 1.5);
}
/* Fallback value */
color: var(--color-accent, #ff0000);
33. How can you update CSS variables with JavaScript?
// Read
const value = getComputedStyle(document.documentElement)
.getPropertyValue('--color-primary');
// Write
document.documentElement.style.setProperty('--color-primary', '#ef4444');
// Scoped to an element
document.querySelector('.card').style.setProperty('--card-bg', '#f8f9fa');
This enables dynamic theming, dark/light mode toggles, and per-component overrides.
34. What is the difference between CSS custom properties and preprocessor variables (SCSS)?
| Feature | CSS custom properties | SCSS variables |
|---|---|---|
| Runtime | Yes — change with JS or cascade | No — compiled away |
| Inheritance | Yes — cascade through DOM | No |
| Media queries | Can change value inside @media |
Only at compile time |
| Scope | DOM-based (:root, element) |
Lexical (block scope) |
| Browser support | All modern browsers | Requires build step |
Typography & colors
35. What is the difference between em and rem?
em— relative to the current element's font-size (or parent's, for font-size itself). Compounds through nesting.rem— relative to the root (<html>) element's font-size. Predictable everywhere.
html { font-size: 16px; }
.parent { font-size: 1.5em; } /* 24px */
.child { font-size: 1.5em; } /* 36px (1.5 × 24) — compounds! */
.child-rem { font-size: 1.5rem; } /* always 24px regardless of nesting */
Rule: use rem for font sizes and spacing; em for component-relative values (like padding that should scale with the component's font-size).
36. How does line-height work?
line-height sets the height of a line box. The line-height gap (leading) is distributed equally above and below the text.
/* Unitless — recommended — multiplied by the element's font-size */
p { line-height: 1.6; }
/* px — fixed, doesn't scale with font-size */
p { line-height: 24px; }
/* em — relative, but "locks in" at current font-size */
p { line-height: 1.6em; }
Prefer unitless line-height so it scales correctly when font-size changes (e.g., at breakpoints or for accessibility zoom).
Performance & best practices
37. What is critical CSS?
Critical CSS (above-the-fold CSS) is the minimum CSS required to render the visible portion of the page without additional network requests. Inlining it in <style> tags eliminates a render-blocking stylesheet request.
<head>
<!-- Critical CSS inlined -->
<style>.hero { ... } nav { ... }</style>
<!-- Non-critical loaded asynchronously -->
<link rel="preload" href="main.css" as="style" onload="this.rel='stylesheet'">
</head>
38. What causes layout reflow (reflow/repaint)?
- Reflow (layout): changing geometry (width, height, position, font-size). Expensive — triggers layout recalculation for the element and its descendants.
- Repaint: changing visual properties (color, background, box-shadow) without geometry change. Less expensive.
- Composite: only
transform/opacitychanges. Cheapest — runs on the GPU thread.
// BAD: forces multiple reflows
el.style.width = '100px';
const h = el.offsetHeight; // forces reflow to read
el.style.height = h + 'px';
// GOOD: batch reads then writes, or use requestAnimationFrame
39. What is specificity hell and how do you avoid it?
Specificity hell is when selectors escalate in complexity (#nav .list > li:first-child a.active) to override each other, making CSS brittle.
Solutions:
- Use low-specificity utility classes (Tailwind) or BEM naming
- Use
@layerto control cascade order without fighting specificity - Avoid IDs in CSS selectors
- Avoid
!important(except in utility overrides)
/* BEM: predictably low specificity */
.card { }
.card__title { }
.card--featured { }
/* @layer: explicit priority without high specificity */
@layer base, components, utilities;
@layer utilities { .mt-4 { margin-top: 1rem; } }
40. What is the @layer rule?
@layer establishes explicit cascade layers. Lower-priority layers never beat higher-priority ones, regardless of specificity.
@layer reset, base, components, utilities;
@layer reset {
* { box-sizing: border-box; margin: 0; }
}
@layer base {
a { color: blue; } /* specificity [0,0,1] */
}
@layer utilities {
.text-red { color: red; } /* specificity [0,0,1] — but wins because layer is higher priority */
}
Unlayered styles always beat layered styles.
Modern CSS
41. What is logical properties and why use them?
Logical properties use writing-mode-relative directions (start/end) instead of physical (left/right). They're essential for internationalization (RTL, vertical writing modes).
/* Physical */
.box { margin-left: 1rem; padding-right: 1rem; }
/* Logical equivalents */
.box { margin-inline-start: 1rem; padding-inline-end: 1rem; }
| Physical | Logical |
|---|---|
margin-top |
margin-block-start |
margin-bottom |
margin-block-end |
margin-left |
margin-inline-start |
margin-right |
margin-inline-end |
width |
inline-size |
height |
block-size |
42. What is aspect-ratio?
aspect-ratio sets the preferred width-to-height ratio of an element, without needing the old padding-top hack.
/* Modern */
.video-wrapper { aspect-ratio: 16 / 9; width: 100%; }
/* Old hack (still needed for very old browsers) */
.video-wrapper { position: relative; padding-top: 56.25%; }
.video-wrapper iframe { position: absolute; inset: 0; }
43. What is inset shorthand?
inset is shorthand for top right bottom left (same syntax as margin/padding).
/* Old */
.overlay { top: 0; right: 0; bottom: 0; left: 0; }
/* Modern */
.overlay { inset: 0; }
/* Directional */
.toast { inset: auto 1rem 1rem auto; } /* no top offset, 1rem from right and bottom */
44. What is scroll-behavior and scroll-snap?
/* Smooth scrolling when following anchor links */
html { scroll-behavior: smooth; }
/* Snap scrolling — items snap to positions */
.carousel {
overflow-x: scroll;
scroll-snap-type: x mandatory;
}
.carousel-item {
scroll-snap-align: start;
flex: 0 0 100%;
}
45. What is the color-scheme property?
color-scheme tells the browser which color schemes an element supports, so browser-native controls (scrollbars, inputs, buttons) render correctly in dark mode.
:root { color-scheme: light dark; } /* supports both */
/* Force dark across the whole page */
:root { color-scheme: dark; }
Pair with @media (prefers-color-scheme: dark) to provide custom dark styles.
Advanced topics
46. What is the difference between visibility: hidden and display: none?
| Property | Takes up space? | Accessible? | Animatable? |
|---|---|---|---|
display: none |
No | No (removed from a11y tree) | No |
visibility: hidden |
Yes | No (invisible but present) | Yes (via transition) |
opacity: 0 |
Yes | Yes (still in a11y tree!) | Yes |
Use opacity: 0 + pointer-events: none + aria-hidden="true" for animatable hide with full accessibility control.
47. What is CSS content property used for?
content is used with ::before and ::after pseudo-elements to insert generated content.
/* Icon via content */
.external-link::after { content: " ↗"; }
/* Counter */
ol { counter-reset: item; }
ol li::before { content: counter(item) ". "; counter-increment: item; }
/* Attribute value */
a[href]::after { content: " (" attr(href) ")"; }
/* Empty (required for pseudo-elements to render) */
.clearfix::after { content: ""; display: block; clear: both; }
48. What is currentColor?
currentColor is a CSS keyword that evaluates to the element's computed color value. Useful for keeping icon colors or borders in sync with text.
.icon {
color: #3b82f6;
border: 2px solid currentColor; /* same blue as text */
fill: currentColor; /* SVG fill follows text color */
}
.icon:hover { color: #1d4ed8; } /* border and fill update automatically */
49. What is the isolation property?
isolation: isolate creates a new stacking context without setting z-index, opacity, or transform. This scopes z-index to children without affecting siblings.
/* Modal stacking is scoped — won't affect page z-index */
.modal-container { isolation: isolate; }
.modal { z-index: 1000; } /* only competes with siblings inside .modal-container */
50. What are common CSS performance pitfalls?
| Pitfall | Better alternative |
|---|---|
Animating width/height/top/left |
transform: scale()/translate() |
Universal selector (*) in complex rules |
Scope with a class |
| Deep descendant selectors | BEM classes |
box-shadow on animated elements |
Static shadow + opacity animated shadow |
| Large images without lazy loading | loading="lazy" + srcset |
Using @import in CSS |
<link> tags (loads in parallel) |
| Unused CSS shipped to browser | PurgeCSS / Tailwind safelist |
/* WRONG: forces layout on every frame */
@keyframes bad { to { width: 200px; } }
/* GOOD: compositor-only */
@keyframes good { to { transform: scaleX(1.5); } }
Common mistakes
| Mistake | Fix |
|---|---|
z-index not working |
Check position is not static; check stacking context |
| Margin collapse surprise | Use padding on parent or display: flex |
100vh too tall on mobile |
Use 100dvh or min-height: -webkit-fill-available |
| Flexbox items won't shrink | Add min-width: 0 (default min-width is content width) |
| CSS variable not inheriting | Ensure it's defined on :root or a parent in the DOM |
| Pseudo-element not visible | Missing content: "" or display: block |
gap not working |
Confirm parent is display: flex or grid |
:hover not firing on iOS |
Add cursor: pointer to the element |
CSS vs preprocessors quick comparison
| Feature | CSS | SCSS | Less |
|---|---|---|---|
| Variables | Custom properties (runtime) | $var (compile-time) |
@var (compile-time) |
| Nesting | Yes (native, &) |
Yes | Yes |
| Mixins | No | @mixin / @include |
.mixin() |
| Functions | calc(), clamp(), etc. |
Custom @function |
Built-in functions |
| Build step | No | Yes | Yes |
| Cascade layer | @layer |
Via output CSS | Via output CSS |
Modern CSS has closed much of the gap — custom properties, native nesting, @layer, and clamp() cover most preprocessor use cases.
FAQ
Q: Is CSS Turing complete?
A: Not on its own, but CSS + HTML (with checkboxes as state) can simulate some logic. In practice, use JavaScript for complex interactivity.
Q: What is the difference between flex: 1 and flex: 1 1 0?
A: They're the same. flex: 1 expands to flex-grow: 1; flex-shrink: 1; flex-basis: 0% — items start from 0 and grow proportionally.
Q: When should I use Grid vs Flexbox?
A: Flexbox = one-dimensional (a row or column). Grid = two-dimensional (rows and columns together). Flexbox is content-driven; Grid is layout-driven. You can nest them freely.
Q: Why does height: 100% not work?
A: The parent must have an explicit height for percentage heights to resolve. Use min-height: 100vh on body or use Flexbox/Grid on the parent instead.
Q: What's the best way to center something in CSS in 2025?
A: display: flex; justify-content: center; align-items: center; on the parent. For a single element with a known parent, margin: auto in a flex container also works elegantly.
Q: Does CSS load order matter?
A: Yes — when two rules have equal specificity, the last one wins. <link> tags are loaded in DOM order; stylesheets loaded later can override earlier ones.