123 CSS interview questions with detailed answers, sorted from basic to advanced. Free to practice, with progress saved automatically.
CSS controls how web pages are presented, from colour and spacing to layouts that adapt to the screen. Questions cover the box model, selectors and the cascade, display and position, Flexbox and Grid, responsive design, modern features such as :has and logical properties, BEM-style organisation, and performance topics like critical CSS.
and 34 more topics.
The cascade is the algorithm that picks a winning value when several declarations target the same property on the same element. The order it checks, top down — it stops as soon as one step decides: 1. Origin and !important: the browser's default styles lose…
Some CSS properties flow down to descendants automatically; the rest do not. Inherited Not inherited ------ color, font-, line-height, letter-spacing margin, padding, border, background text-align, visibility, cursor, list-style width, height, display, position Rule of thumb: text properties inherit, box properties do not. Four controlling keywords:…
Three groups, split by what the value is relative to. Unit Anchored to Risk --------- px nothing ignores the user's font-size setting em the current element's font-size compounds through nesting rem the <html font-size stable and predictable % the parent element depends on which property…
!important moves a declaration into a separate priority bucket that outranks any specificity within the same origin. Why avoid it: overriding an !important takes another !important — with higher specificity, or equal specificity placed later (with @layer the order flips: an !important in an earlier-declared…
:has() is the parent selector — it matches an element based on what it contains. CSS could not express this before; you had to add a class from JS. Its specificity comes from the strongest selector inside (like :is()), not zero as with :where(). Support:…
Four combinators describe the relationship between two elements: Symbol Name Relationship --------- space descendant any depth below child direct child + adjacent sibling the next sibling ~ general sibling all later siblings The most common real use is + for spacing between consecutive items: Note:…
Every element is a box of four layers, inside out: content → padding → border → margin. Margin differs from the other three layers in three ways: it sits outside the border, it is always transparent (no background), and it collapses vertically with adjacent margins.…
The difference is what width is measuring. content-box border-box --------- width includes content only content + padding + border Adding padding the element grows the content shrinks Margin excluded in both excluded in both The line nearly every project carries: Why border-box is easier: when…
When two vertical margins touch, the browser merges them into one and keeps the larger value instead of adding them. Three situations where it happens: It does not happen with: horizontal margins, flex items, grid items, or absolutely/fixed positioned elements. An element that establishes a…
position decides whether an element stays in normal flow, and what top/right/bottom/left are measured against. Value Still occupies space Anchored to --------- static yes — relative yes (original slot kept) itself absolute no nearest ancestor with position != static fixed no the viewport sticky yes…
sticky behaves as relative until it reaches a threshold, then behaves as fixed within its parent. Three conditions, all mandatory: 1. At least one of top/right/bottom/left. 2. No ancestor with overflow: hidden auto scroll — if there is one, it sticks inside that scroll box…
z-index sets the stacking order, but it only compares elements inside the same stacking context. Two ways for z-index to apply: the element has position other than static, or it is a flex/grid item (where z-index works without positioning). Why z-index: 9999 can still sit…
A stacking context is an independent stacking group: z-index comparisons happen only inside it, and the whole group is stacked as a single unit against the outside world. What creates one: - the root <html element - position: fixed or sticky (always, even without a…
Flexbox is a one-dimensional layout model: it lays items along a single axis and distributes the leftover (or missing) space. Its real strength is flex on the items — controlling how they grow and shrink: Flex or Grid? Situation Pick ------ One row or one…
justify-content aligns along the main axis, align-items along the cross axis. Which is which depends on flex-direction. justify-content align-items --------- Axis main cross Unique values space-between, space-around, space-evenly stretch, baseline Shared flex-start, center, flex-end Dead-centre, the short way: Note: after switching to flex-direction: column, align-items:…
The three properties answer three different questions about one flex item: flex: 1 vs flex: auto — the most common confusion: Shorthand Full Result with two items of different content length --------- flex: 1 1 1 0 both items equal (basis 0, everything shared) flex:…
flex-wrap decides whether items may move to a new line when space runs out. Two properties people mix up once wrapping is on: - align-items — aligns each item within its line. - align-content — aligns the lines within the container. The shorthand combines direction…
gap puts space between items without adding any at the container edges. Compared with the old margin approach: Concrete benefits: - No leftover margin on the first/last item, no :last-child rule. - When items wrap onto several lines, the spacing between lines is correct for…
Grid is a two-dimensional layout: you declare rows and columns, and items land in that grid's cells. Flexbox Grid --------- Dimensions one (row or column) two (rows and columns) Layout driven by content pushing out container defined up front Suits nav bars, button groups, chips…
fr (fraction) divides the remaining space in a grid container after all fixed sizes and gap have been subtracted. Why it beats %: Combine with minmax() so tracks do not get too narrow: Note: 1fr really means minmax(auto, 1fr), so it will not shrink below…
These two declare the explicit grid: how many tracks there are and how wide or tall each one is. Common track values: <length, %, fr, auto (fit content), min-content, max-content, minmax(a, b), fit-content(300px). Items beyond the declared tracks fall into the implicit grid, sized by…
Both pair with repeat() so the browser computes the column count; they differ in how empty tracks are handled. In a 1000px container holding only 2 items: Tracks created What you see --------- auto-fill 5 (empty tracks kept) two 200px items, empty space to the…
minmax(min, max) sets a lower and upper bound for a grid track. That last line is the single most-used formula in modern CSS Grid: each card is at least 260px, the column count follows the width, and cards stretch to fill the row. Accepted values:…
grid-template-areas lets you draw the layout in text and then assign items to named regions. Changing the layout for mobile means redrawing the picture, not touching any item: How to write the area map: one whole row is one string, area names are not quoted…
Responsive design means one codebase presenting sensibly at any screen size, rather than a separate mobile site. The three original ingredients (Ethan Marcotte, 2010): 1. Fluid grids — %, fr, flex instead of fixed widths. 2. Flexible images — max-width: 100%, srcset. 3. Media queries…
Mobile-first means the default CSS targets small screens, with min-width queries adding on for larger ones. Compared with desktop-first: Three reasons to go mobile-first: 1. Fewer overrides — each breakpoint adds instead of cancelling, so the CSS is shorter and easier to trace. 2. Forces…
A media query applies a block of CSS when a device condition holds. Common thresholds: 640 / 768 / 1024 / 1280px — but those are Tailwind's convention, not a standard. Don't name breakpoints after devices; pick thresholds where the layout actually breaks, found by…
clamp(min, preferred, max) locks a value into a range and scales continuously in between. It replaces stepping through media queries: The usual fluid-typography formula mixes rem with vw so it still honours the user's font size: Note 1: a pure vw middle term (clamp(1rem, 4vw,…
Container queries let a component respond to its parent's width rather than the viewport. The practical value: the same component renders differently in a 300px sidebar and a 900px content column — something media queries cannot do, since the viewport is identical in both cases.…
srcset lists several versions of an image; sizes tells the browser how wide it will be displayed so it can pick the right file. How the browser decides with sizes="(min-width: 1024px) 50vw, 100vw" on a 1280px screen at DPR 2: - The image will be…
@keyframes describes the waypoints; animation attaches them to an element. The sub-properties of animation: name, duration, timing-function, delay, iteration-count, direction, fill-mode, play-state. fill-mode is the one people forget: - forwards — hold the final state after it finishes. - backwards — apply the initial state…
will-change warns the browser which property is about to change so it can prepare, usually by promoting the element to its own composite layer. The catch: every layer costs GPU memory. Sprinkling will-change across many elements makes the page slower, not faster — noticeably so…
Logical properties describe position by writing direction instead of fixed left/right/top/bottom. Two axes: - inline — the direction text runs. LTR: left to right. RTL (Arabic, Hebrew): right to left. - block — the direction lines stack. Usually top to bottom. Physical Logical ------ margin-left…
scroll-snap makes scrolling settle on defined points without a JS library. Value Behavior ------ mandatory always lands on a point — right for full-screen carousels proximity snaps only when you stop nearby — right for long lists, feels natural Uses: image carousels, horizontally scrolling card…
BEM is a class naming convention that makes each class state which component it belongs to and what role it plays. What it solves: deeply nested selectors (.sidebar .card h3 span) break whenever the DOM changes, and specificity escalates out of control. BEM keeps every…
Utility-first means styling with many small classes, one property each, directly in the HTML. The real strengths are not "typing faster": 1. No naming — a large share of CSS debate in a team is debate about class names. 2. CSS size barely grows with…
CSS Modules compile each .module.css file into uniquely renamed classes, so styles never leak out of the component. After the build, .root becomes Buttonrootx7f2a — two components can both define .root without colliding. The key property: everything happens at build time, with no runtime at…
CSS-in-JS writes styles in JavaScript, attached to the component. Pros: automatic scoping, styles that react to props/state in the same file, and deleting a component deletes its styles (no dead CSS). Cons: a runtime library must generate and inject CSS during render — main-thread cost,…
Critical CSS is the minimum CSS needed to paint the first screen, inlined into <head so rendering does not wait on an external file. The problem it solves: <link rel="stylesheet" is render-blocking — the browser paints nothing until the CSS arrives. On a slow connection…
font-display controls what the browser does while a custom font is still loading. Value Block period Result --------- block ~3s of hidden text FOIT — invisible text, worst for perceived speed swap 0s fallback shows immediately, swaps on arrival — FOUT, can cause CLS fallback…
backdrop-filter filters what is behind an element rather than the element itself. Compared with filter: Uses: translucent sticky navigation, modal overlays, glassmorphism cards, overlays on images. Note 1: forgetting the semi-transparent background. With an opaque background there is nothing to see through, and the effect…
Two recipes, depending on how many lines you keep. Single line: Multiple lines: Despite the -webkit- prefix, line-clamp works in every modern browser (Chrome, Safari, Firefox 68+, Edge) — one of the few prefixes that became a de facto standard. An unprefixed line-clamp property exists…
A variable font is one file containing one or more axes of variation (weight, width, slant...) instead of one file per style. Five registered axes: wght (weight), wdth (width), slnt (slant), ital (italic), opsz (optical size); each has its own CSS property such as font-weight…
prefers-reduced-motion reports that the user has enabled reduced motion at the OS level. This is not an aesthetic preference: large motion causes genuine dizziness and nausea for people with vestibular disorders. The recommended shape — no animation by default, added only when the user has…
prefers-color-scheme reports whether the OS is in light or dark mode. The correct implementation is to declare color tokens on :root and override only the tokens in dark — never rewrite every rule: Tell the browser the page supports both so form controls and scrollbars…
<picture lets the browser choose between sources that differ in format or framing, with <img as the final fallback. The browser walks the <source list in order and stops at the first match, so the newest format must come first. When to use <picture versus…
box-shadow casts a shadow of the box; filter: drop-shadow() casts one of the actual rendered shape, transparency included. The difference shows on transparent PNGs, SVG icons, or clip-path shapes. clip-path has one easy-to-miss catch: it clips everything the element paints, including its own shadow. So…
By content, not by device. The reason is plain: the device list changes every year — iPhone SE at 375px, Pro Max at 430px, folding tablets, half-screen desktop windows. There is no stable set of "standard sizes" to target. How to do it in practice:…
A composite layer is a separate paint surface that the browser hands to the GPU to stitch together at the end. An element on its own layer can move or change opacity without repainting the rest of the page. What promotes an element to its…
Four math functions, usable anywhere a length, number, angle or frequency is accepted. A common trick — min() in place of max-width, max() in place of min-width: All four nest and combine: Note 1 — whitespace around operators. calc(100%-2rem) is invalid; + and - need…
The core principle: every color goes through a custom property, and dark mode changes token values rather than rewriting rules. Those three blocks cover all three states: chose light, chose dark, follow the system. color-scheme has to change with the active theme. If you pin…
touch-action tells the browser which touch gestures it may handle on its own (scrolling, zooming). For gestures you turn off, the browser stops stepping in, so your pointer events run uninterrupted for the whole gesture. Value Browser still handles Typical use --------- auto scrolling, pinch…
The two differ in how many dimensions they control. - Flexbox — one-dimensional: distributes items along a single axis (row or column). Item sizes flow from their content, which suits navigation bars, item lists, button rows, or simple centering. - Grid — two-dimensional: defines rows…
A BFC (Block Formatting Context) is an independent layout region in CSS where elements inside don't affect the layout outside and vice versa. The classic example: a container holding only float elements has zero height, because floats are taken out of normal flow. Give the…
Margin collapsing is when the vertical (top/bottom) margins of touching blocks merge into one margin equal to the larger value instead of adding up. So margin-bottom: 20px meeting margin-top: 30px gives a 30px gap. Horizontal margins never collapse. For A–B, the two margins touch, so…
grid-template-areas lets you name each region of a grid and place elements into a region with grid-area. Because placement lives in CSS rather than in the order of the HTML tags, changing the layout on another screen size only means redrawing the area map inside…
A stacking context is a layering system in CSS; each context creates its own independent z-index scope. A child only compares its z-index with elements inside the same context; the whole context is layered as one block against the outside. The modal has z-index: 9999…
Semantic HTML first: <button, <a, <nav, <main, <label, properly ranked headings — these come with built-in roles, focus, keyboard control, and meaning for screen readers. ARIA rule 1: do not use ARIA if a native HTML element already does the job (a <div onClick is…
A CSS custom property is a variable declared with a -- prefix and read back via the var() function: Key traits: - Inherits through the DOM tree and is scoped: declared on :root it is global; declared inside a selector it applies only to that…
- Pseudo-class (one colon :): selects an element by its state or position in the tree — it creates nothing new. Examples: :hover, :focus, :active, :checked, :disabled, :first-child, :nth-child(2n), :not(...). It answers "what state is this element in / where does it sit". - Pseudo-element…
- transition: interpolates between two states — the current value and a new one — when something triggers it (hover, a class change, adding/removing inline style). It needs a "nudge" to run, goes one direction at a time, and does not loop by itself. -…
Both address browsers shipping different default styles (<body margin, <h1 size, <ul styling...), but with opposite philosophies: - Reset (e.g. Meyer reset): strips most defaults to zero — margins, padding, font-size... A blank slate; you rebuild everything from scratch. Total consistency but more work. -…
- border: part of the box model, drawn between padding and margin. It takes up space, so it grows the element and shifts layout. Can be set per side (border-top...) and rounded via border-radius. - outline: drawn outside the border and takes no space in…
flex: 1 is shorthand for flex-grow: 1; flex-shrink: 1; flex-basis: 0%. The key part is flex-basis: 0%: the browser treats the item's starting size as 0, then distributes all free space by the flex-grow ratio. So items sharing flex: 1 end up with equal width…
Toolbar → Flexbox. Card grid → Grid. The deciding factor: Flexbox is one-dimensional — lay out a single row (or column) and distribute free space based on content. Grid is two-dimensional — you declare rows and columns up front, then place items into cells. A…
- align-items: aligns each item within its own line, along the cross axis. - align-content: aligns the set of lines as a whole relative to the container, also along the cross axis. align-content only does anything when the container has multiple lines and spare space…
gap declares spacing between items and applies only in between — no leftover margin at the edges, so no compensating :last-child rule. Concrete advantages: - Wrapping works: when items wrap, gap also spaces between lines (row-gap); margin-right does not, so you add margin-bottom and get…
The cause is min-width: auto, the default minimum size of a flex item on the main axis. It says the item may not shrink below its min-content size — the longest unbreakable word or the minimum width of its children. flex-shrink: 1 still runs, but…
Because auto-fit collapses empty tracks to zero and lets the populated tracks absorb the leftover space. With one card left, every other track disappears and that card grows via 1fr to fill the row. auto-fill keeps the empty tracks. The single card stays one column…
Change 1fr to minmax(0, 1fr). 1fr is really shorthand for minmax(auto, 1fr). That auto floor is the cell's min-content size, so unbreakable content forces the track wider and the whole grid overflows its container. minmax(min, max) defines a track that flexes between two bounds. A…
grid-template-areas names regions and draws the layout as ASCII strings; going responsive means redrawing the map, with no HTML changes and no order hacks. Rules to remember: each string is one row, every row needs the same token count, a repeated name makes the area…
position: sticky behaves like relative until scrolling reaches the offset threshold, then it sticks. But it only travels inside its parent and sticks relative to the nearest scroll container. Almost every "it does not stick" bug is a missing offset, or one of those two…
This is margin collapsing between a parent and its first child: with nothing separating them at the top edge (no border, no padding, no inline content), the child's top margin escapes and merges with the parent's. The result is the larger of the two, not…
aspect-ratio states the width-to-height ratio directly; the browser derives the missing dimension from the known one. Compared with the old padding-top: 56.25% plus an absolutely positioned inner layer: - No extra wrapper element, and no percentage to recompute when the ratio changes. - Content stays…
The browser picks a value through three tiers, moving down only when the tier above ties: 1. Origin and importance — user-agent < author < !important (which reverses the order). 2. Specificity — the triple (id, class/attribute/pseudo-class, element/pseudo-element). Inline styles (the style attribute) are not…
!important does not fix the cause — it opts out of the cascade. Consequences: - Overriding an !important declaration later requires another, more specific !important — the stylesheet slides into an escalation race. - Inline styles set by JS (animation libraries, element.style) can no longer…
@supports is a feature query: it asks the browser whether it understands a property/value pair before applying the block inside. The syntax supports not, and, or, and selector() for testing selectors: Points interviewers probe: - Write the fallback first, @supports after — old browsers skip…
Because custom properties follow DOM inheritance, unlike SASS globals. Declaring --gap on .card makes it readable by .card and its descendants only; siblings outside that subtree see var(--gap) as invalid. To share it, declare it on a common ancestor, usually :root (i.e. <html). The var(--x,…
The principle: components know no colors, they only read tokens. All light/dark differences live in one place. - prefers-color-scheme handles the OS default. - A data-theme attribute on <html handles the manual choice. It beats the media query not through specificity (the selector inside the…
Both selector-grouping functions match exactly the same elements; they differ only in specificity: - :is(...) takes the specificity of the most specific selector in its list. - :where(...) always has zero specificity, whatever it contains. Practical consequence: an :is() rule with an id hidden in…
:has() is the parent selector: it targets an element based on what it contains or what follows it. CSS previously only walked downwards, so any state depending on children had to be toggled as a class by JS. Patterns that come up in real projects:…
Logical properties describe position by text flow instead of the physical left/right axis. With dir="rtl", the browser mirrors them automatically — no separate RTL stylesheet. Physical Logical ------ margin-left margin-inline-start padding-right padding-inline-end text-align: left text-align: start border-top border-block-start width / height inline-size / block-size inline…
Both solve the same problem: CSS has no scoping, so a convention is needed to avoid class collisions and leaking styles. BEM — blockelement--modifier, one meaning layer per class: - Flat specificity (a single class), predictable override order. - Clean HTML, class names describe roles,…
clamp(min, preferred, max) scales continuously with the viewport instead of jumping at breakpoints: The middle value must contain a vw component to scale at all. Deriving it: pick two anchors (e.g. 360px → 28px, 1280px → 48px), compute the slope (48-28)/(1280-360) = 0.0217 → 2.17vw,…
Because every frame goes through style → layout → paint → composite, and the property you change decides which step must rerun. - Changing left, top, width, height, margin → triggers layout (reflow) of the affected subtree, then paint, then composite. The most expensive path.…
There are three: inline (a style attribute on each tag), internal (a <style tag in the <head) and external (a separate .css file loaded with <link rel="stylesheet"). Real projects almost always use external; the other two are for special cases. Method Pros Cons --------- External…