Master these 31 carefully curated interview questions to ace your next Css interview.
Every element is a box: content, padding, border, margin. box-sizing: border-box includes padding/border in width.
Layers: content, padding, border, margin. Default content-box: width applies to content only. border-box: width includes padding and border. Margin collapsing: adjacent vertical margins overlap. Use box-sizing: border-box globally.
Specificity determines which rule wins: inline > ID > class > element. Higher specificity overrides lower.
Calculated as (a,b,c,d): inline styles, ID selectors, class/attribute/pseudo-class, element/pseudo-element. !important overrides all. Equal specificity: last rule wins. Universal (*) adds no specificity.
Flexbox is a one-dimensional layout for rows or columns with flexible sizing: justify-content, align-items, flex-grow/shrink.
Container: display:flex. Direction: flex-direction. Alignment: justify-content (main axis), align-items (cross axis). Item sizing: flex-grow, flex-shrink, flex-basis. Shorthand: flex:1. Use for navbars, centering, card layouts.
CSS Grid is a two-dimensional layout system with rows and columns: grid-template-columns, grid-template-rows, gap.
Container: display:grid. Tracks: grid-template-columns: 1fr 2fr, repeat(), minmax(). Placement: grid-column, grid-row, grid-area. Named areas: grid-template-areas. Use for page layouts, dashboards, complex responsive grids.
static (default), relative (offset from normal), absolute (to positioned ancestor), fixed (to viewport), sticky (hybrid).
static: normal flow. relative: offset but stays in flow, creates positioning context. absolute: removed from flow, positioned to nearest positioned ancestor. fixed: positioned to viewport. sticky: normal until scroll threshold, then fixed. z-index works only on positioned elements.
CSS variables (--name: value) store reusable values, support inheritance, and can be changed with JavaScript at runtime.
Declaration: --primary: #04AA6D on :root. Usage: var(--primary, fallback). Benefits: design tokens, live runtime changes via JS, media query overrides for themes. Dark mode: prefers-color-scheme media query to swap variables.
Transitions animate between two states; animations define multi-step sequences with @keyframes for complex motion.
Transitions: transition: property duration timing-function delay. Animations: @keyframes with multiple stops (0%, 50%, 100%). Performance: animate transform and opacity (GPU-accelerated). Use will-change sparingly.
Container queries style elements based on parent container size rather than viewport, enabling truly responsive components.
container-type: inline-size on parent; @container (min-width: 400px) {} on children. Unlike media queries, responds to component's actual available space. Supported in all modern browsers. Paradigm shift for responsive component design.
CSS-in-JS writes styles in JavaScript (styled-components, Emotion), enabling scoped styles and dynamic values with runtime cost.
Benefits: scoped styles, dynamic styling, colocation with components. Drawbacks: runtime cost, larger bundle. Alternatives: CSS Modules (no runtime), Tailwind CSS, vanilla CSS with BEM. Trend: zero-runtime solutions (vanilla-extract, Panda CSS).
Mobile-first with fluid layouts, relative units (rem, vw), media queries, responsive images (srcset), and container queries.
Strategy: (1) Mobile-first base styles. (2) Fluid typography: clamp(). (3) Flexbox/Grid with fr units. (4) Responsive images: srcset, picture. (5) Content-based breakpoints. (6) Touch-friendly targets (48px). (7) Real device testing.
CSS scroll-driven animations, IntersectionObserver, GPU-accelerated transforms, and carefully optimized images.
Techniques: scroll-timeline for scroll-linked animations, IntersectionObserver for viewport-triggered effects, transform: translateZ(0) for GPU, will-change, position: sticky, optimized WebP images, minimal JS, prefers-reduced-motion support.
The box model defines every element as a rectangular box with content, padding, border, and margin areas.
Content: the actual content area (text, images). Padding: space between content and border (background-color applies). Border: surrounds padding (width, style, color). Margin: space outside the border (transparent, can collapse vertically). box-sizing: content-box (default, width = content only) vs border-box (width includes padding + border — much easier to work with). Always set *, *::before, *::after { box-sizing: border-box }. Inspect with DevTools box model visualization.
Padding is space inside the border around content; margin is space outside the border between elements.
Padding: inside the element, affected by background-color, increases element size (in content-box), cannot be negative, no collapsing. Margin: outside the element, always transparent, can be negative (overlapping), vertical margins collapse (larger wins), auto margin for centering. Margin collapse: two adjacent vertical margins merge into one (max value). Padding for internal spacing (buttons, cards). Margin for external spacing between elements. Use gap property in flexbox/grid instead of margins.
Specificity determines which CSS rules win when multiple rules target the same element, calculated as (inline, id, class, element).
Specificity weight: inline styles (1000) > ID selectors (100) > class/attribute/pseudo-class (10) > element/pseudo-element (1). Example: #nav .item a = 0,1,1,1 (111). !important overrides all specificity (avoid it). Equal specificity: last rule wins. Universal selector (*) has 0 specificity. :not() doesn't add specificity itself, but its argument does. :is() and :where() differ: :is() uses highest argument specificity, :where() has zero specificity. Best practice: keep specificity low, use classes.
Flexbox is a one-dimensional layout model for distributing space and aligning items along a row or column.
Container (display: flex): flex-direction (row/column), justify-content (main axis: center, space-between, space-around), align-items (cross axis: center, stretch, flex-start), flex-wrap, gap. Items: flex-grow (expand ratio), flex-shrink (shrink ratio), flex-basis (initial size), align-self (override alignment), order (visual reorder). Shorthand: flex: 1 1 0% (grow, shrink, basis). Use for: navigation, card layouts, centering, equal-height columns. Main axis follows flex-direction; cross axis is perpendicular.
Grid is a two-dimensional layout system for rows and columns simultaneously; Flexbox handles one dimension at a time.
Grid: display: grid, grid-template-columns/rows, grid-template-areas for named regions, fr unit for fractional space. Item placement: grid-column, grid-row, span. auto-fill/auto-fit with minmax() for responsive grids. Use Grid for: page layouts, complex 2D arrangements. Use Flexbox for: component layouts, single row/column alignment. They work together: Grid for page structure, Flexbox for component internals. Grid gap = Flexbox gap. Grid is content-out (define structure), Flexbox is content-in (items determine flow).
Transitions animate between two states on trigger (hover); animations run keyframe sequences automatically without triggers.
Transitions: property, duration, timing-function, delay. Triggered by state change (hover, focus, class toggle). Only start-to-end. transition: all 0.3s ease. Animations: @keyframes with from/to or percentages. Can loop (animation-iteration-count: infinite), reverse, pause. animation: name 2s ease-in-out infinite alternate. Animations run automatically; transitions need triggers. Performance: transform and opacity are GPU-accelerated (composite layer). will-change hints browser for optimization. prefers-reduced-motion media query for accessibility.
CSS Variables (--name) store reusable values, are inherited, can be updated with JavaScript, and enable dynamic theming.
Define: --primary: #04AA6D on :root (global) or any selector (scoped). Use: color: var(--primary, fallback). Inherited by children. Dynamic: JavaScript can update via element.style.setProperty('--primary', '#ff0'). Use cases: theming (dark/light mode), responsive values, component variants. Unlike preprocessor variables (Sass $var), CSS Variables are live in the browser — changes propagate instantly. Scope: defined on element, available to descendants. Can compute: calc(var(--spacing) * 2). Media queries can change values.
static: normal flow. relative: offset from normal position. absolute: relative to positioned ancestor. fixed: relative to viewport. sticky: hybrid.
static: default, no special positioning. relative: offset from its normal position, still occupies original space. absolute: removed from flow, positioned relative to nearest positioned ancestor (not static). fixed: removed from flow, positioned relative to viewport, stays during scroll. sticky: acts as relative until scroll threshold, then acts as fixed (position: sticky; top: 0). z-index only works on positioned elements (not static). Stacking context: created by positioned elements with z-index, opacity < 1, transform, etc.
Container queries allow elements to respond to their parent container's size instead of the viewport, enabling truly reusable components.
Define container: container-type: inline-size (or size). container-name: sidebar. Query: @container sidebar (min-width: 400px) { .card { flex-direction: row } }. Unlike media queries (viewport-based), container queries make components self-contained — they adapt to wherever they're placed. Container query units: cqw, cqh, cqi, cqb (container width/height/inline/block). Enable component-driven responsive design. @container style queries: respond to custom property values. Supported in all modern browsers since 2023.
Cascade layers (@layer) give explicit control over CSS specificity order, eliminating specificity wars between stylesheets.
@layer order declaration: @layer reset, base, components, utilities. Layers defined first have lower priority regardless of specificity within them. Unnamed styles have higher priority than any named layer. !important reverses layer order. Use: @layer base { ... } or @import url('lib.css') layer(vendor). Benefits: third-party CSS in low-priority layer, utility classes always win, no need for !important hacks. Replace BEM/ITCSS architecture patterns. Combine with @scope for perfect style encapsulation.
Use prefers-color-scheme media query with CSS custom properties to toggle color themes based on OS settings.
Approach: (1) Define color tokens as CSS variables: :root { --bg: #fff; --text: #000 }. (2) Dark variant: @media (prefers-color-scheme: dark) { :root { --bg: #1a1a1a; --text: #fff } }. (3) Manual toggle: [data-theme='dark'] { --bg: ... }. (4) JavaScript: matchMedia('(prefers-color-scheme: dark)'). Store preference: localStorage, cookie. color-scheme: light dark meta tag tells browser to style scrollbars, form controls. Semantic color naming (--bg-primary vs --white) makes theming easier.
Use CSS Grid with auto-fill/minmax, Flexbox with flex-wrap, clamp() for fluid typography, and container queries.
Techniques: (1) Grid: grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)) — cards automatically wrap. (2) Flexbox: flex: 1 1 300px with flex-wrap: wrap. (3) Fluid typography: font-size: clamp(1rem, 2.5vw, 2rem). (4) min()/max()/clamp() for widths: width: min(90%, 1200px). (5) aspect-ratio for responsive embeds. (6) Container queries for component-level responsiveness. (7) CSS logical properties (inline-size vs width) for internationalization. These create 'intrinsic' responsive designs that adapt naturally.
Remove unused CSS with PurgeCSS, split critical/non-critical CSS, minify, use efficient selectors, and adopt modern features.
Steps: (1) PurgeCSS/UnCSS — remove unused rules (can reduce 90%+). (2) Extract critical CSS (above-fold) inline in <head>. (3) Lazy load non-critical CSS: <link rel='preload' as='style'>. (4) Minify with cssnano. (5) Combine media queries. (6) Avoid deep nesting (div > div > div > span — slow). (7) Use shorthand (margin: 10px vs margin-top/right/bottom/left). (8) Replace large libraries with custom CSS. (9) CSS containment: contain: layout for performance. (10) Audit with Chrome Coverage tab to find unused CSS.
Animate only transform and opacity properties, use will-change for GPU acceleration, and prefer CSS animations over JavaScript.
Performance: transform and opacity are composited by GPU (no layout/paint). Avoid animating: width, height, top, left, margin, padding (trigger layout recalculation). will-change: transform triggers GPU layer creation (use sparingly). requestAnimationFrame for JS animations. @keyframes for complex sequences. transition for simple state changes. cubic-bezier() for custom easing. animation-fill-mode: forwards retains end state. Accessibility: @media (prefers-reduced-motion: reduce) { * { animation: none !important } }.
CSS-in-JS writes styles in JavaScript (styled-components, Emotion), offering scoping and dynamic styles at the cost of runtime overhead.
Benefits: automatic scoping (no class conflicts), dynamic styles based on props, colocated with components, TypeScript support, dead code elimination. Drawbacks: runtime overhead (generating/injecting styles), larger JS bundle, learning curve, harder to debug (generated class names). Alternatives: CSS Modules (scoped, zero runtime), Tailwind (utility-first), vanilla-extract (zero-runtime CSS-in-TS). Trend: moving away from runtime CSS-in-JS toward zero-runtime solutions. Airbnb migrated from CSS-in-JS to static extraction.
Use BEM naming convention, CSS Modules for scoping, cascade layers for priority, and avoid ID selectors and !important.
Strategies: (1) BEM: .block__element--modifier naming prevents conflicts. (2) CSS Modules: locally scoped class names (hash-based). (3) @layer: explicit priority ordering. (4) Low-specificity selectors: single class selectors only. (5) No ID selectors in CSS. (6) No !important (except utility overrides). (7) Utility-first (Tailwind) eliminates specificity concerns. (8) CSS-in-JS auto-scoping. (9) @scope rule for native scoping. (10) Linting: stylelint with max-specificity rules. Code review: catch specificity violations early.
Pseudo-classes select elements based on state (:hover, :focus); pseudo-elements style parts of elements (::before, ::after).
Pseudo-classes: :hover, :focus, :active (interaction), :nth-child(), :first-child, :last-child (structural), :not(), :is(), :where(), :has() (functional), :empty, :checked, :disabled (state). Pseudo-elements: ::before, ::after (content injection), ::first-line, ::first-letter, ::selection, ::placeholder, ::marker. ::before/::after require content property. Single colon (:) for classes, double (::) for elements (CSS3), but single colon works for legacy (IE8). :has() is the parent selector — .card:has(img) targets cards containing an image.
display controls how an element renders: block, inline, inline-block, flex, grid, none, and contents.
block: full width, new line (div, p, h1). inline: width of content, no line break, ignores height/width (span, a). inline-block: inline flow but respects width/height. flex: flex container. grid: grid container. none: removes from layout. contents: element disappears but children remain. inline-flex, inline-grid: inline-level containers. list-item: renders with bullet marker. table, table-row, table-cell: table layout. flow-root: creates new block formatting context (clears floats). visibility: hidden differs from display: none — hides but keeps space.
Use flexbox (display: flex; justify-content: center; align-items: center) or grid (display: grid; place-items: center).
Modern methods: (1) Flexbox: parent { display: flex; justify-content: center; align-items: center; min-height: 100vh }. (2) Grid: parent { display: grid; place-items: center }. (3) Grid shorthand: child { margin: auto } in grid container. (4) position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) — works without flexbox. (5) margin: 0 auto — horizontal only for block elements with width. Flexbox/Grid methods are preferred — cleaner, more maintainable. Avoid: table-cell vertical alignment (legacy technique).
Ready to master Css?
Start learning with our comprehensive course and practice these questions.