The blog wall that hummed at 50 Hz

2026-11-06来源 dev.to UXEnglish

Much like my past life as a sound engineer, my current work is a delicate mix of UX, design, and code. And just like accidentally creating a 50Hz ground loop hum with 10kW of bass behind it, mixing these three up usually results in a very loud, very public, less enjoyable UX.

The blog on idunworks.com used to be a tidy grid of cards. Same size, same corners, same polite little "Read more". It looked like every other blog. So I wrote the brief for its replacement in one line:

"There should be NO sweet cards, only splashy brutalist, uneven ones, served at a random pace."

This is the story of that sentence, two follow-ups, and the night the wall started to vibrate. It's about what happens when design tasks pile up on top of code that has to measure things, and the one rule that would have saved us an evening.

Task one: no sweet cards

The first version came out nicely rude. Cards in different sizes, tilted a few degrees this way and that, loud colours, heavy type. Even the link got bored of saying the same thing: "Read more" became ten different labels, from "Dive in" to "Feed your brain" to "Click for mo'" to "Down the rabbit hole". It is not for every corporate eye with a stick up their ass. It is me. Oh is your ass "profanity"? I must have misunderstood something.

"Random" needed a small cheat. If the page picks a card's look by rolling dice, the server rolls one number and the browser rolls another. The page then redraws itself the moment it loads. So every card's look is worked out from the post's own address. It looks random to you and stays identical for the server and the browser. Random enough, and repeatable.

Task two: break the grid

Uneven cards in a grid leave holes. A short card next to a tall one leaves a gap under the short one, and the wall looks like a mouth missing teeth. So a small script started packing the cards: measure each one, give it exactly the height it needs, and let later cards slide up into the gaps.

Then I looked at it again. It still wasn't what I wanted.

"I need to have a negative margin left/right for some cards, so they stick out of their parent sideways."

So cards in the outer columns got permission to hang over the edge of the wall. To do that, the script has to know which cards ended up on an edge, and it can only know that after it has packed them.

And then, of course, even more offset where there is room, in big screens. So a design is not just a design but needs to be checked, rechecked, recoded, repeated for all screens. 20 years ago, we had problems with different browsers interpreting CSS differently. We still have the same problem but from screens having different sizes and resolutions.

It is like the famous 3 times winner of Tour de France, Greg LeMond said: "It never gets easier, you just go faster".

More overhang on wide screens. Kept clear of the window edge, so nothing leaks off the page. Fine. Shipped. It looked great.

The night it vibrated

A couple of weeks later, after an unrelated deploy, the blog cards started flickering. "Probably 50hz", by my estimate. We opened the page and saw nothing. A tidy, uneven, perfectly still wall.

The catch, which took longer to find than it should have: "now scroll, I got it after scrolling."

The wall loads lazily. You get one screenful, and more cards arrive as you scroll. The first screen was fine. It was the cards that came later that started fighting.

Here's the fight in one card's view of it:

  1. I'm in the last column, so I'm an edge card. I get to stick out. I get wider.
  2. Wider means my text wraps differently. I get shorter.
  3. Shorter means the packing changes. Now I fit somewhere else, one column in.
  4. I'm not on the edge any more, so I don't get to stick out. I get narrower.
  5. Narrower means taller. Taller means I'm back in the last column. Go to 1.

Every step was correct. Every rule did exactly what it was told. Together they made a loop, and the browser ran it every frame. When we counted, a card on the live site changed its mind about 700 times a second. That's not a flicker, that's a hum. And you can hear the hiss of your computer's fans revving up like they're partying. Ouch.

Quick checks never caught it, because quick checks look at the first screen. Nobody scrolls in a quick check. That is what testers are for: they do the stuff a dev would never do because for a dev, when the logic is sound, leave it. Testers' job is to try to break that logic. Kudos to you!

The fix: you get two changes of heart

The fix is almost embarrassingly small. Each card may change its "I'm on the edge" status twice. After that it keeps whatever it has. The count only starts over when something real happens from outside: the window changes width, or new cards load.

We tested it the honest way. With the limit, the count dropped to zero. Then we took the limit out again just to be sure, and the hum came straight back. Put it back. Zero. It has been still ever since, on the live site too.

What happened, and how else it could be done

The problem: a layout rule (stick out if you're on the edge) changed the very thing it depended on (where you are), so the script and the cards argued forever. The fix: a limit on how often a card may change sides, reset only by outside events.

There are other ways out, and they trade differently:

  • Ours, the limit: a few lines, no design change. The cost is that once in a while a card may keep an overhang it no longer strictly deserves. Nobody will ever notice.
  • Shift the card instead of widening it. If the overhang only moves the card sideways, without making it wider, the text never rewraps and the loop can't start. The cost: the card pulls away from its neighbour on the inner side, so the wall gets gaps where it should touch.
  • Measure once, then stop measuring. Pack the wall, decide the edges, apply the overhang and don't look again until the window changes. No loop by design. The cost: a card that grows from its overhang can now bump into the card below, so you need extra spacing to be safe.
  • Let the browser do it. Native masonry layouts in CSS are on their way, and then there's no script at all to argue with. The cost: not every browser has them yet, so for now you still need the script as a backup.

The rule of thumb I'm keeping: any code that measures something and then changes what it measured is a loop, whether you meant it or not. Give it a way to stop. And when you test a page that loads more as you scroll, scroll.

Each design task was small. "Uneven." "Stick out." "A bit more where there's room." The code said yes to every one. That's the risk: it never tells you which yes was one too many.

The wall is on idunworks.com/blog. Scroll all the way down. It holds still now. Promise!

Originally published at idunworks.com.

原文:https://www.a8q9.cn/en/article/the-blog-wall-that-hummed-at-50-hz-ff6a21.html

相关文章