D
P
0

HTML & CSS

A Duplicate `style=` Attribute on One Element — The Browser Silently Keeps Only the First

June 8, 2026·4 min read
A Duplicate `style=` Attribute on One Element — The Browser Silently Keeps Only the First

This bug is interesting because the CSS was correct, the values were correct, and the element was correct — yet one of my style blocks was never applied at all. On a content site I maintain, a logo was supposed to render small and tidy (32×32, fit inside a box). But in production the logo blew up to fill the entire card at its natural PNG size — around 386×360 — as if the width, height, and object-fit I'd written had simply evaporated.

What made it more confusing: in the headless screenshots I used for QA, the logo looked correct. Only when I opened the page in a real browser did the sizing fall apart. The cause turned out to be one easy-to-miss markup mistake: two style= attributes on the same element.

The broken markup

The generated markup looked roughly like this — notice style= appearing twice on a single <img>:

<img
  style="display:block"
  src="/logo.png"
  style="width:32px;height:32px;object-fit:contain"
/>

It looks like those two style blocks would merge. They don't. The result: the logo rendered at its PNG's natural size, and every sizing rule — width, height, object-fit — vanished without a trace.

Why only the first style= wins

This is HTML-spec behavior, not a browser bug. When an element has the same attribute name more than once, the parser takes the first one and ignores the rest. No merging, no warning, no console error.

So on the <img> above, the browser reads style="display:block" and discards style="width:32px;height:32px;object-fit:contain" entirely. All that's left is display:block. With no dimension constraints, the image falls back to its intrinsic size — 386×360 — and fills the card.

This also explains why the headless screenshots hid it. The headless renderer I used normalizes / rewrites element attributes before doing layout, so the duplicate style got accidentally "deduped" and QA passed. A real browser doesn't do that — it follows the spec rule as-is: first wins, the rest are silently dropped. The hard-won lesson: verify in a real browser, not just in a headless screenshot.

The fix: never emit two style= on one element

The fix is trivial once you know the cause — merge all declarations into a single style= attribute:

<img
  src="/logo.png"
  style="display:block;width:32px;height:32px;object-fit:contain"
/>

One attribute, every rule alive. The logo goes back to 32×32.

Because this usually comes from templating — one layer adds style="display:block", another layer adds the sizing style — I audited the codebase with a simple regex to catch any element carrying two style=:

# Find tags where style= appears twice on a single element
grep -rEn 'style=[^>]*style=' .

The style=[^>]*style= pattern matches two style= within the same tag (as long as both are before the closing >). Every hit is an element whose rules are being silently thrown away.

When two styles are actually fine

An important distinction: the problem is two style= on one and the same element, not two elements that each have a style=. The wrapper pattern below is correct — two elements, one style attribute each:

<!-- Safe: two distinct elements, one style= each -->
<div style="display:block">
  <img src="/logo.png" style="width:32px;height:32px;object-fit:contain" />
</div>

Often splitting into wrapper + inner like this is the cleaner approach anyway: the container handles layout, the image handles its own sizing, and no single element ever carries a duplicate attribute.

A few extra notes

  • The "first attribute wins" rule applies to all attributes, not just style. Two class=, two id=, two href= — the second and beyond are always ignored. style bites most often because the lost sizing is immediately visible.
  • If an image suddenly renders at a "random but consistent" size, suspect the asset's intrinsic dimensions. The 386×360 in my case was exactly the PNG's natural size — a strong hint that every sizing constraint was being ignored.
  • Put the dedup at the templating/build stage, not just in review. If two different helpers can inject style onto the same element, sooner or later they'll collide again.

The takeaway: when your CSS is "correct" but has no effect, check whether the declarations are actually reaching the element. Duplicate attributes are one of the quietest ways part of your markup disappears — no error, no warning, just the first one surviving.