CSS · Responsive layout
Castaway: fixing responsive layout, from problem to result
Author: Grundy · Checked: October 6, 2026
This review documents actual changes to the educational Castaway demo. We measured overflow and inspected CSS constraints, fixed the implementation and repeated the checks. Each section explains the problem, cause, implemented change and result. Code excerpts show the relevant rules; the updated demo is linked below.
1. Recorded the overflow
Before the fixes, a 375px window produced a 935px-wide page. At 768px, the page was still 935px wide. Episodes, the contact panel and reviews were the main contributors. Fixed 70px side paddings, horizontal flex cards and three review columns could not fit together. The original grid below required at least 790px before section padding.
.reviews {
display: grid;
grid-template-columns: repeat(3, minmax(250px, 1fr));
gap: 20px;
}2. Made section spacing flexible
In section.module.css, replaced fixed left and right paddings with padding-inline and clamp. Spacing now ranges from 16px to 70px. Narrow-screen section top spacing is reduced to 56px. This gives content room instead of masking overflow with overflow-x: hidden.
.section {
padding-inline: clamp(16px, 5vw, 70px);
}3. Stacked the hero and restored normal flow
The hero stayed horizontal and Listen on used a relative top: 74px offset. At widths up to 900px, switched to a column, allowed children to shrink with min-width: 0 and removed the links’ offset. The photo now fits its container, and the decoration no longer extends to the left on small screens.
.hero { gap: clamp(24px, 4vw, 60px); }
.hero > * { min-width: 0; }
.listenOn { position: static; padding-left: 0; margin-top: 32px; }
@media (max-width: 900px) {
.hero { flex-direction: column; align-items: stretch; }
.underline { width: 100%; height: auto; }
}4. Resized headings and their child spans
The hero used 70px text and child fragments at 75px and 80px. Reducing only the parent would leave those fragments oversized. Added clamp sizing and inherited child sizes, with relative line-height. Episode, host and subscription headings were adjusted too. The decorative underline scales on narrow screens.
.heroTitle {
font-size: clamp(2rem, 1rem + 4vw, 4.375rem);
line-height: 1.2;
letter-spacing: 0.03em;
}
.heroTitle_bold, .heroTitle_span {
font-size: inherit;
letter-spacing: inherit;
}5. Fixed card constraints and the invalid gap
Cards had non-shrinking images, a 53px gap and 40px padding. Made the images flexible, added min-width: 0 to text and stacked cards up to 900px. The episode list also had gap: 80 without a unit, which the browser ignored. Corrected it to 80px, then used clamp(32px, 6vw, 80px) for flexible spacing.
.episode { padding: clamp(20px, 3vw, 40px); gap: clamp(24px, 4vw, 53px); }
.content { min-width: 0; }
.image { flex: 0 1 389px; min-width: 0; }
.image img { width: 100%; height: auto; }
@media (max-width: 900px) {
.episode { flex-direction: column; }
.image { flex-basis: auto; width: 100%; }
}6. Kept three desktop columns, added two and one
The old grid always required three tracks at least 250px wide. Replaced that minimum with minmax(0, 1fr), added two columns up to 1100px and one up to 650px. Three desktop columns preserve the design’s composition. Smaller card padding and type sizes make the narrower layouts usable.
.reviews { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 1100px) {
.reviews { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 650px) {
.reviews { grid-template-columns: minmax(0, 1fr); }
}7. Preserved photo proportions
In hero-image.module.css, made the wrapper flexible and gave the main photo its own photo class with width: 100% and height: auto. These rules do not scale the decorative SVG. The host photo is flexible too, and the about section stacks on small screens. Kept next/image dimensions, improved photo alt text and used empty alt text for decoration.
.heroImageContainer { width: min(100%, 650px); flex: 0 1 50%; }
.photo { width: 100%; height: auto; border-radius: 12px; }
@media (max-width: 900px) { .heroImageContainer { flex: initial; } .cornerImage { top: 0; left: 0; } }8. Fixed the subscription panel and footer
The contact panel stayed in a row, fields lacked a width constraint and a non-breaking space in Subscribe for updates prevented wrapping. Removed that space, constrained inputs, allowed flex items to shrink and stacked the panel up to 900px. The footer now uses two columns up to 900px and one up to 500px. Demo subscription controls remain disabled.
.title, .form { min-width: 0; flex: 1; }
.input { width: 100%; min-width: 0; }
@media (max-width: 900px) { .panel { flex-direction: column; } }10. Compared against the baseline
After fixing the layout, checked 320px, 375px, 768px, 900px, 1024px and 1440px. At each width, page scrollWidth matched clientWidth: horizontal overflow was removed without hiding it. Verified native menu opening and Escape closing with focus returning to the button. The table records measurements in the same browser; usable width is 15px less than window width because of its scrollbar. These checks cover the listed sizes, not every device.
| Window | Available | Before | After |
|---|---|---|---|
| 375 | 360 | 935 | 360 |
| 768 | 753 | 935 | 753 |
| 1024 | 1009 | 1009 | 1009 |
| 1440 | 1425 | 1425 | 1425 |