Interview prep · 41 questions

CSS Interview Questions and Answers

These are the CSS questions that come up most often in front-end interviews, from selectors and the box model to Flexbox, Grid, stacking contexts and modern features like container queries. Questions are grouped by level, so start with the fresher section and move up, and try answering each one aloud before reading the answer.

CSS interview questions: fresher level

What are the different ways to add CSS to an HTML page?

There are three ways: inline styles, an internal stylesheet, and an external stylesheet.

  • Inline: a style attribute on the element. Useful for quick, one-off values or styles set by JavaScript, but hard to maintain and very high in priority.
  • Internal: CSS written inside a style element in the head of the page. Fine for a single page or critical above-the-fold CSS.
  • External: a separate .css file connected with a link element. This is the standard choice because one file can style many pages and the browser can cache it.
HTML
<link rel="stylesheet" href="styles.css">
<style>
  h1 { color: navy; }
</style>
<p style="color: red;">Inline style</p>

You can also pull one stylesheet into another with @import, but it delays loading because the imported file is discovered only after the first one is downloaded.

Interview tip: A common follow-up is which one wins when all three set the same property: inline beats internal and external, and between internal and external the rule that appears later wins if specificity is equal.

What are CSS selectors, and what are the common types?

A selector tells the browser which elements a rule applies to. The common types are:

  • Universal: * matches every element.
  • Type (element): p, h1.
  • Class: .card; ID: #header.
  • Attribute: input[type="email"], a[href^="https"].
  • Combinators: descendant nav a, child ul > li, adjacent sibling h2 + p, general sibling h2 ~ p.
  • Pseudo-classes such as :hover, :focus, :nth-child(2) and pseudo-elements such as ::before.
  • Grouping with a comma: h1, h2, h3.
CSS
ul > li.active a:hover { color: tomato; }
input[type="checkbox"]:checked + label { font-weight: bold; }

What is the difference between a class and an ID in CSS?

An ID should be unique on the page, while a class can be reused on any number of elements, and an element can have several classes.

The other big difference is specificity. An ID selector is worth (1,0,0) while a class is worth (0,1,0), so a single ID beats any number of classes. That makes ID-based styles hard to override, which is why most teams style with classes and keep IDs for page anchors (#contact), label and for pairing, and JavaScript hooks.

CSS
#title { color: red; }     /* (1,0,0) */
.heading.main { color: blue; } /* (0,2,0) */
/* An element matching both is red */

What is the CSS box model?

Every element is drawn as a rectangular box made of four layers, from inside out: content, padding, border and margin.

  • Content: the text or image, sized by width and height.
  • Padding: space between the content and the border. It takes the element background.
  • Border: the line around the padding.
  • Margin: transparent space outside the border that pushes other elements away. Vertical margins between blocks can collapse.

Padding is inside the element and clickable; margin is outside it. By default, width sets only the content area, so padding and border are added on top of it.

Interview tip: Expect a follow-up asking for the total rendered width of a box with given width, padding and border, which leads straight into box-sizing.

What does box-sizing: border-box do?

It makes width and height include padding and border, so the box ends up exactly the size you set.

The default is content-box, where width covers only the content and padding plus border are added outside it. That makes layouts like two 50% columns with padding overflow. With border-box, the padding and border eat into the content area instead. Most projects apply it to every element at the start of the stylesheet.

CSS
.box { width: 200px; padding: 20px; border: 5px solid; }
/* content-box: rendered width 250px (200 + 40 + 10) */
/* border-box:  rendered width 200px, content 150px */

*, *::before, *::after { box-sizing: border-box; }

What is the difference between block, inline and inline-block?

They control how an element sits in the flow and whether width and height apply.

  • block (div, p, h1): starts on a new line, takes the full available width by default, and respects width, height, margin and padding on all sides.
  • inline (span, a, strong): flows within a line of text, ignores width and height, and its vertical margins do not move surrounding lines. Vertical padding is painted but does not push lines apart.
  • inline-block: sits in a line like inline but accepts width, height and vertical margin like a block. Useful for buttons or badges.

Other common values are none, flex, grid, inline-flex and inline-grid.

How do the position values static, relative, absolute, fixed and sticky differ?

  • static: the default. The element is in normal flow and top, left and similar offsets have no effect.
  • relative: stays in normal flow, but offsets shift it visually from where it would be. Its original space is kept. Often used just to become the reference for absolute children.
  • absolute: removed from normal flow and placed relative to the nearest ancestor that is positioned (any value other than static). If there is none, it uses the initial containing block.
  • fixed: removed from flow and placed relative to the viewport, so it stays put while scrolling.
  • sticky: behaves like relative until its scroll container is scrolled past a threshold such as top: 0, then sticks, but only within its parent.
CSS
.card { position: relative; }
.badge { position: absolute; top: 8px; right: 8px; }
.site-header { position: sticky; top: 0; }

Interview tip: Interviewers often ask what an absolute element is positioned against; the answer "the nearest positioned ancestor" is the key phrase.

What is the difference between px, em, rem and % units?

px is an absolute CSS pixel. The others are relative.

  • em is relative to the font size of the element itself. When used on font-size, it is relative to the parent font size, so nested ems compound.
  • rem is relative to the root (html) font size, so it does not compound. Good for font sizes and spacing that should scale with the user font setting.
  • % depends on the property: for width and for padding and margin (even vertical ones) it is a percentage of the containing block width; for font-size it is of the parent font size.
  • vw and vh are 1% of the viewport width and height.
CSS
/* root font-size is 16px (browser default) */
.parent { font-size: 1.5em; }  /* 24px */
.child  { font-size: 1.5em; }  /* 36px, compounds */
.child2 { font-size: 1.5rem; } /* 24px, always */

Interview tip: Be ready to explain why rem is preferred for font sizes: it respects the font size the user picked in browser settings.

What is the difference between a pseudo-class and a pseudo-element?

A pseudo-class selects an existing element when it is in a certain state or position; a pseudo-element styles a part of an element, or creates content that is not in the HTML.

Pseudo-classes use one colon: :hover, :focus, :checked, :first-child, :nth-child(2n). Pseudo-elements use two colons: ::before, ::after, ::first-line, ::placeholder, ::selection. Browsers still accept the old single-colon form for :before and :after. Note that ::before and ::after render nothing unless content is set, even to an empty string.

CSS
a:hover { text-decoration: underline; }
.required::after { content: " *"; color: red; }

What is the difference between display: none, visibility: hidden and opacity: 0?

All three make an element invisible, but they differ in layout, interaction and accessibility.

  • display: none removes the element from layout entirely. It takes no space, cannot be clicked or focused, and is hidden from screen readers.
  • visibility: hidden keeps the space the element occupies, but it cannot be clicked or focused and is hidden from screen readers. A child can set visibility: visible and still show.
  • opacity: 0 keeps the space and the element is still fully interactive: it can be clicked, focused and read by screen readers.

opacity animates smoothly, which is why fade effects use it, often together with visibility so the hidden element cannot be clicked.

Interview tip: The trap is opacity: 0 on a button or modal, which leaves an invisible element that still catches clicks.

How do you center a div horizontally and vertically?

The simplest modern way is Flexbox or Grid on the parent.

CSS
.parent { display: flex; justify-content: center; align-items: center; min-height: 100vh; }

.parent { display: grid; place-items: center; }

.parent { position: relative; }
.child  { position: absolute; top: 50%; left: 50%;
          transform: translate(-50%, -50%); }

The absolute method works because top: 50% and left: 50% place the top-left corner at the center, and translate(-50%, -50%) shifts the element back by half its own size. For horizontal centering only, a block with a set width can use margin: 0 auto, and inline content can use text-align: center on the parent.

Interview tip: Mention at least two methods and when each fits; interviewers like hearing that vertical centering needs the parent to have height.

What does "cascading" mean in Cascading Style Sheets?

It is the algorithm the browser uses to decide which declaration wins when several rules set the same property on the same element.

In simplified order, the browser compares:

  • Importance and origin: !important declarations beat normal ones, and author styles beat browser default styles.
  • Inline styles beat styles from selectors.
  • Specificity: an ID beats classes, classes beat element selectors.
  • Source order: if everything else is equal, the rule that comes later wins.
CSS
p { color: blue; }
p { color: green; }  /* wins: same specificity, later */
.intro { color: red; } /* wins over both on p.intro */

What is inheritance in CSS? Which properties are inherited?

Inheritance means some properties set on a parent are passed down to its children when the child does not set its own value.

Mostly text-related properties inherit: color, font-family, font-size, line-height, text-align, letter-spacing, visibility, cursor, list-style. Box and layout properties do not: margin, padding, border, background, width, height, display, position. That is why setting font-family on body styles the whole page.

You can control it with keywords: inherit forces the parent value, initial uses the property default, unset acts as inherit for inherited properties and initial for others, and revert falls back to the browser default style.

CSS
button { font: inherit; } /* buttons do not inherit font by default */

What is Flexbox and when do you use it?

Flexbox is a one-dimensional layout system for arranging items in a row or a column, with control over alignment, spacing and how items grow or shrink.

You turn it on with display: flex on a container; its direct children become flex items. Key container properties are flex-direction, justify-content, align-items, flex-wrap and gap. Typical uses: navbars, button groups, card rows, centering, and pushing a footer to the bottom of a card.

CSS
.nav {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
}

What are media queries?

Media queries apply CSS only when a condition about the device or viewport is true, such as its width, orientation or user preferences.

They are the main tool for responsive design. Besides width, you can query orientation, hover, prefers-color-scheme for dark mode and prefers-reduced-motion for users who want less animation. For them to work on phones, the page needs the viewport meta tag; without it, mobile browsers render at a wide virtual width and scale down.

CSS
.grid { display: grid; grid-template-columns: 1fr; }

@media (min-width: 768px) {
  .grid { grid-template-columns: repeat(2, 1fr); }
}
@media (prefers-color-scheme: dark) {
  body { background: #111; color: #eee; }
}

What does the overflow property do?

overflow controls what happens when content is bigger than its box.

  • visible (default): content spills outside the box.
  • hidden: extra content is clipped with no scrollbar, though it can still be scrolled with code.
  • scroll: always reserves scrollbars.
  • auto: shows scrollbars only when needed. Usually the best choice.
  • clip: clips like hidden but does not create a scroll container at all.

You can set axes separately with overflow-x and overflow-y. A catch: if one axis is not visible or clip, a visible on the other axis is treated as auto. A single-line ellipsis needs three properties together.

CSS
.title { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

CSS interview questions: intermediate level

What is specificity and how is it calculated?

Specificity is a score that decides which selector wins when two rules target the same element with the same importance. It is written as three numbers (A, B, C) and compared left to right.

  • A: number of ID selectors.
  • B: classes, attribute selectors and pseudo-classes.
  • C: type selectors and pseudo-elements.
  • The universal selector * and combinators add nothing. :where() always counts as zero; :is(), :not() and :has() take the specificity of their most specific argument.
CSS
li                    /* (0,0,1) */
ul li.active          /* (0,1,2) */
.card::before         /* (0,1,1) */
#menu a:hover         /* (1,1,1) */
nav ul li a.link.on   /* (0,2,4) */
:not(.done) span      /* (0,1,1) */
:where(#x) p          /* (0,0,1) */

It is not a decimal number: eleven classes (0,11,0) still lose to one ID (1,0,0). Inline styles beat any selector, and !important beats both.

Interview tip: Interviewers often give two selectors and ask which wins; count IDs first and only look at classes if the IDs tie.

What does !important do and why is it discouraged?

!important makes a declaration win over normal declarations, regardless of selector specificity or inline styles.

If two !important declarations conflict, the normal rules apply between them again: higher specificity wins, then later source order. An !important inline style beats an !important rule in a stylesheet.

It is discouraged because it breaks the natural cascade. Overriding it usually needs another !important with higher specificity or later source order, which leads to escalating overrides that are hard to debug. Acceptable uses are utility classes that must always win (such as a .hidden helper) and overriding third-party CSS you cannot edit.

CSS
.btn { color: white !important; }
#save.btn { color: black; }  /* loses, not important */

What is margin collapsing?

Margin collapsing is when the vertical margins of block elements touch and combine into a single margin equal to the larger one, instead of adding up.

It happens in three cases: between adjacent siblings, between a parent and its first or last child when no border, padding or content separates them, and on empty blocks. With negative margins, the result is the largest positive plus the most negative.

It does not happen with horizontal margins, between flex or grid items, for floated or absolutely positioned elements, or across a parent that creates a new block formatting context (for example with display: flow-root or overflow: hidden).

CSS
.a { margin-bottom: 30px; }
.b { margin-top: 20px; }
/* gap between .a and .b is 30px, not 50px */

Interview tip: A classic follow-up: a child margin-top that pushes the parent down instead of creating space inside it. Fix it with padding or a border on the parent, or with display: flow-root.

How does z-index work and what is a stacking context?

z-index sets the stacking order of positioned elements (and flex or grid items) along the z-axis, but it only competes with siblings inside the same stacking context.

A stacking context is a group that is layered as one unit. A child can never escape its parent context, so a child with z-index: 9999 inside a parent with z-index: 1 stays below a sibling of that parent with z-index: 2.

Common things that create a stacking context: the root element, a positioned element with a z-index other than auto, position: fixed or sticky, flex or grid items with a z-index, opacity below 1, transform, filter, and isolation: isolate.

CSS
.parent { position: relative; z-index: 1; }
.child  { position: relative; z-index: 9999; } /* inside .parent */
.other  { position: relative; z-index: 2; }    /* sibling of .parent, sits on top */

Interview tip: When z-index "does not work", the answer is almost always a missing position value or an ancestor that created a stacking context.

What is the difference between justify-content and align-items in Flexbox?

justify-content aligns items along the main axis, and align-items aligns them along the cross axis.

The main axis follows flex-direction. With the default row, the main axis is horizontal, so justify-content controls horizontal placement and align-items controls vertical placement. With flex-direction: column, they swap: justify-content becomes vertical.

  • justify-content: flex-start, center, flex-end, space-between, space-around, space-evenly.
  • align-items: stretch (default), flex-start, center, flex-end, baseline.
  • align-content aligns the lines themselves when items wrap onto several lines.
  • align-self overrides align-items for one item.

Interview tip: If you say "justify is horizontal, align is vertical", expect the column follow-up; tie it to the main and cross axis instead.

What does flex: 1 mean?

flex: 1 is shorthand for flex-grow: 1, flex-shrink: 1 and flex-basis: 0, which makes items share the free space equally regardless of their content.

  • flex-grow: how much of the leftover space an item takes, as a ratio.
  • flex-shrink: how much it gives up when space is short.
  • flex-basis: the starting size before growing or shrinking.

Other common values: the default is 0 1 auto (do not grow, may shrink, size from content); flex: auto is 1 1 auto, so items grow but bigger content stays bigger; flex: none is 0 0 auto, a fixed item.

CSS
.sidebar { flex: 0 0 250px; } /* fixed 250px */
.main    { flex: 1; }         /* takes the rest */
.a { flex: 2; } .b { flex: 1; } /* a gets twice b */

What is CSS Grid and what is the fr unit?

CSS Grid is a two-dimensional layout system that places items into rows and columns at the same time.

You define tracks on the container with grid-template-columns and grid-template-rows, add spacing with gap, and items can span tracks with grid-column and grid-row.

The fr unit means a fraction of the free space left after fixed-size tracks and gaps are taken out. In the example, the first column is 200px and the remaining space is split 1:2. One detail: 1fr will not shrink below its content minimum, so use minmax(0, 1fr) when long content overflows.

CSS
.layout {
  display: grid;
  grid-template-columns: 200px 1fr 2fr;
  gap: 16px;
}
.banner { grid-column: 1 / -1; } /* spans every column */

How do grid-template-areas work?

grid-template-areas lets you draw the layout with named regions, then place items by name using grid-area.

Each string is one row and each word is one cell. Repeating a name across cells makes that area span them. A dot (.) leaves a cell empty. Every area must form a rectangle, and every row must have the same number of cells, or the declaration is invalid. It makes responsive changes easy: redefine the areas inside a media query and the HTML does not change.

CSS
.page {
  display: grid;
  grid-template-columns: 220px 1fr;
  grid-template-areas:
    "header header"
    "sidebar main"
    "footer footer";
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }

When would you use Flexbox and when Grid?

Use Flexbox for one-dimensional layouts, a single row or column, where content size drives the layout; use Grid for two-dimensional layouts where you control rows and columns together.

  • Flexbox fits navbars, toolbars, button groups, aligning an icon with text, and spacing items in a line.
  • Grid fits page layouts, card galleries where columns must line up across rows, dashboards and overlapping items in the same cell.
  • Flexbox works content-out: items decide their size and the container distributes space. Grid works layout-in: the container defines tracks and items are placed into them.

They combine well. A common pattern is Grid for the page and card list, Flexbox inside each card.

Interview tip: Avoid saying one replaces the other; interviewers want to hear the one-dimension versus two-dimension reasoning.

What is responsive design and what does mobile-first mean?

Responsive design means one page adapts its layout to any screen size; mobile-first means writing the base styles for small screens and adding min-width media queries for larger ones.

The building blocks are the viewport meta tag, fluid layouts with Flexbox, Grid and percentages, flexible media (max-width: 100% on images), relative units, and media queries at breakpoints where the design breaks rather than at specific device sizes.

Mobile-first keeps phone CSS simple, since small screens get only the base rules, and it pushes you to prioritise content. The opposite, desktop-first, uses max-width queries to undo styles for smaller screens.

CSS
.cards { display: grid; gap: 1rem; }
@media (min-width: 640px) { .cards { grid-template-columns: 1fr 1fr; } }
@media (min-width: 1024px) { .cards { grid-template-columns: repeat(3, 1fr); } }
h1 { font-size: clamp(1.5rem, 4vw, 3rem); }

What are CSS variables (custom properties)?

Custom properties are values you define once with a --name and reuse with var(), and unlike Sass variables they live in the browser and can change at runtime.

They follow the cascade and are inherited, so a variable set on :root is available everywhere, and you can override it for one component or inside a media query. var() accepts a fallback as its second argument. JavaScript can read and update them, which makes theming such as dark mode easy.

CSS
:root { --brand: #2563eb; --gap: 16px; }
.btn { background: var(--brand); padding: var(--gap); }
.dark { --brand: #60a5fa; }  /* overrides for this subtree */
.card { margin: var(--space, 8px); } /* fallback used if unset */
JS
document.documentElement.style.setProperty('--brand', 'tomato');

Interview tip: The usual follow-up is how they differ from Sass variables: Sass variables are replaced at compile time, custom properties exist at runtime and cascade.

What is the difference between a CSS transition and a CSS animation?

A transition animates a property from one value to another when the value changes; an animation runs a sequence defined with @keyframes and does not need a trigger.

  • Transitions need a state change, such as :hover, :focus or a class added by JavaScript. They go from A to B and back.
  • Animations can start on page load, have many steps, repeat (animation-iteration-count: infinite), alternate direction, and keep the final state with animation-fill-mode: forwards.
CSS
.btn { transition: background-color 0.3s ease; }
.btn:hover { background-color: navy; }

@keyframes spin { to { transform: rotate(360deg); } }
.loader { animation: spin 1s linear infinite; }

For smooth performance, prefer animating transform and opacity.

What does the transform property do, and how is it different from changing top or left?

transform visually moves, rotates, scales or skews an element without changing the layout around it.

Functions include translate(), rotate(), scale() and skew(), and the pivot point is set with transform-origin. Percentages in translate() are relative to the element's own size, which is why translate(-50%, -50%) centers things.

Changing top, left, width or margin affects geometry, so the browser recalculates layout. A transform is applied after layout, other elements do not move, and browsers can usually handle it on the compositor, so animations stay smooth. Note that a transform also creates a new stacking context and becomes the containing block for fixed and absolute descendants.

CSS
.card:hover { transform: translateY(-4px) scale(1.02); }

What is BEM?

BEM (Block, Element, Modifier) is a class naming convention that keeps CSS predictable and avoids conflicts in large projects.

  • Block: a standalone component, such as .card.
  • Element: a part that belongs to the block, joined with two underscores: .card__title.
  • Modifier: a variation or state, joined with two hyphens: .card--featured, .card__button--disabled.

Because every selector is a single class, specificity stays flat and low, so overrides are easy and you avoid long nested selectors. The class names also make the HTML self-documenting.

HTML
<div class="card card--featured">
  <h3 class="card__title">Title</h3>
  <button class="card__button card__button--disabled">Buy</button>
</div>

What are floats and what is a clearfix?

float pushes an element to the left or right so that text and inline content wrap around it, which is its original purpose (an image inside an article).

Floated elements are taken out of normal flow, so a parent that contains only floats collapses to zero height. A clearfix fixes that by making the parent contain its floats. The old trick adds a pseudo-element with clear: both; the modern fix is display: flow-root on the parent, which creates a new block formatting context.

CSS
.clearfix::after { content: ""; display: block; clear: both; }
.parent { display: flow-root; } /* modern alternative */

Today, use Flexbox or Grid for layouts and keep floats for wrapping text around images.

CSS interview questions: advanced level

What is the difference between reflow and repaint, and how does it affect performance?

Reflow (layout) is when the browser recalculates the size and position of elements; repaint is when it redraws pixels without changing geometry. Reflow is more expensive because it often affects many elements and is always followed by a repaint.

  • Layout changes: width, height, margin, padding, top, font-size, adding or removing elements.
  • Paint-only changes: color, background-color, box-shadow, visibility.
  • Often composite-only: transform and opacity, which is why they are preferred for animation.

A common problem is layout thrashing: writing a style and then reading a geometry value like offsetHeight in a loop forces the browser to run layout synchronously each time. Batch reads first, then writes. Use will-change sparingly, only on elements that are about to animate.

Interview tip: Interviewers often ask how you would animate a sidebar sliding in; the strong answer is transform: translateX rather than left or width.

What is the difference between auto-fit and auto-fill in CSS Grid?

Both create as many columns as fit in the container; the difference shows only when there are fewer items than columns. auto-fill keeps the empty columns, so items keep the width they would have in a full row. auto-fit collapses empty columns to zero, so with 1fr the existing items stretch to fill the row.

CSS
.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 16px;
}
/* Container 1000px wide, only 2 items:
   auto-fill: 4 tracks of 238px, 2 stay empty
   auto-fit:  empty tracks collapse, 2 items of 492px */

This pattern gives a responsive card grid with no media queries. Use auto-fill when you want consistent card sizes, auto-fit when a few items should fill the row. Wrapping the minimum in min(), as in minmax(min(200px, 100%), 1fr), prevents overflow on very narrow screens.

Why might position: sticky not work?

Sticky positioning needs a threshold, room to move inside its parent, and the right scroll container. The usual causes are:

  • No offset is set. You must give top, bottom, left or right.
  • An ancestor has overflow set to hidden, auto or scroll. That ancestor becomes the scroll container, so the element sticks relative to it, and if it does not scroll, nothing happens.
  • The parent is no taller than the sticky element. Sticky elements never leave their parent, so there is no space to stick.
  • Inside a flex container, the default align-items: stretch makes the item as tall as the container, removing that space. Use align-self: flex-start.
CSS
.sidebar { position: sticky; top: 1rem; align-self: flex-start; }

Interview tip: This is a debugging question; walking through the checklist in order matters more than any single cause.

Why does 100vh cause problems on mobile, and what are dvh, svh and lvh?

On mobile browsers, the address bar and toolbars expand and collapse while scrolling, and in most mobile browsers 100vh equals the largest viewport, with toolbars hidden. So a height: 100vh hero can be taller than the visible screen and hide content under the toolbar.

  • svh (small viewport height): the height with browser UI expanded. Safe: never hidden.
  • lvh (large viewport height): the height with browser UI retracted.
  • dvh (dynamic viewport height): updates as the UI expands or retracts.

dvh matches what users see, but the size changes while scrolling and can cause layout jumps, so svh is often the better choice for full-screen sections. Matching width units exist too (svw, lvw, dvw). Keep a vh line first as a fallback for older browsers.

CSS
.hero { min-height: 100vh; min-height: 100svh; }

What is the :has() selector?

:has() is a relational pseudo-class that matches an element if it contains, or is followed by, something matching the selector inside it. It is often called the parent selector because CSS could not select upward before.

CSS
.card:has(img) { padding: 0; }            /* cards containing an image */
label:has(+ input:invalid) { color: red; } /* label followed by invalid input */
form:has(input:focus) { outline: 2px solid; }
body:has(dialog[open]) { overflow: hidden; }

Its specificity is that of its most specific argument, so .card:has(#x) counts as (1,1,0). Pseudo-elements are not allowed inside it, and :has() cannot be nested inside another :has(). It is supported in current versions of the major browsers, but check support for your audience if older browsers matter, and keep the anchor reasonably specific, since a very broad one makes the browser re-check more elements when the page changes.

What are container queries and how are they different from media queries?

Container queries apply styles based on the size of a parent container, while media queries respond to the size of the viewport.

That makes components truly reusable: a card can switch to a horizontal layout when its own container is wide, whether it sits in a narrow sidebar or a wide main area on the same screen. You first declare a container with container-type, usually inline-size, then write @container rules. The query styles descendants of the container, not the container itself. Units like cqi (1% of the container inline size) are also available.

CSS
.card-wrap { container-type: inline-size; container-name: card; }

.card { display: grid; gap: 1rem; }
@container card (min-width: 400px) {
  .card { grid-template-columns: 150px 1fr; }
}

Interview tip: A good follow-up answer: keep media queries for page-level layout and use container queries for components.

What is the full order of the cascade, and what are cascade layers?

When declarations conflict, the browser compares these criteria in order and stops at the first one that decides:

  • Origin and importance: browser defaults, user styles, author styles, with !important reversing the order of origins.
  • Context, for Shadow DOM encapsulation.
  • Element-attached styles: inline style attributes beat selector-based rules.
  • Cascade layers.
  • Specificity.
  • Order of appearance.

@layer lets you group CSS into named layers whose order you declare up front. A later layer beats an earlier one no matter the specificity, and styles not in any layer beat all layered styles. For !important declarations, layer order is reversed. Layers are handy for keeping resets and third-party CSS low priority.

CSS
@layer reset, vendor, components;
@layer components { .btn { color: blue; } }
@layer reset { #app .btn { color: gray; } } /* loses, earlier layer */

What is the difference between :is() and :where()?

Both take a list of selectors and match an element that matches any of them; the only difference is specificity. :is() takes the specificity of its most specific argument, while :where() always has zero specificity.

CSS
:is(header, footer) a:hover { color: red; }   /* shorter than two selectors */

:is(#nav, .menu) a    /* (1,0,1): uses #nav even when matched via .menu */
:where(#nav, .menu) a /* (0,0,1) */

That makes :where() ideal for resets and library defaults that users should override easily. Both also use forgiving selector lists: one invalid selector inside them is ignored instead of invalidating the whole rule, unlike a normal comma-separated list.

Interview tip: The detail interviewers listen for is that :is() uses the highest specificity in the list even if a lower one actually matched.

Why does text overflow a flex item even with flex: 1, and how do you fix it?

Flex items have a default min-width: auto, which stops them from shrinking below the width of their content. A long URL, a pre block or a nowrap text with ellipsis forces the item, and the whole row, to stay wide.

The fix is min-width: 0 on the flex item (or min-height: 0 in a column layout), or an overflow value such as hidden or auto, which also removes the automatic minimum. Grid has the same issue with 1fr columns, fixed with minmax(0, 1fr).

CSS
.row { display: flex; }
.content {
  flex: 1;
  min-width: 0;          /* allows shrinking */
}
.content p { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

Interview tip: This one separates people who have built real layouts from those who have only read about Flexbox.

What is a containing block, and why might a fixed element stop being fixed to the viewport?

The containing block is the rectangle an element uses for its percentage sizes and offsets.

  • For static and relative elements it is usually the content box of the nearest block container ancestor.
  • For absolute elements it is the padding box of the nearest positioned ancestor.
  • For fixed elements it is normally the viewport.

The surprise: if any ancestor has transform, filter, perspective, certain contain values, or will-change set to one of those properties, that ancestor becomes the containing block for both absolute and fixed descendants. A modal with position: fixed inside an animated, transformed card will then be positioned and clipped relative to the card instead of the screen. The usual fix is to render modals near the end of body, outside transformed ancestors.

Free coding challenge

How good is your CSS, really?

Take the 15-question HTML, CSS and JavaScript challenge. Miss one and you get a short explanation plus a second chance to win the point back. At the end you see exactly where you stand, and which class to take next.

  • 15 questions
  • About 10 minutes
  • 100% free
Start the free challenge