Three front-end bugs my build said were fine
I run a static browser-games site. Every page exists twice: once as prerendered HTML for search engines, and once as a React app for people clicking around. The build is a babel bundle plus a generator script. Here are t
I run a static browser-games site. Every page exists twice: once as prerendered HTML for search engines, and once as a React app for people clicking around. The build is a babel bundle plus a generator script. Here are three bugs that went through that build without a single error and broke the page people actually saw.
1. <img width="700" height="700"> means height: 700px
Every game card has an image with width and height attributes. That is the standard advice: the browser reserves the right space before the image loads, so the layout does not jump.
My CSS made the image fill its card and kept it square:
.grid img, .cards img { width: 100%; aspect-ratio: 1/1; object-fit: cover; display: block; }
The cards were about 176 px wide, so I expected 176 × 176.
The browser drew 176 × 700 on every category, tag and collection page. Everything below the first row was pushed off the screen.
The reason: the height attribute is not just a hint for the aspect ratio. It maps to a CSS height: 700px, and aspect-ratio only takes effect while height is auto. My rule set the width and said nothing about the height, so the attribute won.
The fix is two words in the same rule:
.grid img, .cards img { width: 100%; height: auto; aspect-ratio: 1/1; object-fit: cover; display: block; }
Keep the attributes, because they still prevent layout shift. Just never set a width on an image without also saying height: auto.
2. Two class names for one grid
The generator that writes the static pages had grown in pieces. Some templates wrote <ul class="grid">, others <ul class="cards">. Only .grid had styles.
Every .cards list rendered as one full-width thumbnail per row. That included the "related games" strip at the bottom of every game page, which nobody looked at closely because it was at the bottom.
Nothing failed. The HTML was valid, the CSS was valid, and the pages returned 200. The fix was to style both names together:
.grid, .cards { list-style: none; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(158px, 1fr)); gap: 16px; }
Better still is one class name everywhere, but until then, anything shaped like a grid gets both selectors.
3. Deleting a feature deleted a neighbour
I removed an ad integration from one large component file. The change was one hunk of about 240 lines. It ran a little past the end of the ad code and also deleted the Logo component that sat right below it.
The bundle compiled. Babel transforms syntax; it does not know whether a name you use is defined anywhere. The prerendered pages have no React in them, so they looked perfect.
The React app threw ReferenceError: Logo is not defined on load. For a day the homepage showed only its no-JavaScript fallback: a list of popular games with no header, no search, no navigation and no footer. From a distance it looked like a page, which is why it survived a quick look.
Two checks catch this now:
- After deleting code, compare the top-level definitions before and after:
git show HEAD~1:components.jsx | grep -oE "^(function|const|let) +\w+" > before.txt
grep -oE "^(function|const|let) +\w+" components.jsx > after.txt
diff before.txt after.txt
Anything in the diff that you did not mean to remove is the bug.
- Load the page in a real browser with a listener on
pageerror. A static check cannot tell you that a name is missing at run time; the browser can, in one line of output.
What the three have in common
Each bug produced valid output. The build, the validator and the HTTP status code all agreed things were fine. What caught them was looking at the rendered page: a screenshot at phone and desktop width, and the browser's error log.
That is now the last step before anything ships on 360 PlayZone: screenshot a few pages both ways, including the full games list, and read the console.
Written by an AI assistant from my own build notes.
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.