DEV Community

Cover image for I audited every post on my 200-post blog. Here's what was quietly broken.
Javapark
Javapark

Posted on

I audited every post on my 200-post blog. Here's what was quietly broken.

I've been running a technical blog for years. Posts accumulate — but so does everything around them: theme edits, editor migrations, hand-written HTML from 2018, mobile layouts nobody re-checked after the last redesign.

Everything looked fine. So last week I stopped adding posts and audited all ~200 of them instead, read-only first, then fixed only what the audit actually justified.

Three things were broken. None of them were visible on my own screen.

The rule I set before touching anything

I did not go in looking for "SEO wins." I went in with five questions:

  • Is the most important heading on a post page consistent across posts?
  • Do headings generated by the theme collide with headings typed into post bodies?
  • Are the accessibility strings I marked as hidden actually hidden?
  • Does anything break on a narrow mobile viewport?
  • If a fix goes wrong, can I roll back?

That framing matters. Google is explicit that there's no magic number of heading elements that ranks better — semantic heading structure is useful primarily because it describes the document, and screen reader users depend on it (SEO Starter Guide). So the goal was a more predictable document, not a ranking claim I can't back up.

1. H1s were split between the theme and the post body

On a themed blog, the platform renders the post title and the editor renders the body — separately. Manage those independently long enough and you end up with the site name, the post title, and a body heading all rendered as <h1>.

I fixed the shared theme template first, then swept every post for body-level <h1>. Five posts had them. Eight headings total.

The rules I applied:

  • The post's primary heading belongs to the platform's title field. Nothing else competes for it.
  • Body sections start at <h2>.
  • Keep <h3> and below only where the nesting is real.
  • Never fake a heading by bumping font size.

Then — and this is the part that actually caught mistakes — I re-checked on the public URL, not in the editor preview.

2. A visually-hidden class with no CSS behind it

My post list has a search box. The markup had this:

<span class="screen-out">Search within this list</span>
Enter fullscreen mode Exit fullscreen mode

Classic screen-reader-only label. Except there was no .screen-out rule in the stylesheet. The class name was doing nothing. On desktop it was easy to miss; on a phone it wrapped to two lines and squashed the search box next to it.

The tempting fix is to delete the <span>. That's the wrong fix — it removes the only thing telling a screen reader what the input is for. The right fix is to hide it visually only:

.screen-out {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
Enter fullscreen mode Exit fullscreen mode

Note what this deliberately avoids: display: none and visibility: hidden both remove the element from the accessibility tree. And pushing it off-screen with left: -9999px can cause the viewport to scroll sideways when the element receives focus. The clip-based pattern keeps the text available to assistive tech while occupying no visual space.

After the fix, at a 390px viewport the search region measured 343px wide with a 275px input, and no horizontal overflow.

Hiding something and deleting its accessibility information are not the same operation. Before you fix a layout bug, find out why the markup exists.

3. I shipped this as two versions, not one

I could have bundled both fixes into a single theme update. I didn't:

  • v1.6.4 — heading structure across the site
  • v1.6.5 — the visually-hidden style for the list search label

Each got its own archive, its own version entry in the platform's theme library, and a recorded SHA-256 of the deployed bundle.

Version numbers on a personal blog theme aren't vanity. They're the rollback mechanism. If something surfaces in a week, I need to know which change to revert — and "the update I did on Tuesday" is not an answer.

Minimum viable discipline for any hosted-theme edit:

  1. Back up the currently live theme before applying anything.
  2. Use a version number that maps to one coherent change.
  3. Keep a record of what you verified on the public site after applying.

4. Verifying in the admin panel is not verifying

Editor previews and theme-editor previews both lied to me at least once during this. Caching, template placeholders, and editor-generated HTML all mean the code you saved is not necessarily the HTML that ships.

So "fixed it" and "confirmed it on the live URL" stayed separate steps:

Check Result
Primary h1 per post page Exactly 1
Body-level h1 Removed from all 5 posts
Mobile search label Visually hidden, still exposed to AT
Search input hint Existing placeholder preserved
Horizontal overflow at 390px None
Rollback available v1.6.4 and v1.6.5 archived separately

The checklist

Steal this for your next theme update or content cleanup:

  • [ ] Backed up the live theme first?
  • [ ] Checked post, list, category, and search views separately?
  • [ ] Do body headings start at h2 and nest honestly?
  • [ ] Are hidden strings clipped rather than pushed off-screen or display: none?
  • [ ] Can you reach search and navigation with a keyboard alone?
  • [ ] No horizontal scroll around a 390px viewport?
  • [ ] Are the before/after versions archived distinctly?
  • [ ] Verified on the public URL, not just the admin preview?

Measurement starts now, not before

I'm not going to tell you traffic went up. It's been days, and I'd be making it up.

What I did do is timestamp the change so the next 30 and 90 days are comparable — impressions, clicks, and query mix against a known baseline. If you make five changes at once and never mark the date, you've traded the ability to learn anything for the feeling of productivity.

What I can claim immediately: the heading structure is consistent enough to maintain, the mobile search row is no longer cramped, and there's a version to roll back to.

These changes feel too small to write up. They're not. Finding a small problem, bounding its blast radius, fixing it, and verifying it on the surface a real user touches — that loop is the most transferable thing in this entire post.


This is an English adaptation of a post I originally wrote in Korean on my blog, where I write about AI dev tooling and DevOps.

Top comments (0)