Module 12: Interview Questions
Coding Exercises with Solutions and Reasoning
Ten hands-on CSS exercises typical of interviews, from centering and layout to text truncation and debugging, each with a worked solution and the reasoning behind it.
Coding rounds in CSS are usually small, specific and a little unfair: you have 15 minutes and a blank editor. What interviewers watch is how you think. Do you reach for the right tool, explain your choice, and handle the edge cases without being asked?
Try each exercise yourself before reading the solution. Time yourself.
Exercise 1: Center a box in three ways#
Task. Center a 200 by 100px box inside a full-height container, horizontally and vertically.
<div class="parent"><div class="box">Hi</div></div>
Solution A: grid.
.parent { display: grid; place-items: center; min-height: 100dvh; }
.box { width: 200px; height: 100px; }
Solution B: flex.
.parent { display: flex; justify-content: center; align-items: center; min-height: 100dvh; }
Solution C: absolute with auto margins.
.parent { position: relative; min-height: 100dvh; }
.box { position: absolute; inset: 0; margin: auto; width: 200px; height: 100px; }
Reasoning. In A and B the parent distributes space, which is the layout-native approach. In C, inset: 0 stretches the box to all four edges, and with a fixed size and margin: auto the leftover space is split equally in every direction. If the size were unknown, you would use top: 50%; left: 50%; transform: translate(-50%, -50%). Say out loud why you chose one: I prefer A for a single child because it is two lines.
Exercise 2: The classic page layout#
Task. Header, footer, a left nav, a right aside and a main area. The footer sticks to the bottom on short pages. On screens narrower than 700px, stack everything with the main content first after the header.
Solution.
.page {
display: grid;
min-height: 100dvh;
grid-template:
"header header header" auto
"nav main aside" 1fr
"footer footer footer" auto
/ 12rem minmax(0, 1fr) 12rem;
}
.page > header { grid-area: header; }
.page > nav { grid-area: nav; }
.page > main { grid-area: main; }
.page > aside { grid-area: aside; }
.page > footer { grid-area: footer; }
@media (max-width: 700px) {
.page {
grid-template:
"header" auto
"main" 1fr
"nav" auto
"aside" auto
"footer" auto
/ minmax(0, 1fr);
}
}
Reasoning. Named areas make the layout readable, and the responsive version is only a redefinition of the template, with no HTML changes. The 1fr row makes the middle row absorb the extra height, which pushes the footer down. minmax(0, 1fr) prevents wide content, like a code block, from stretching the main column. The shorthand grid-template takes rows with their areas and then / columns.
Exercise 3: Equal-height cards with pinned buttons#
Task. Three cards in a row with different amounts of text. All cards have the same height, and each card's button sits at the bottom.
<div class="cards">
<article class="card"><h3>Short</h3><p>One line.</p><a class="btn" href="#">Go</a></article>
<article class="card"><h3>Long</h3><p>Much more text that wraps over several lines...</p><a class="btn" href="#">Go</a></article>
</div>
Solution.
.cards { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr)); }
.card { display: flex; flex-direction: column; padding: 1rem; border: 1px solid #ddd; border-radius: 10px; }
.card .btn { margin-top: auto; align-self: flex-start; }
Reasoning. Grid items stretch to the row height by default, so the cards are equal in height without extra code. Inside each card, a column flex container with margin-top: auto on the button eats all the free space above it, so the button is always at the bottom. align-self: flex-start stops the button from stretching to full width.
Exercise 4: Truncate text#
Task. (a) Truncate a title to a single line with an ellipsis. (b) Clamp a description to three lines.
Solution.
.title {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.description {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
line-clamp: 3;
overflow: hidden;
}
Reasoning. text-overflow only works on an element that clips its overflow, and the text must not wrap, so all three properties are required. Multi-line clamping still relies on the legacy -webkit-box mechanism, which all major browsers support under the prefixed names. Mention the edge cases: inside a flex item the title also needs min-width: 0, and users lose access to the hidden text, so provide it through a title attribute or an expandable control when it matters.
Exercise 5: Responsive gallery with no media queries#
Task. Images in a grid that has as many columns as fit, with a minimum width of 200px, each image a square.
Solution.
.gallery { display: grid; gap: 0.75rem; grid-template-columns: repeat(auto-fill, minmax(min(200px, 100%), 1fr)); }
.gallery img { width: 100%; aspect-ratio: 1; object-fit: cover; }
Reasoning. repeat with auto-fill and minmax lets the browser decide how many columns fit. min(200px, 100%) avoids overflow in very narrow containers. aspect-ratio: 1 plus object-fit: cover makes every image a square regardless of its source proportions, cropping rather than stretching. Using auto-fill here, instead of auto-fit, keeps the tile size consistent when there are only a few images. If asked why, the answer is that auto-fit would stretch two images across the whole row.
Exercise 6: An accordion with no JavaScript#
Task. A FAQ list where clicking a question reveals the answer.
Solution.
<details class="faq">
<summary>What is the box model?</summary>
<p>Every element is a box made of content, padding, border and margin.</p>
</details>
.faq { border-bottom: 1px solid #ddd; }
.faq summary { display: flex; justify-content: space-between; padding: 1rem 0; cursor: pointer; list-style: none; }
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: "+"; font-weight: 700; }
.faq[open] summary::after { content: "−"; }
.faq summary:focus-visible { outline: 3px solid #2f5bea; outline-offset: 2px; }
Reasoning. The right answer starts with HTML: details and summary already provide the toggle, keyboard support (Enter and Space) and accessibility semantics. CSS only styles it. The checkbox hack from the combinators lesson also works, but it is a workaround for something the platform now does natively, and a native element is better for assistive technology. If an interviewer wants the animation, mention that animating the open state needs the grid-rows technique or newer features, and be honest about support.
Exercise 7: A tooltip arrow and a triangle#
Task. Draw a small triangle with CSS and use it as the arrow of a tooltip.
Solution.
.tooltip {
position: relative;
padding: 0.5rem 0.75rem;
border-radius: 6px;
background: #111827;
color: #fff;
}
.tooltip::after {
content: "";
position: absolute;
top: 100%;
left: 50%;
width: 12px;
height: 8px;
transform: translateX(-50%);
background: inherit;
clip-path: polygon(0 0, 100% 0, 50% 100%);
}
Reasoning. ::after with content: "" creates a box. Absolutely positioning it at the bottom edge (top: 100%) and clipping it to a triangle with clip-path gives the arrow. background: inherit keeps the arrow the same color as the tooltip, so a theme change does not need two updates. The older solution is a zero-size box with a transparent border on three sides and a color on one, and it is worth recognizing if you see it in legacy code:
.arrow { width: 0; height: 0; border-left: 6px solid transparent; border-right: 6px solid transparent; border-top: 8px solid #111827; }
Exercise 8: Sticky header that does not hide anchor targets#
Task. A header that stays at the top. Clicking an in-page link must not scroll the target under the header.
Solution.
.site-header { position: sticky; top: 0; z-index: 100; height: 4rem; background: #fff; }
section[id], h2[id] { scroll-margin-top: 5rem; }
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
}
Reasoning. scroll-margin-top tells the browser to leave extra space above the element when scrolling to it. It replaces JavaScript offset calculations that used to be common. Use a value a little larger than the header height. Smooth scrolling is wrapped to respect users who requested reduced motion. If sticky does not work, remember to check ancestors for overflow.
Exercise 9: Responsive video embed and cover image#
Task. Make an iframe video keep a 16:9 ratio at any width, and a hero image fill a 3:1 banner without distortion.
Solution.
.video { aspect-ratio: 16 / 9; width: 100%; }
.video iframe { width: 100%; height: 100%; border: 0; }
.banner { width: 100%; aspect-ratio: 3 / 1; object-fit: cover; object-position: center 30%; }
Reasoning. aspect-ratio sets the height from the width, so there is no need for the old padding-percentage hack. The iframe fills its wrapper. object-fit: cover crops the image to fit the banner without distortion, and object-position selects which part stays visible, for example keeping faces in view.
Exercise 10: Debug this stylesheet#
Task. Six things are wrong. Find them.
<div class="card">
<h3 class="title">Plan</h3>
<button class="btn primary">Buy</button>
</div>
<div class="badge">New</div>
// card styles
.card {
width: 100%
padding: 24px;
border: 1px solid #ccc;
}
.btn .primary { background: #2f5bea; color: white; }
.badge { z-index: 10; top: 0; right: 0; }
.panel { height: 100%; }
Solution.
//is not a CSS comment. The browser reads it as part of the next selector, and the.cardrule is invalidated. Use/* card styles */.- A missing semicolon after
width: 100%. Without it, the next line is merged into the value and both declarations fail. Add the;. width: 100%with padding and a border overflows the parent undercontent-box. Addbox-sizing: border-box(globally), or drop the width and let the block fill naturally..btn .primaryis a descendant selector. It looks for an element withprimaryinside.btn. The button has both classes itself, so the selector should be.btn.primary.z-index,topandrighton.badgedo nothing because it isposition: static. It needsposition: absolute(with a positioned parent) or another non-static value..panel { height: 100% }works only if its parent has a defined height. Otherwise it behaves likeauto. Give the parent a height, or use a layout method such as flex or grid to distribute space.
Reasoning. Each bug maps to a lesson from this course: syntax and error recovery, box sizing, selectors, positioning, and percentage heights. When you debug aloud, say which tool you would use to find each one. For instance, the Styles pane would show the whole .card rule missing, and the warning icons would point to invalid values.
Practice#
- Do all ten exercises again from a blank file, with a timer, and note which one took longest.
- For Exercise 3, write a second version using only grid, no nested flex. Compare the HTML and CSS.
- Invent two more debugging exercises like Exercise 10 and give them to a friend or write down the answers.
- For each exercise, write a one-sentence justification you could say to an interviewer while typing: what you chose, and why it beats the alternative.