Have you ever tried stopping a transform: translateY()
animation and noticed that your text or images become blurry? It happens because CSS transforms often leave elements at sub-pixel positions (e.g., translateY(-385.562px)
), which causes anti-aliasing issues.
This is especially annoying when you’re working with WAAPI (Web Animations API) or CSS animations that loop infinitely, and you want to pause or stop the animation smoothly.
Well, here’s a simple hack that forces your element to “snap” to integer pixel values when you stop the animation, restoring that perfect crispness.
The Problem
-
CSS transform animations can leave elements at fractional pixel positions.
-
When you stop the animation, elements may be positioned at translateY(-385.562px).
-
This results in blurry text, distorted borders, and a generally messy look.
-
Simply setting .style.transform doesn’t help because the running animation overrides it.
The Solution — Snap to Integer with data-attribute
1. Snap Current Transform to Integer (JS Function)
const snapTransformToInteger = (el) => {
const computedStyle = getComputedStyle(el);
const match = computedStyle.transform.match(/matrix.*((.+))/);
if (match) {
const values = match[1].split(', ');
const translateY = parseFloat(values[5]); // matrix(a, b, c, d, tx, ty)
const roundedY = Math.round(translateY);
el.style.setProperty('--stopTranslateY', `${roundedY}px`);
el.dataset.stopAnimation = 'true';
}
};
2. Force CSS Transform with Data Attribute
.element[data-stop-animation='true'] {
transform: translateY(var(--stopTranslateY, 0px)) !important;
}
3. When You Want to Stop Animation
// Stop the animation smoothly and fix blurry pixels
snapTransformToInteger(el);
4. When You Want to Resume
-
Remove
data-stop-animation
attribute. -
Resume your WAAPI animation.
el.dataset.stopAnimation = 'false';
// Resume the animation here.
Why This Works
-
WAAPI animations or CSS animations will always win over direct .style edits.
-
But CSS selectors like [data-stop-animation=’true‘] with !important can override inline transforms.
-
By forcing a CSS variable-based transform, you “lock” the element in place.
-
Once you’re ready to resume, remove the attribute and resume the animation.
Conclusion
This trick is perfect for cases when you:
-
Need to pause infinite transform animations.
-
Want your UI to stop without blurry elements.
-
Hate sub-pixel rendering glitches after animations.
It’s a small hack, but it saves hours of frustration. And the best part? No need to rewrite your animations with absolute positioning hacks or crazy workarounds.