Blurry text after using CSS transform: scale(); in Chrome

Google ChromeCssWebkitTransformCss Animations

Google Chrome Problem Overview


Seems like there has been a recent update to Google Chrome that causes blurry text after doing a transform: scale(). Specifically I'm doing this:

@-webkit-keyframes bounceIn {
  0% {
    opacity: 0;
    -webkit-transform: scale(.3);
  }

  50% {
    opacity: 1;
    -webkit-transform: scale(1.05);
  }

  70% {
    -webkit-transform: scale(.9);
  }

  100% {
    -webkit-transform: scale(1);
  }
}

If you visit http://rourkery.com in Chrome, you should see the problem on the main text area. It didn't used to do this and it doesn't seem to effect other webkit browsers (like Safari). There were some other posts about people experiencing a similar issue with 3d transforms, but can't find anything about 2d transforms like this.

Any ideas would be appreciated, thanks!

Google Chrome Solutions


Solution 1 - Google Chrome

I have had this problem a number of times and there seems to be 2 ways of fixing it (shown below). You can use either of these properties to fix the rendering, or both at the same time.

Backface visibility hidden fixes the problem as it simplifies the animation to just the front of the object, whereas the default state is the front and the back.

backface-visibility: hidden;

TranslateZ also works as it is a hack to add hardware acceleration to the animation.

transform: translateZ(0);

Both of these properties fix the problem that you are having but some people also like to add

-webkit-font-smoothing: subpixel-antialiased;

to their animated object. I find that it can change the rendering of a web font but feel free to experiment with that method too.

Solution 2 - Google Chrome

After trying everything else here with no luck, what finally fixed this issue for me was removing the will-change: transform; property. For some reason it caused horribly blurry looking scaling in Chrome, but not Firefox.

Solution 3 - Google Chrome

To improve the blurriness, esp. on Chrome, try doing this:

transform: perspective(1px) translateZ(0);
backface-visibility: hidden;

UPDATE: Perspective adds distance between the user and the z-plane, which technically scales the object, making the blurriness seem 'permanent'. The perspective(1px) above is like duck-tape because we're matching the blurriness we're trying to solve. You might have better luck with the css below:

transform: translateZ(0);
backface-visibility: hidden;

Solution 4 - Google Chrome

I found that adjusting the scale ratio helped slightly.

Using scale(1.048) over (1.05) seemed to generate a better approximation to a whole-pixel font size, reducing the sub-pixel blurring.

I also used translateZ(0) which seems to adjust Chrome's final rounding step in the transform animation. This is a plus for my onhover usage because it increases speed and reduces visual noise. For an onclick function however, I wouldn't use it because, the transformed font doesn't appear to be as crispy.

Solution 5 - Google Chrome

Instead of

transform: scale(1.5);

using

zoom : 150%;

fixes the text blurring problem in Chrome.

Solution 6 - Google Chrome

This must be a bug with Chrome (Version 56.0.2924.87), but the below fixes the bluriness for me when changing css properties in the console('.0'). I'll report it.

filter: blur(.0px)

Solution 7 - Google Chrome

Sunderls lead me to the answer. Except filter: scale does not exist, but filter: blur does.

Apply the next declarations to the elements that appear blurred (in my case they were inside a transformed element):

backface-visibility: hidden;    
-webkit-filter: blur(0);

It almost worked perfectly. "Almost" because i'm using a transition and while in transition, elements don't look perfect, but once the transition is done, they do.

Solution 8 - Google Chrome

I found out, that the problem occures on relative transforms in any way. translateX(50%), scale(1.1) or what ever. providing absolute values always works (does not produce blurry text(ures)).

None of the solutions mentions here worked, and I think there is not solution, yet (using Chrome 62.0.3202.94 while I am writing this).

In my case transform: translateY(-50%) translateX(-50%) causes the blur (I want to center a dialog).

To reach a bit more "absolute" values, I had to set decimal values to transform: translateY(-50.09%) translateX(-50.09%).

NOTE

I am quite sure, that this values vary on different screen sizes. I just wanted to share my experiences, in case it helps someone.

Solution 9 - Google Chrome

I have this same problem. I fixed this using:

.element {
  display: table
}

Solution 10 - Google Chrome

In my case following code caused blurry font:

-webkit-transform: translate(-50%,-50%);
transform: translate(-50%,-50%);

and just adding zoom property fixed it for me. Play around with zoom, following worked for me:

zoom: 97%;   

Solution 11 - Google Chrome

I have found a much better and clean solution:

.element{
 transform:scale(0.5) 
 transform-origin: 100% 0;
}

or

.element{
 transform:scale(0.5) 
 transform-origin: 0% 0;
}

Thanks to this post: https://stackoverflow.com/questions/29037176/preventing-blurry-rendering-with-transform-scale/29037803

Solution 12 - Google Chrome

Try using zoom: 101%; for complex designs when you can't use a combination of zoom + scale.

Solution 13 - Google Chrome

Another fix to try i just found for blurry transforms (translate3d, scaleX) on Chrome is to set the element as "display: inline-table;". It seems to force pixel rounding in some case (on the X axis).

I read subpixel positioning under Chrome was intended and devs won't fix it.

Solution 14 - Google Chrome

2019 Update
The Chrome display bug is still unfixed and though no fault of the patrons, none of the suggestions offered in the entirety of this website help to resolve the issue. I can concur that I have tried every single one of them in vain: only 1 comes close and that's the css rule: filter:blur(0); which eliminates the shifting of a container by 1px but does not resolve the blurred display bug of the container itself and any content it may have.

Here's the reality: there literally is no fix to this problem so here is a work around for fluid websites

CASE
I'm currently developing a fluid website and have 3 divs, all centered with hover effects and sharing percentage values in both the width and position. The Chrome bug occurs on the center container which is set to left:50%; and transform:translateX(-50%); a common setting.

EXAMPLE: First the HTML...

<div id="box1" class="box">
    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry"s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.
</div>

<div id="box2" class="box">
    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry"s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.
</div>

<div id="box3" class="box">
    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry"s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.
</div>

Here's the CSS where the Chrome bug occurs...

*{margin:0; padding:0; border:0; outline:0; box-sizing:border-box;  background:#505050;}
.box {position:absolute; border:1px solid #fff; border-radius:10px; width:26%; background:#8e1515; padding:25px; top:20px; font-size:12pt; color:#fff; overflow:hidden; text-align:center; transition:0.5s ease-in-out;}
.box:hover {background:#191616;}
.box:active {background:#191616;}
.box:focus {background:#191616;}
#box1 {left:5%;}
#box2 {left:50%; transform:translateX(-50%);} /* Bugged */
#box3 {right:5%;}

Here's the fixed css...

*{margin:0; padding:0; border:0; outline:0; box-sizing:border-box;  background:#505050;}
.box {position:absolute; border:1px solid #fff; border-radius:10px; width:26%; background:#8e1515; padding:25px; top:20px; font-size:12pt; color:#fff; overflow:hidden; text-align:center; transition:0.5s ease-in-out;}
.box:hover {background:#191616;}
.box:active {background:#191616;}
.box:focus {background:#191616;}
#box1 {left:5%;}
#box2 {left:37%;} /* Fixed */
#box3 {right:5%;}

Bugged fiddle: https://jsfiddle.net/m9bgrunx/2/<br/> Fixed fiddle: https://jsfiddle.net/uoc6e2dm/2/

As you can see a small amount of tweaking to the CSS should reduce or eliminate the requirement to use transform for positioning. This could also apply to fixed width websites as well as fluid.

Solution 15 - Google Chrome

It's important to add that this issue arises if the element which is being translated has a height with an odd number of pixels. So, if you have control over the height of the element, setting it to an even number will make the content appear crisp

Solution 16 - Google Chrome

None of above worked for me. I had this animation for popups:

@keyframes pulse {
  from {
    transform: scale3d(1, 1, 1);
  }
  50% {
    transform: scale3d(1.05, 1.05, 1.05);
  }
  to {
    transform: scale3d(1, 1, 1);
  }
}

In my case blurry effect was gone after applying this rule: -webkit-perspective: 1000; even though it is marked as unused in Chrome inspector.

Solution 17 - Google Chrome

None of the above worked for me.

It worked when I added perspective

ie from

transform : translate3d(-10px,-20px,0) scale3d(0.7,0.7, 1)

i changed to

transform : perspective(1px) translate3d(-10px,-20px,0) scale3d(0.7,0.7, 1)

Solution 18 - Google Chrome

I used a combination of all answers and this is what worked for me in the end:

.modal .modal--transition {
  display: inline-table;
  transform: perspective(1px) scale(1) translateZ(0);
  backface-visibility: hidden;
  -webkit-font-smoothing: subpixel-antialiased;
}

Solution 19 - Google Chrome

My solution was:

display: initial;

Then it was crispy sharp

Solution 20 - Google Chrome

I was facing the blurry text issue on Chrome but not on Firefox when I used transform: translate(-50%,-50%).

Well, I really tried a lot of workarounds like:

transform: perspective(1px);
filter: blur(0);
transform: translateZ(0);
backface-visibility: hidden;

None of these worked to me.

Finally, I made the height and width of the element even. It resolved the issue for me!!!

Note: It might depend from use case to use case. But surely worth a try!

Solution 21 - Google Chrome

I have tried a lot of examples from these answers unfortunately nothing help for Chrome Version 81.0.4044.138 I have added to transforming element instead

 transform-origin: 50% 50%;

this one

 transform-origin: 51% 51%;

it helps for me

Solution 22 - Google Chrome

This is what worked for me:

body { perspective: 1px; }

Solution 23 - Google Chrome

I fixed my case by adding:

transform: perspective(-1px)

Solution 24 - Google Chrome

I removed this from my code - transform-style: preserve-3d; and added this- transform: perspective(1px) translateZ(0);

the blur went away!

Solution 25 - Google Chrome

FOR CHORME:

I´ve tried all suggestions here. But diden't work. My college found a great solution, that works better:

You should NOT scale past 1.0

And include translateZ(0) in the hover but NOT in the none-hover/initial position.

Example:

a {
    transition: all 500ms cubic-bezier(0.165, 0.840, 0.440, 1.000);
    transform: scale(0.8, 0.8);
}

a:hover {
    transform: translateZ(0)scale(1.0, 1.0);
}

Solution 26 - Google Chrome

I have a div that has a small perspective shift on it to give a subtle 3D effect. The text in the div was blurring and I tried all the suggestions here to no avail.

Oddly, I found that setting 'filter: inherit;' on the text elements vastly improved the clarity. Though I can't understand why.

Here's my code in case it helps:

Html:

<div id="NavContainer">
    <div id="Nav">
        <label>Title</label>
        <nav>
            <a href="/">home</a>
            <a href="/link1">link1</a>
            <a href="/link2">link2</a>
        </nav>
    </div>
</div>

Css:

    #NavContainer {
        position: absolute;
        z-index: 1;
        top: 0;
        left: 20px;
        right: 20px;
        perspective: 80vw;
        perspective-origin: top center;
    }

    #Nav {
        text-align: right;
        transform: rotateX(-5deg);
    }

        #Nav > nav > a,
        #Nav > label {
            display: inline-block;
            filter: inherit;
        }

        #Nav > label {
            float: left;
            font-weight: bold;
        }

Solution 27 - Google Chrome

For me the problem was that my elements were using transformStyle: preserve-3d. I realized that this wasn't actually needed for the app and removing it fixed the blurriness.

Solution 28 - Google Chrome

In Chrome 74.0.3729.169, current as of 5-25-19, there doesn't seem to be any fix for blurring occurring at certain browser zoom levels caused by the transform. Even a simple TransformY(50px) will blur the element. This doesn't occur in current versions of Firefox, Edge or Safari, and it doesn't seem to occur at all zoom levels.

Solution 29 - Google Chrome

It will be difficult to solve with only css.

So I solved it with jquery.

This is my CSS.

.trY {
   top: 50%;
   transform: translateY(-50%);
}

.trX {
   left: 50%;
   transform: translateX(-50%);
}

.trXY {
   top: 50%;
   left: 50%;
   transform: translate(-50%, -50%);
}

and this is my jquery.

function tr_init() {
$(".trY, .trX, .trXY").each(function () {
    if ($(this).outerWidth() % 2 != 0) {
        var fixed_width = Math.ceil($(this).outerWidth() / 2) * 2;
        $(this).css("width", fixed_width);
    }
    if ($(this).outerHeight() % 2 != 0) {
        var fixed_height = Math.ceil($(this).outerHeight() / 2) * 2;
        $(this).css("height", fixed_height);
    }
})}

Solution 30 - Google Chrome

Just to add to the fix craze, putting {border:1px solid #???} around the badly looking object fixes the issue for me. In case you have a stable background colour, consider this too. This is so dumb noone thought about mentioning I guess, eh eh.

Solution 31 - Google Chrome

In my case, the mistake was that the animation was set to a parent div of the animated element (an SVG). The parent div had some crazy width, like 466.667px. Setting that to an odd number wouldn't help. But: targetting the SVG itself with the animation (instead of the parent container did).

Solution 32 - Google Chrome

For anyone reading in the future: In my case the issue was that I added:

perspective: 2500px;

To a parent element. Removing this property resolved the issue.

Solution 33 - Google Chrome

So. I tried all the solutions above and nothing really worked. But!

I have a modal-root div in my index.html of my React App. I am rendering a Modal component (.modal) in it if it is necessary. First I positioned the modal itself fixed, making it top-left 50% and applied a transition(-50%, -50%) to get it centered.

I zoomed in-and-out and noticed the blurriness of the modal content if the zoom ratio of the Chrome browser was not 100%. It could be 110% or 90-80-75 etc. percent, doesn't matter. Apart from 100% zoom it was really blurry and ugly.

So I decided to get rid of the entire transition-based solution that I had before to center the child of the .modal element.

I am positioning my modal-root fixed, making it top-left-right-bottom 0, so it is always 100vh and wv. Then I made it a flex-container and positioned its child via align-items and justify-content centered.

But! There is always a but. The modal-root has a z-index: -1 on default. I decided to change it programmatically to 59 if the modal is opened. I also apply an overlay that makes the rest of the page darker, that is the .overlay which has a z-index of 60. The actual modal content (.modal) has a z-index of 61.

I also wanted to animate the entrance of that element when it appears so I am playing around with the margins, instead of applying any kind of transition to it. It's a cubic-bazier animation that handles that margin-top at the fitting percent within the animation but at the end it is margin-top 0 with no transition property.

It was a bit pity to have to rework the component but after testing it it works pretty fine.

Summary:

  • Highest parent container fixed, covering the entire page
  • Setting the highest parentcontainer's z-index -1 or [custom-value] depending on wanting to interacting with the modal (modal is open)
  • Setting the container's z-index to -1 if the modal is closed
  • Making the container a flex-container and position its child to the center
  • Animating the child via margin values instead of transition

I hope it can be helpful for some of you folks :)

Solution 34 - Google Chrome

Try to play with zoom value on the animated block. In my case, zoom: 99.6%; totally fixes the blurry text. But for example, with 99.7% value text is still blurry, so in each case this value can vary.

Solution 35 - Google Chrome

What worked for me was to remove backdrop-filter: blur(8px);. While this filter was only being applied to the background of a <div>, and not to its text, it seems like merely the presence of this property causes Chrome to slightly blur the text when used with transform: scale();.

Solution 36 - Google Chrome

you can use css filter to fix this.

.element {
    filter: blur(0);
}

about vendor-prefix, please do it by yourself.-webkit-filter,-ms-filter. detail is here http://browser.colla.me/show/css_transformation_scale_cause_blurring

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRyan O&#39;RourkeView Question on Stackoverflow
Solution 1 - Google Chrome2neView Answer on Stackoverflow
Solution 2 - Google ChromeDanView Answer on Stackoverflow
Solution 3 - Google ChromeykadaruView Answer on Stackoverflow
Solution 4 - Google ChromeJordan NakamotoView Answer on Stackoverflow
Solution 5 - Google ChromeNaisheel VerdhanView Answer on Stackoverflow
Solution 6 - Google ChromeandywView Answer on Stackoverflow
Solution 7 - Google ChromeruidovisualView Answer on Stackoverflow
Solution 8 - Google ChromescipperView Answer on Stackoverflow
Solution 9 - Google ChromeRaviView Answer on Stackoverflow
Solution 10 - Google ChromeRaza AhmedView Answer on Stackoverflow
Solution 11 - Google ChromeGabriel GView Answer on Stackoverflow
Solution 12 - Google ChromeTom RoggeroView Answer on Stackoverflow
Solution 13 - Google ChromeCorentinView Answer on Stackoverflow
Solution 14 - Google ChromeSJacksView Answer on Stackoverflow
Solution 15 - Google ChromeStojan MihajlovskiView Answer on Stackoverflow
Solution 16 - Google ChromeGendos-uaView Answer on Stackoverflow
Solution 17 - Google ChromeSengupta AmitView Answer on Stackoverflow
Solution 18 - Google ChromeKyle UnderhillView Answer on Stackoverflow
Solution 19 - Google Chromeuser9164129View Answer on Stackoverflow
Solution 20 - Google ChromePrajwal_ShenoyView Answer on Stackoverflow
Solution 21 - Google ChromeOleg BondarenkoView Answer on Stackoverflow
Solution 22 - Google ChromeHarsh MittalView Answer on Stackoverflow
Solution 23 - Google ChromeAnders LundView Answer on Stackoverflow
Solution 24 - Google ChromeTanha IslamView Answer on Stackoverflow
Solution 25 - Google ChromeJonas BornelandView Answer on Stackoverflow
Solution 26 - Google ChromeCraig PooleView Answer on Stackoverflow
Solution 27 - Google ChromeNormangormanView Answer on Stackoverflow
Solution 28 - Google ChromeAustinView Answer on Stackoverflow
Solution 29 - Google ChromemadstoneView Answer on Stackoverflow
Solution 30 - Google Chromeuser1769038View Answer on Stackoverflow
Solution 31 - Google ChromeUrsView Answer on Stackoverflow
Solution 32 - Google ChrometoljoasView Answer on Stackoverflow
Solution 33 - Google ChromeSzitás TamásView Answer on Stackoverflow
Solution 34 - Google ChromeRoman ReznikovView Answer on Stackoverflow
Solution 35 - Google ChromeDaniel FernandesView Answer on Stackoverflow
Solution 36 - Google ChromesunderlsView Answer on Stackoverflow