Module 12: Interview Questions
Layout and Responsive Design Questions
Questions on Flexbox, Grid, positioning, centering, media and container queries, viewport units and responsive images, answered with the reasoning interviewers listen for.
Layout questions are where interviewers separate people who have memorized properties from people who have built real interfaces. The strongest answers explain the algorithm behind the behavior, and name the trade-offs.
Q1. When do you choose Flexbox, and when Grid?#
Flexbox is one-dimensional. It distributes items along a single axis and lets their content size influence the layout. Use it for toolbars, navbars, button groups, centering, and any row or column of items of varying size.
Grid is two-dimensional. You define rows and columns first, then place content into them, so tracks line up in both directions. Use it for page skeletons, dashboards, card galleries and anything where rows and columns must align.
They combine. A page is often a grid of regions, each region being a flex container for its internals. A useful heuristic: if you are wrapping flex items onto several lines and wish the columns lined up, you wanted Grid.
Q2. How many ways can you center an element? Which do you use?#
For a block horizontally: margin-inline: auto with a width or max-width. For inline content: text-align: center on the parent.
For both axes, today:
.parent { display: grid; place-items: center; }
or with flex:
.parent { display: flex; justify-content: center; align-items: center; }
For absolutely positioned elements: inset: 0; margin: auto with a size, or top: 50%; left: 50%; transform: translate(-50%, -50%) for unknown sizes.
I reach for grid with place-items: center for a single child, and flex when there are several items to align.
Q3. What does flex: 1 mean exactly?#
It is shorthand for flex: 1 1 0%: grow factor 1, shrink factor 1, and a flex-basis of zero. Because the basis is zero, every item starts with no size and splits all the free space by its grow factor, so items with flex: 1 end up equal widths regardless of content. Compare with flex: auto (1 1 auto), where each item starts at its content size and then shares the leftover, so longer content gives a wider item.
If you set width on an item that also has flex: 1, the width is ignored for sizing, since the basis takes precedence.
Q4. A flex child with long text refuses to shrink and overflows. Why?#
Flex items have min-width: auto, which means they will not shrink below their minimum content size. A long unbroken string, a wide image or a pre block holds the item open. The fix is min-width: 0 on the item (and overflow: auto or overflow-wrap: anywhere on the content). The same applies vertically with min-height: 0 in column layouts, and to text-overflow: ellipsis inside a flex item.
The Grid equivalent is the 1fr blowout: 1fr is minmax(auto, 1fr), so the fix is minmax(0, 1fr).
Q5. What is the difference between auto-fit and auto-fill in repeat()?#
Both create as many columns as fit. auto-fill keeps the empty tracks, so existing items stay at their column width and there may be blank space at the end. auto-fit collapses the empty tracks to zero, so the items stretch to occupy the full row. With a full row of items they behave the same. They differ when there are fewer items than fit.
grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr));
The min(15rem, 100%) prevents overflow in containers narrower than 15rem.
Q6. Explain the position values. What is an absolutely positioned element positioned against?#
static is the default: normal flow, offsets ignored. relative stays in flow and shifts visually, keeping its original space.
absolute leaves the flow and is positioned against its containing block: the padding box of the nearest ancestor that is not static (or has a transform or similar), and the initial containing block if none exists.
fixed is positioned against the viewport, unless an ancestor has a transform, filter or similar. sticky acts like relative until it crosses a scroll threshold, then sticks, but only within its parent's bounds.
The classic bug is forgetting position: relative on the parent, so the child flies to the page corner.
Q7. position: sticky does nothing. What do you check?#
- Is there a threshold set (
top,bottom, and so on)? Without one, sticky has nothing to react to. - Does any ancestor have
overflowset tohidden,autoorscroll? That ancestor becomes the scroll container that sticky binds to, and if it does not scroll, nothing sticks. - Is the parent as tall as the sticky element? The element cannot leave its parent's box.
- Is it inside a flex or grid container with
align-items: stretch? A stretched item has no room to move.align-self: startoften fixes it.
Q8. Why is the viewport meta tag needed?#
Without width=device-width, initial-scale=1, mobile browsers lay the page out in a virtual viewport around 980px wide and then scale it down. Your mobile media queries never fire because the browser believes the screen is wide. The tag tells the browser to use the real device width for layout.
Q9. Mobile-first versus desktop-first?#
Mobile-first writes the base styles for the smallest screen and adds complexity with min-width queries. Each query adds to what came before, and you never have to undo styles. Desktop-first writes the full layout and uses max-width queries to simplify, which tends to create override chains and makes the base case the most complex.
Mobile-first also fits how browsers parse. The phone, usually the weakest device, gets the simplest rules as its default.
Breakpoints should come from where the content breaks, not from device names.
Q10. Media queries versus container queries?#
A media query measures the viewport. A container query measures a specific ancestor that declared container-type. For page-level changes and user preferences (prefers-color-scheme, prefers-reduced-motion, print), use media queries. For reusable components that may appear in a sidebar or a wide main column, use container queries, so the component responds to the space it actually has.
One subtlety: a container query applies to descendants of the container, never to the container itself, so you need a wrapper and an inner element.
Q11. A hero with height: 100vh is cut off by the browser toolbar on phones. What is happening?#
On mobile browsers, the address bar slides in and out as you scroll. 100vh is computed against the largest viewport (toolbar hidden), so at first load the bottom of the element is under the toolbar. Use 100dvh (dynamic viewport height), which tracks the visible area, or 100svh (small viewport height) for the always-visible area. Write height: 100vh; height: 100dvh; for a fallback.
Q12. How do you make images responsive and avoid layout shift?#
Use img { max-width: 100%; height: auto; } so images shrink to fit. Add width and height attributes that match the file's natural size, so the browser can reserve space from the aspect ratio before loading. Use srcset and sizes for resolution switching, picture for art direction or format selection, loading="lazy" for offscreen images (not the main hero image), and object-fit with aspect-ratio for consistently cropped thumbnails.
Q13. How would you build a layout with a sticky footer?#
body { min-height: 100dvh; display: grid; grid-template-rows: auto 1fr auto; }
with header, main, footer as children, or with flex:
body { min-height: 100dvh; display: flex; flex-direction: column; }
main { flex: 1; }
On short pages the main area takes all the free space, pushing the footer down. On long pages it simply follows the content.
Q14. When would you use gap instead of margins?#
Almost always, in flex and grid. gap adds space only between items, so there is no stray margin on the first or last element and no need for :last-child overrides. It is also controlled in one place, on the parent, so a component does not need to know about its neighbors.
Q15. How do you tame a z-index mess?#
Find out why the order is wrong, which is nearly always a stacking context created by an ancestor (transform, opacity, position with z-index). Then contain each component with isolation: isolate so its internal z-indexes cannot leak. Define a short global scale (dropdown, sticky, modal, toast) in custom properties. Render modals with the native dialog element, whose showModal() uses the top layer and sidesteps the whole problem.
Practice#
- Choose five questions and write the CSS to demonstrate each answer in a small CodePen or local file. Prove it by breaking it first.
- For Q4 and Q7, build the broken version intentionally and write down your debugging steps in DevTools.
- Explain Q1 aloud to someone without a CSS background, with a drawing of rows, columns and axes.
- Create a list of the five layout bugs you have personally hit, and for each one write the two-sentence answer you would give in an interview.