CSS is often underestimated, but deep knowledge of layout and rendering is crucial for frontend roles. These questions test your understanding of the cascade, box model, and modern layout techniques.
Every HTML element is a rectangular box with four layers: Content (the actual text/image), Padding (space between content and border), Border (the visible edge), and Margin (space outside the border, separating from other elements). Understanding this is fundamental to all CSS layout.
Flexbox: One-dimensional layout (row OR column). Best for distributing space among items in a single axis—navbars, card rows, centering content. Grid: Two-dimensional layout (rows AND columns simultaneously). Best for complex page layouts, dashboards, and magazine-style designs. Use both together: Grid for page layout, Flexbox for component internals.
Specificity determines which CSS rule wins when multiple rules target the same element. The hierarchy (highest to lowest):
!important (avoid using)static: Default. Element flows normally.
relative: Offset from its normal position; creates a positioning context for children.
absolute: Removed from flow; positioned relative to the nearest positioned ancestor.
fixed: Positioned relative to the viewport; stays in place on scroll.
sticky: Hybrid—acts like relative until you scroll past a threshold, then sticks like fixed.
z-index controls the stacking order of positioned elements. Higher values appear in front. Key gotcha: it only works on positioned elements (not static) and creates "stacking contexts." A child can never appear above its parent's stacking context, regardless of z-index.
By default (content-box), width only includes content—padding and border are added on top, making layout math annoying. border-box includes padding and border IN the width. Always use: *, *::before, *::after { box-sizing: border-box; }
Pseudo-classes (:hover, :focus, :nth-child()): Select elements based on state or position.
Pseudo-elements (::before, ::after, ::first-letter): Style or create specific parts of an element.
Notation: single colon for classes, double for elements (though single works for legacy reasons).
CSS variables allow you to define reusable values: --primary-color: #3b82f6;. Use with var(--primary-color). Unlike preprocessor variables, they cascade, inherit, and can be changed at runtime with JavaScript. Essential for theming (dark mode).
Media queries apply styles conditionally based on device characteristics (width, orientation, etc.). Common pattern: @media (min-width: 768px) { ... } for tablets and up. Modern approach: design mobile-first, then add larger breakpoints.
em: Relative to the parent element's font size. Compounds in nested elements (can get confusing).
rem: Relative to the root (html) element's font size. Consistent and predictable.
Best practice: Use rem for most sizing, em for component-specific scaling.
Preprocessors add features like variables, nesting, mixins, and functions to CSS. Modern CSS has caught up with variables and nesting, but mixins and advanced functions still make preprocessors valuable. Sass (SCSS syntax) is the most popular.
Block Element Modifier—a naming convention that prevents CSS conflicts: .card, .card__title, .card--featured. Structure: Block (standalone component), Element (part of a block, uses __), Modifier (variation, uses --). Makes CSS predictable and maintainable.
Critical CSS extracts the minimum CSS needed to render above-the-fold content and inlines it in the HTML. The rest loads asynchronously. This dramatically improves First Contentful Paint (FCP). Tools like Critters automate this in build pipelines.
display: none: Element is removed from the document flow entirely. Takes up no space. Not accessible to screen readers.
visibility: hidden: Element is invisible but still occupies space in the layout. Still in the accessibility tree.
Use opacity: 0 for animations where you need to transition visibility.
Reset (Meyer's Reset): Strips ALL default browser styles to a blank slate. Requires you to define everything.
Normalize: Preserves useful defaults but fixes cross-browser inconsistencies.
Modern approach: Use a minimal reset like *, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }