Toolmingo
Guides21 min read

50 CSS Interview Questions (With Answers)

Top CSS interview questions with clear answers and code examples — covering the box model, specificity, Flexbox, Grid, animations, responsive design, and modern CSS features.

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: flex or grid
  • A parent has padding, border, or overflow other than visible
  • 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):

  1. !important rules (then specificity among those)
  2. Author styles (highest specificity wins; equal specificity → last rule wins)
  3. 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):

  • position other than static + z-index not auto
  • opacity < 1
  • transform, filter, clip-path, mask
  • isolation: isolate
  • will-change with 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 positionstatic 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-items aligns items within a single row (on the cross axis)
  • align-content aligns 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-columns defines the explicit grid — columns you name up front.
  • grid-auto-columns defines 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/opacity changes. 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 @layer to 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.

Related tools

Keep reading

All Toolmingotools are free & run in your browser

No sign-up, no upload, no watermark. Your files never leave your device.

Browse all tools