Every element is a box: content → padding → border → margin, from inside out. `box-sizing: content-box` (default) makes width/height apply to content only, so padding+border add to the rendered size. `box-sizing: border-box` makes width/height include padding+border — far more predictable, which is why most resets set it globally. Margins also collapse vertically.
Category
CSS
Layout, specificity, animations, modern Grid/Flex.
30 questions
Box = content + padding + border + margin. Default `box-sizing: content-box` excludes padding/border from width — your 200px width becomes 220px on screen with 10px padding. `border-box` includes them: 200px is 200px. Set border-box globally.
px is an absolute, fixed unit. em is relative to the current element's font-size and compounds when nested. rem is relative to the root (html) font-size — consistent, no compounding. Use rem for scalable, accessible sizing; em for things that should scale with their local context.
The cascade resolves conflicts by: origin/importance > specificity > source order. Specificity is a 3-tuple (IDs, classes/attrs/pseudo-classes, type/pseudo-elements). `!important` and inline styles short-circuit the normal flow.
Pseudo-classes (:hover, :focus, :nth-child) style elements in a particular STATE or position — single colon. Pseudo-elements (::before, ::after, ::first-line) style or create a specific PART of an element — double colon. One targets state, the other targets sub-parts.
display:none removes the element entirely — no box, no space taken, not in layout, not announced to screen readers, can't be focused. visibility:hidden hides it visually but it STILL occupies its space in layout and affects siblings. opacity:0 is a third option (visible to a11y/events). Toggling display triggers reflow.
display:none removes from the layout AND a11y tree (no space, not focusable). visibility:hidden reserves space but hides + removes from a11y. opacity:0 reserves space and IS still interactive + announced — usually a bug if you wanted 'hidden'.
static = default flow. relative = in flow but offsettable + new positioning context. absolute = removed from flow, anchored to nearest positioned ancestor. fixed = anchored to viewport (or transformed ancestor). sticky = relative until a threshold, then fixed within scroll container.
static: default, in normal flow, ignores top/left. relative: in flow but offset from its own position, becomes a positioning context. absolute: removed from flow, positioned against the nearest positioned ancestor. fixed: removed from flow, positioned against the viewport. sticky: hybrid — in flow until it hits a scroll threshold, then sticks.
CSS custom properties (`--name: value`) are real CSS variables — they cascade, inherit, can be scoped to any selector, read with `var(--name, fallback)`, and changed at runtime via JS or media queries. Unlike Sass variables (compile-time, static), they're live in the browser, which makes them ideal for theming, dark mode, and component APIs.
Modern answer: `display: grid; place-items: center;` on the parent, or `display: flex; justify-content: center; align-items: center;`. Both center a child along both axes in one rule.
The modern answer is Flexbox (display:flex; justify-content:center; align-items:center) or Grid (display:grid; place-items:center) on the parent. Older/edge approaches: absolute + transform translate(-50%,-50%), or margin:auto inside a flex/grid container. Know which works without knowing the element's size.
Control flex item width with the `flex` shorthand: `flex-grow` (share of extra space), `flex-shrink` (share of overflow reduction), `flex-basis` (starting size). `flex: 1` makes items share space equally; different grow values or explicit `flex-basis`/`width` give different widths. `flex: 0 0 200px` fixes a width; `flex: 2` vs `flex: 1` makes a 2:1 ratio.
Set the divs to `display: inline-block` (or `display: inline`) — they then flow horizontally like text instead of stacking as block elements. The hint's catch: inline-block elements get whitespace gaps from newlines in the HTML; remove them by setting `font-size: 0` on the parent, putting the divs on one line, or using HTML comments between them.
Flexbox is one-dimensional (a row OR a column). Grid is two-dimensional (rows AND columns at once). Use flex for component layouts and toolbars, grid for page templates, dashboards, and any 2D alignment.
Flexbox is one-dimensional (lay out items along a single row OR column); Grid is two-dimensional (rows AND columns together). Flexbox is content-driven and great for components (toolbars, nav, centering); Grid is layout-driven and great for page-level structure. They compose — Grid for the macro layout, Flexbox inside the cells.
CSS Grid. Product grids are inherently 2D (rows AND columns of equal-sized cards), and Grid handles that natively with one rule: 'grid-template-columns: repeat(auto-fill, minmax(240px, 1fr))'. It gives equal column widths, fluid responsiveness without media queries, and aligned rows automatically. Flexbox is 1D — to fake a grid you fight wrap behavior, leftover-item alignment, and equal heights. Use Flexbox inside each card; Grid for the layout.
Use CSS Grid for the responsive grid: `grid-template-columns: repeat(auto-fill, minmax(min, 1fr))` adapts column count to viewport with zero media queries; add `gap` for spacing. Use Flexbox inside each cell for its internal layout. Layer in `clamp()` for fluid sizing and a few media queries only for major layout changes.
Without the viewport meta tag, mobile browsers render at a ~980px virtual width and scale down — text becomes tiny, taps misalign, and media queries never trigger because the layout viewport ≠ visual viewport. The standard tag `<meta name="viewport" content="width=device-width, initial-scale=1">` ties layout width to device-independent pixels so responsive CSS works as designed.
Fluid layouts (flex/grid + %), relative units (`rem`/`em`/`ch`/`vw`/`vh`), breakpoints via `@media (min-width)` (mobile-first), `clamp()` for fluid type, container queries for component-local responsiveness, `<picture>`/srcset for images, and a viewport meta tag. Layer with logical properties (`margin-inline`) for i18n/RTL.
CSS methodologies (BEM, SMACSS, OOCSS, ITCSS) impose naming and structure conventions to keep CSS scalable and avoid specificity wars. BEM (Block__Element--Modifier) keeps selectors flat and components self-contained. Responsive design uses media queries (mobile-first: base styles + `min-width` breakpoints) plus fluid units and modern intrinsic layout (clamp, auto-fill grid).
Mobile-first: write base styles for narrow viewports, layer min-width media queries to upgrade. Use rem/em + clamp() for fluid type. Container queries (@container) let components respond to their slot, not the viewport.
Beyond layout: responsive means adapting layout, content, interactions, media, and performance to the device. Mobile-first fluid layouts, container queries for components, responsive images, touch vs pointer handling, and shipping less to constrained devices.
Build mobile-first with fluid layouts (flex/grid), relative units, and a small set of meaningful breakpoints driven by content — not devices. Add the viewport meta tag, use responsive images, and test on real constraints.
Tailwind is utility-first (compose from atomic classes); Bootstrap is component-first (pre-built components). Tailwind gives a tiny purged bundle, design consistency via a config-driven token system, no naming or context-switching, and full design freedom. Bootstrap is faster for generic UIs but produces sites that look the same and harder to customize. Traditional CSS scales poorly without conventions.
At scale the real problems are global scope, specificity wars, dead code, and theming. Pick a scoping strategy — CSS Modules, CSS-in-JS (runtime or zero-runtime), or utility-first (Tailwind) — layered with design tokens as CSS custom properties for theming. There's no single right answer; the senior move is matching the choice to team size, SSR needs, and performance budget.
Start from a baseline: a CSS reset/normalize, then build with well-supported standards and check caniuse. Use feature detection (`@supports`) over browser sniffing, progressive enhancement, autoprefixer for vendor prefixes, fluid/intrinsic layouts that tolerate variation, and a real cross-browser test matrix (BrowserStack + the main engines). Accept pixel-perfect-everywhere is the wrong goal — robust and acceptable is.
Use a normalize/reset stylesheet, modern layout primitives (flex/grid), feature detection (@supports), autoprefixer + browserslist, polyfills only where needed, and test on real Safari/iOS plus BrowserStack matrix.
Make it reproducible first — gather environment data, use RUM and session replay, test across real browsers. Intermittent + cross-browser usually means a race condition, a browser-engine difference, or a third-party script/extension. Isolate by binary search, instrument the suspect, fix the root cause, add a regression test.
Reproduce systematically — gather environment data, use RUM/session replay, test across browsers. Intermittent + browser-specific points to race conditions, CSS/JS engine differences, third-party scripts, or extensions. Isolate, instrument, and narrow with a binary search.