CSS Interview Questions & Answers
These are the CSS questions that come up again and again in front-end interviews, at every level from junior screens to staff-level system design chats. Each answer is written to be said out loud, not just recognized — the goal is being able to explain why, not just name the right keyword.
1. What is the CSS box model?
Every element is a rectangular box made of four layers, from the inside out: content, padding, border, and margin. width/height size the content box by default; box-sizing: border-box (see box-sizing) changes that so width/height include padding and border too, which is why almost every modern reset sets it globally.
2. How is specificity calculated?
Specificity is a 3-part tuple, most significant first: (a) ID selectors, (b) classes/attributes/pseudo-classes, (c) type selectors/pseudo-elements. Compare left to right — more IDs always beats any number of classes, more classes always beats any number of type selectors. Inline styles outrank all of it, and !important outranks everything (see Specificity and Calculating Specificity).
#nav a.active /* (1, 1, 1) */ .nav .link:hover /* (0, 2, 0) */ ul li a /* (0, 0, 3) */ /* #nav a.active wins regardless of source order */
3. Inline vs block vs inline-block?
Block | Inline | Inline-block | |
|---|---|---|---|
Starts new line | Yes | No | No |
Respects width/height | Yes | No | Yes |
Respects vertical margin/padding | Yes | Visually only | Yes |
Example element |
|
|
|
4. What are the position values and how do they differ?
static— default, no offsets apply, follows normal flow.relative— stays in flow, offsets shift it visually from where it would have been, and it creates a positioning context for absolute children.absolute— removed from flow, positioned relative to the nearest positioned (non-static) ancestor, or the viewport.fixed— removed from flow, positioned relative to the viewport, ignores scrolling (unless an ancestor has atransform/filter/will-change, which creates a new containing block).sticky— a hybrid: acts relative until a scroll threshold, then acts fixed within its containing block.
5. Flexbox vs Grid — how do you choose?
Flexbox is one-dimensional — it distributes space along a single axis (row or column) and excels at content-driven sizing: nav bars, button groups, anything where item count varies. Grid is two-dimensional — you define rows and columns together, which suits page-level and card layouts where alignment across both axes matters. Rule of thumb: if you find yourself nesting flex containers to fake a grid, switch to Grid.
6. What is a Block Formatting Context (BFC)?
A BFC is an isolated rendering region where floats and margins don't interact with anything outside it. Elements establish a new BFC via overflow: hidden/auto, display: flow-root, float, position: absolute/fixed, or contain: layout. Two classic uses: containing floated children (clearfix) and preventing margin collapse between a parent and its first/last child.
7. What is a stacking context, and how does z-index actually work?
z-index only compares elements within the same stacking context — it does not compare globally. A new stacking context is created by, among others, any positioned element with a z-index other than auto, any element with opacity < 1, a transform, filter, or will-change. A child with z-index: 9999 can still render behind a sibling's box if that sibling's parent created a stacking context first — the child is trapped inside its own parent's stack (see Stacking Contexts).
8. Pseudo-class vs pseudo-element — what's the difference?
A pseudo-class (single colon,
:hover,:nth-child(),:focus) selects an element in a particular state or position — no new content, no new box.A pseudo-element (double colon,
::before,::after,::first-line) targets a sub-part of an element or generates a new, styleable box that did not exist in the DOM.Single-colon
:before/:afterstill work for legacy reasons, but the double-colon form is the modern, correct syntax.
9. rem vs em — when do you use each?
em is relative to the font-size of the current element (or its parent's, for font-size itself), so it compounds when nested — three nested 1.2em elements multiply to 1.728x. rem is always relative to the root <html> font-size, so it never compounds. Use rem for predictable global sizing (spacing, most font sizes); reach for em when a value should scale with its own element's font-size, like padding on a button that should grow with its own text.
10. Transitions vs animations?
A transition interpolates between two states — it needs a state change (hover, class toggle, media query) to trigger, and it always runs once, forward or backward. An animation is defined declaratively with @keyframes, runs on its own (no trigger required), can loop, reverse, and pass through multiple named stops rather than just a start and end.
11. What does will-change do, and when should you avoid it?
will-change (see will-change) hints to the browser that a property is about to change so it can promote the element to its own compositor layer ahead of time, avoiding a layout/paint hitch at the start of an animation. It costs memory per layer, so applying it broadly (or leaving it on permanently) can hurt performance more than it helps — add it just before the animation starts, remove it once done.
12. What is critical CSS?
The minimal CSS needed to render above-the-fold content, inlined directly in <head> so the browser can paint without waiting on an external stylesheet round-trip. The rest of the CSS loads asynchronously (or deferred). It trades a slightly larger HTML payload for a much faster first paint, at the cost of extra build tooling to extract and maintain that critical subset (see Critical CSS).
13. What are container queries, and how do they differ from media queries?
A media query responds to the viewport; a container query (@container, see Container Queries) responds to the size of a containing element that has been declared a query container via container-type. This makes components truly reusable — a card can style itself based on the width of whatever column/sidebar it's dropped into, not the whole page width.
14. What are cascade layers?
@layer (see Cascade Layers) lets you group rules into named layers with an explicit priority order, independent of specificity or source order within a layer. A low-specificity selector in a later layer still loses to any selector in an earlier layer — layers are compared before specificity is ever consulted. This is how large teams keep reset/base/components/utilities from fighting each other with specificity wars.
15. What's the difference between visibility: hidden and display: none?
display: none | visibility: hidden | |
|---|---|---|
Occupies layout space | No | Yes |
Removed from accessibility tree | Yes | Yes |
Can be transitioned | No (discrete) | Yes |
Children can override | No | Yes, via |
More rapid-fire questions
What is the difference between
:is()and:where()? Both group selectors, but:where()always contributes zero specificity while:is()takes the specificity of its most specific argument.How does
:has()differ from other pseudo-classes? It matches a parent based on its descendants — the first "parent selector" native CSS has ever had.What triggers a reflow vs a repaint? Changing geometry (
width,top) triggers layout (reflow) then paint; changing only visual properties (color,background) skips layout and goes straight to paint;transform/opacitychanges can skip both and go straight to compositing.What is the difference between
min-content,max-content, andfit-content?min-contentis the smallest a box can be without overflowing (usually the longest unbreakable word);max-contentis the width the content would take with no wrapping at all;fit-contentclamps between the two, using available space up tomax-content.Why does
margin: autocenter a block element horizontally but not vertically? Because auto margins absorb available space along the axis being solved by the block-level layout algorithm, and historically that only resolved horizontally for block boxes; flexbox and grid extendmargin: autocentering to both axes.What is the difference between
overflow: hiddenandoverflow: clip? Both hide overflow, butclipdisallows scrolling entirely (even programmatically) and does not establish a new formatting context the wayhiddendoes.
Related pages: Specificity, Stacking Contexts, Flexbox vs Grid, Cascade Layers, and the CSS Cheat Sheet.