1. What is the CSS box model?
The CSS box model describes how every element is rendered as a rectangular box made of four layers: content, padding, border and margin, from the inside out. Padding sits between the content and the border, the border wraps the padding, and margin is the transparent space outside the border that separates the element from its neighbours. The total space an element takes up is the sum of all four layers, which is why sizing behaves differently depending on box-sizing.
2. What is the difference between `box-sizing: content-box` and `border-box`?
With content-box (the default), width and height apply only to the content area, so padding and border are added on top of the declared size. With border-box, width and height include content, padding and border, which makes layouts far easier to predict. Most projects apply border-box globally.
*, *::before, *::after {
box-sizing: border-box;
}
3. What is CSS specificity and how is it calculated?
Specificity is the algorithm browsers use to decide which declaration wins when several rules target the same element. It is compared as a tuple: inline styles first, then the number of ID selectors, then classes, attributes and pseudo-classes, and finally type selectors and pseudo-elements. For example #nav .link (1,1,0) beats ul li a.link (0,1,3). The universal selector * and combinators add nothing, and !important overrides normal specificity.
4. What is the difference between `display: none` and `visibility: hidden`?
display: none removes the element from rendering entirely, so it takes up no space and is ignored by screen readers. visibility: hidden hides the element visually but it still occupies its layout space. Setting opacity: 0 is a third option: the element is invisible but still occupies space and still receives clicks and focus.
5. What are the different values of the `position` property?
position has five values: static (the default, normal flow), relative (offset from its normal place while keeping its space), absolute (removed from flow and placed relative to the nearest positioned ancestor), fixed (placed relative to the viewport) and sticky (behaves as relative until a scroll threshold, then sticks). Any value other than static makes the element a positioned element that honours top, right, bottom, left and z-index.
.header {
position: sticky;
top: 0;
}
6. What is the difference between `inline`, `block` and `inline-block`?
Block elements start on a new line and stretch to fill the available width, and they accept width, height, margin and padding on all sides. Inline elements flow within a line of text, ignore width and height, and only respect horizontal margins and padding in layout terms. inline-block flows inline like text but still accepts width, height and vertical margins like a block.
7. How does Flexbox work, and when would you use it?
Flexbox is a one-dimensional layout model that arranges children along a main axis and distributes space and alignment along it. You enable it with display: flex on the container, then control direction with flex-direction, main-axis distribution with justify-content, and cross-axis alignment with align-items. It is ideal for navbars, toolbars, card rows and any component where items need to align or share space dynamically.
.nav {
display: flex;
justify-content: space-between;
align-items: center;
gap: 1rem;
}
8. What does `flex: 1` mean?
flex: 1 is shorthand for flex: 1 1 0%, meaning flex-grow: 1, flex-shrink: 1 and flex-basis: 0%. The item starts from a zero base size and grows to share the free space equally with other flexible items. This is the common way to make several siblings take equal widths, or to make one element fill the remaining space.
9. What is the difference between `justify-content` and `align-items`?
justify-content distributes items along the main axis of a flex container, while align-items aligns them along the cross axis. In a row container the main axis is horizontal, so justify-content works horizontally and align-items vertically. When you switch to flex-direction: column, the axes swap, and so do their visual effects.
10. What is CSS Grid and how does it differ from Flexbox?
CSS Grid is a two-dimensional layout system that controls rows and columns at the same time, whereas Flexbox lays out items along a single axis. Grid is best for page-level layouts and anything that needs aligned rows and columns, while Flexbox suits component-level, content-driven layouts. The two are commonly combined, with Grid for the overall structure and Flexbox inside the cells.
.layout {
display: grid;
grid-template-columns: 240px 1fr;
grid-template-rows: auto 1fr auto;
gap: 16px;
}
11. What does the `fr` unit do in CSS Grid?
The fr unit represents a fraction of the free space left in the grid container after fixed-size tracks and gaps are accounted for. For instance, grid-template-columns: 1fr 2fr gives the second column twice the share of the remaining space. It is often combined with repeat() and minmax() to build flexible, responsive grids without percentages or calculations.
12. What is the difference between `px`, `em`, `rem`, `%`, `vh` and `vw`?
px is an absolute CSS pixel. em is relative to the element's own font size, or to the parent's font size when used on font-size itself, so it compounds when nested. rem is relative to the root element's font size, which makes it predictable. % is relative to a property-specific reference, usually the parent. vh and vw are 1% of the viewport height and width. Modern units such as dvh account for mobile browser toolbars.
13. How do you make a website responsive?
Responsive design means a layout adapts to any screen size. The core techniques are the viewport meta tag, fluid layouts using relative units, flexible images with max-width: 100%, modern layout tools like Flexbox and Grid, and media queries or container queries to adjust styles at breakpoints. A mobile-first approach, starting with base styles for small screens and enhancing with min-width queries, is generally preferred.
<meta name="viewport" content="width=device-width, initial-scale=1">
14. What are media queries and how do you write them?
Media queries apply CSS conditionally based on device or viewport characteristics such as width, orientation, resolution or user preferences like prefers-color-scheme and prefers-reduced-motion. In a mobile-first workflow you write base styles first and add min-width queries for larger screens. Modern range syntax such as width >= 768px is also supported.
.card { padding: 1rem; }
@media (min-width: 768px) {
.card { padding: 2rem; }
}
15. What is the difference between pseudo-classes and pseudo-elements?
A pseudo-class selects an element based on its state or position, such as :hover, :focus, :first-child or :nth-child(2), and uses a single colon. A pseudo-element targets a part of an element or generates virtual content, such as ::before, ::after, ::first-line or ::placeholder, and uses a double colon. Pseudo-elements ::before and ::after require the content property to render.
.btn:hover { background: #333; }
.btn::after { content: "→"; margin-left: 4px; }
16. How does the CSS cascade work?
The cascade is the process that resolves conflicting declarations for the same property. The browser considers, in order, origin and importance (user agent, user and author styles, with !important reversing priority), cascade layers declared with @layer, specificity, and finally source order, where the later rule wins. Understanding this order explains why a rule sometimes does not apply even though it appears later in the file.
17. What is inheritance in CSS, and which properties are inherited?
Inheritance means some property values pass from a parent element to its children automatically. Text-related properties such as color, font-family, font-size, line-height and text-align inherit by default, while box-related ones such as margin, padding, border and background do not. You can control this explicitly with the keywords inherit, initial, unset and revert.
18. How does `z-index` work and what is a stacking context?
z-index controls the paint order of overlapping elements along the z-axis, but it only applies to positioned elements and to flex or grid items. A stacking context is an isolated group in which z-index values are compared only among its members. It is created by the root element, by positioned elements with a z-index other than auto, and by properties such as opacity below 1, transform and filter. This is why a huge z-index can still appear behind another element in a different context.
19. What are CSS variables (custom properties) and how do you use them?
CSS variables are author-defined properties that start with --, declared on a selector and read with var(). Unlike preprocessor variables they are live in the browser, follow the cascade and inheritance, and can be changed at runtime with JavaScript or overridden in media queries. They are well suited to theming, such as dark mode. var() accepts a fallback as a second argument.
:root { --brand: #0a7cff; }
.btn {
background: var(--brand, blue);
}
20. What is the difference between CSS transitions and animations?
A transition animates a property between two states, typically triggered by a change such as :hover or a class toggle, and it needs a start and end value. An animation uses @keyframes to define multiple steps and can run automatically, loop, alternate and be controlled with properties like animation-iteration-count. Use transitions for simple state changes and animations for complex or repeating sequences.
.box { transition: transform 0.3s ease; }
.box:hover { transform: scale(1.1); }
21. How do you center a div horizontally and vertically?
The simplest modern method is Grid with place-items: center on the parent, or Flexbox with justify-content and align-items set to center. For horizontal-only centering of a block with a set width, use margin-inline: auto. For the older approach, an absolutely positioned element can be offset with top: 50%; left: 50% and transform: translate(-50%, -50%).
.parent {
display: grid;
place-items: center;
min-height: 100vh;
}
22. What is margin collapsing?
Margin collapsing is when the vertical margins of adjacent block elements combine into a single margin equal to the largest of them instead of being added together. It happens between siblings, between a parent and its first or last child when nothing separates them, and for empty blocks. It does not occur in flex or grid containers, with floats, absolutely positioned elements, or when the parent has padding, a border or establishes a new block formatting context, for example via overflow: hidden or display: flow-root.
23. What is the difference between `relative`, `absolute` and `fixed` positioning?
A relative element stays in the normal flow and is offset from its original position, with its original space preserved. An absolute element leaves the flow and is positioned against its nearest ancestor that has a position other than static, or the initial containing block if none exists. A fixed element leaves the flow and is positioned against the viewport, so it stays in place while scrolling.
24. What are the `:nth-child()` and `:nth-of-type()` selectors, and how do they differ?
Both select elements by their position among siblings using an an+b formula. :nth-child(n) counts all sibling elements regardless of tag, and the element must also match any other part of the selector. :nth-of-type(n) counts only siblings of the same element type. So p:nth-child(2) matches a paragraph only if it is the second child overall, while p:nth-of-type(2) matches the second paragraph.
li:nth-child(odd) { background: #f5f5f5; }
25. What are the different ways to include CSS in an HTML page?
There are three ways: inline styles via the style attribute, an internal <style> block in the document, and an external stylesheet linked with <link rel="stylesheet"> or imported with @import. External stylesheets are preferred because they can be cached and shared across pages, and they keep content and presentation separate. Inline styles have the highest specificity and are hard to maintain, and @import is slower because it delays parallel loading.
<link rel="stylesheet" href="styles.css">
26. What are container queries and how do they differ from media queries?
Container queries apply styles based on the size of a parent container rather than the viewport, so a component can adapt to wherever it is placed. You mark the parent with container-type: inline-size and then write an @container rule. Media queries respond to the whole viewport, which breaks down for reusable components that appear in sidebars and main columns.
.card-wrap { container-type: inline-size; }
@container (min-width: 400px) {
.card { display: grid; grid-template-columns: 1fr 2fr; }
}
27. What does the `:is()`, `:where()` and `:not()` selector do, and how does each affect specificity?
:is() matches any selector in its list and takes the specificity of its most specific argument. :where() works the same way but always has zero specificity, which makes it ideal for easily overridable base styles and resets. :not() negates a selector list and also takes the specificity of its most specific argument. All three shorten repetitive selectors.
28. What is the `:has()` selector and what problems does it solve?
:has() is the relational pseudo-class, often called the parent selector, because it matches an element that contains a descendant or is followed by a sibling matching the given selector. It lets you style a card differently when it contains an image, or a form group when its input is invalid, without JavaScript. It is supported in all modern browsers, but complex :has() selectors on large DOMs can be costly, so keep them specific.
.card:has(img) { padding: 0; }
label:has(+ input:invalid) { color: red; }
29. What are cascade layers (`@layer`) and why would you use them?
Cascade layers let you group rules into named layers whose order, not specificity, decides which wins. Rules in a later-declared layer beat earlier layers regardless of selector specificity, and unlayered styles beat all layers. This makes it practical to organise resets, third-party libraries and your own components, and to override a framework without raising specificity or using !important.
@layer reset, vendor, components;
@layer components {
.btn { background: teal; }
}
30. How do `grid-template-areas` work?
grid-template-areas lets you draw a layout by naming cells with strings, where each string is a row and each word is a column. You then assign an element to a region with grid-area. A name repeated across adjacent cells makes the area span them, and a period leaves a cell empty. Areas must form rectangles. It makes layouts very readable and easy to rearrange in media queries.
.page {
display: grid;
grid-template-columns: 200px 1fr;
grid-template-areas:
"header header"
"nav main"
"footer footer";
}
.page > header { grid-area: header; }
31. What is the difference between `auto-fit` and `auto-fill` in `repeat()`?
Both create as many columns as fit the container, but they differ when there are fewer items than columns. auto-fill keeps the empty tracks, so items stay at their set size and blank space remains at the end. auto-fit collapses the empty tracks to zero, so the 1fr items stretch to fill the row. Combined with minmax() this gives a responsive grid without media queries.
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 1rem;
}
32. Why does `flex-shrink` cause items to shrink below the width you set, and how do you prevent it?
Flex items default to flex-shrink: 1, so when the total size exceeds the container, items shrink in proportion to their base size, which can squash images or buttons. Set flex-shrink: 0 on items that must keep their size, or use flex: none. Also remember that flex items have min-width: auto, so long text or wide content may refuse to shrink and overflow unless you set min-width: 0.
33. Why does a long text or wide child overflow a flex or grid item, and how do you fix it?
Flex and grid items have an automatic minimum size equal to their content, so they will not shrink below the width of a long word, URL or wide child. The fix is to set min-width: 0 on the item, or overflow: hidden, which also changes the automatic minimum. For grid tracks, use minmax(0, 1fr) instead of plain 1fr. Then add overflow-wrap: anywhere or text-overflow: ellipsis to handle the text itself.
.col { min-width: 0; }
.grid { grid-template-columns: minmax(0, 1fr) 300px; }
34. How do you truncate text with an ellipsis, on one line and on multiple lines?
For a single line, combine overflow: hidden, white-space: nowrap and text-overflow: ellipsis on a block with a constrained width. For multiple lines, use line-clamp, which works in current browsers with the -webkit- prefixed box setup, and the unprefixed line-clamp is gaining support. Always make sure the full text is still accessible, for example through a title or an expand control.
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;
}
35. What is the difference between `em`-based and `rem`-based media queries, and why might you prefer one?
In media queries, both em and rem refer to the browser's initial font size, not the page's CSS, so they scale when a user changes their default text size. Using them instead of px means layouts break to a single column at a sensible point for users who enlarge their text, which improves accessibility. Pixel breakpoints ignore this preference, so rem or em breakpoints are the more robust choice.
36. What is the difference between `transform` animations and animating `top`/`left`, and why does it matter for performance?
Animating transform and opacity can run on the compositor thread without triggering layout or paint on every frame, so they stay smooth even when the main thread is busy. Animating top, left, width or margin forces layout recalculation each frame, which is costly and causes jank. Prefer translate, scale and opacity, and use will-change sparingly because it consumes memory.
.slide { transition: transform 0.3s; }
.slide.open { transform: translateX(0); }
37. What are reflow and repaint, and how can CSS help avoid them?
Reflow (layout) is when the browser recalculates element sizes and positions, and repaint is when it redraws pixels without changing geometry. Changes to dimensions, fonts or DOM structure trigger reflow, which also triggers repaint, while a colour change triggers only repaint. To reduce cost, animate compositor-friendly properties, avoid reading layout values in loops with JavaScript, and use contain or content-visibility: auto to limit the work to part of the page.
38. What does `content-visibility: auto` do?
content-visibility: auto lets the browser skip rendering work for an element until it is near the viewport, which can greatly speed up the initial render of long pages. Pair it with contain-intrinsic-size so the skipped section reserves an estimated height and the scrollbar does not jump. It is best applied to large offscreen sections such as long feeds or article blocks.
.section {
content-visibility: auto;
contain-intrinsic-size: auto 600px;
}
39. How would you implement a dark mode using CSS only?
Define colours as custom properties on :root, then override them inside a prefers-color-scheme: dark media query so the page follows the system setting. For a manual toggle, scope the overrides to a data-theme attribute on the root element and set it with a small script. Declaring color-scheme: light dark also makes native controls and scrollbars match the theme.
:root { color-scheme: light dark; --bg: #fff; --fg: #111; }
@media (prefers-color-scheme: dark) {
:root { --bg: #121212; --fg: #eee; }
}
body { background: var(--bg); color: var(--fg); }
40. What does `aspect-ratio` do, and how does it replace the old padding-bottom hack?
aspect-ratio sets a preferred width-to-height ratio on an element, so the browser calculates one dimension from the other. It replaces the old technique of a wrapper with padding-bottom: 56.25% and an absolutely positioned child. It is useful for video embeds, cards and image placeholders that prevent layout shift while content loads. Combine it with object-fit: cover for images.
.video { aspect-ratio: 16 / 9; width: 100%; }
img { aspect-ratio: 4 / 3; object-fit: cover; }
41. What is the difference between `object-fit` values `cover`, `contain` and `fill`?
object-fit controls how replaced content such as an image or video is resized to fit its box. fill is the default and stretches the content, distorting it. contain scales it to fit entirely inside the box while keeping the aspect ratio, leaving empty bars. cover scales it to fill the whole box while keeping the ratio and crops any overflow. object-position adjusts which part is kept.
42. How does `clamp()` work and how would you use it for fluid typography?
clamp(min, preferred, max) returns the preferred value, but never below the minimum or above the maximum. For fluid type, use a viewport-based middle value so the font grows with the screen between two limits, without media queries. Include a rem term in the preferred value so the text still responds to user zoom settings, which pure vw values do not.
h1 {
font-size: clamp(1.75rem, 1rem + 3vw, 3rem);
}
43. What is the difference between `em` and `rem` pitfalls in nested components, and what does `1em` mean in `padding`?
In properties other than font-size, 1em equals the element's own computed font size, so padding set in em scales with the text of that component, which is handy for buttons. The pitfall is nested em on font-size, where each level multiplies the parent's size, so a list inside a list can shrink or grow unexpectedly. Use rem for font sizes and em for component-relative spacing.
44. How do `min-content`, `max-content` and `fit-content` sizing keywords work?
min-content is the smallest width at which content does not overflow, usually the longest word. max-content is the width the content would take on a single line with no wrapping. fit-content behaves like max-content but never exceeds the available space, so it shrinks to wrap. They are useful for sizing tooltips, buttons and grid tracks to their content.
.tag { width: fit-content; }
.grid { grid-template-columns: min-content 1fr; }
45. How do CSS logical properties help with internationalisation?
Logical properties replace physical directions like left and margin-right with flow-relative ones such as inline-start, margin-inline-end and padding-block. They follow the writing mode and text direction, so one stylesheet works for left-to-right, right-to-left and vertical languages without separate overrides. For example margin-inline-start is the left margin in English and the right margin in Arabic.
.icon { margin-inline-end: 0.5rem; }
46. What is the difference between `@supports` and feature detection with fallbacks, and when would you use `@supports`?
@supports is a CSS conditional rule that applies styles only if the browser understands a given property and value, enabling progressive enhancement. Since unknown declarations are simply ignored, a simple fallback declaration before the modern one often suffices. Use @supports when the new feature changes the whole layout, for example wrapping a display: grid layout so the fallback styles do not conflict with it.
.gallery { display: flex; flex-wrap: wrap; }
@supports (display: grid) {
.gallery { display: grid; }
}
47. What does `position: sticky` need to work, and why might it fail?
position: sticky needs at least one inset such as top: 0 to define the threshold, and it sticks only within its containing block. It commonly fails because an ancestor has overflow set to hidden, auto or scroll, which becomes the scroll container, or because the parent is no taller than the sticky element. A flex parent with the default align-items: stretch can also defeat it, so use align-self: flex-start.
48. What is wrong with this code, and why does the child not fill the parent's height?
Percentage heights resolve against the containing block, and if the parent's own height is auto the percentage computes to auto, so it has no effect. Every ancestor up to the root must have a definite height, including html and body. Modern alternatives are min-height: 100dvh on the container, or using Flexbox or Grid, where stretch behaviour fills the space without percentages.
.parent { height: 100%; }
.child { height: 100%; }
49. How do you structure CSS for a large project, and what are the trade-offs of BEM, utility-first and CSS Modules?
Pick a convention that keeps specificity flat and names predictable. BEM uses block__element--modifier class names, which is simple and framework-free but verbose. Utility-first CSS such as Tailwind composes small single-purpose classes, giving fast development and tiny output, at the cost of busy markup. CSS Modules scope class names per component automatically, avoiding collisions but requiring a build step. Whatever you choose, avoid deep nesting and ID selectors.
50. How do you reduce the render-blocking impact of CSS and improve page performance?
CSS is render-blocking, so the browser will not paint until it has downloaded and parsed it. Inline the critical above-the-fold CSS in the <head>, load the remainder asynchronously, and use media attributes so non-matching stylesheets do not block rendering. Minify and compress files, remove unused rules, avoid @import chains, and use preload for key resources such as fonts, with font-display: swap.
<link rel="stylesheet" href="print.css" media="print">
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>