Reputation: 1871
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!
Upvotes: 187
Views: 263172
Reputation: 101
I tried all the css suggestions without any luck. After some experimentation I found that if you replace the html element directly under the element being scaled with itself everything is crisp. Here is a react hook example:
const useChromeScaleHack = (ref: MutableRefObject<HTMLElement>, scale: number) => {
if (!window.chrome) return
useEffect(() => {
if (scale > 1.09 && ref.current) {
const el = ref.current
el.replaceWith(el)
}
}, [scale])
}
const Comp = ({ scale, children }) => {
const ref = useRef(null)
useChromeScaleHack(ref, scale)
return (
<div
style={{
willChange: "transform",
transform: `scale(${scale})`,
}}
>
<div ref={ref}>{children}</div>
</div>
)
}
Upvotes: 2
Reputation: 55
In many cases trouble blurry text caused videocard painting (in reason of opacity+animation). And even when animation is ended, videocard still painting block and text is blurry. To avoid it you need:
Upvotes: 0
Reputation: 1
2024 answer here !
I tried all the options posted here, but I didn't succeed.
Here's my solution with javascript:
const myDiv = document.querySelector('.my-div');
const divHeight = myDiv.offsetHeight - 1;
myDiv.style.height = modalHeight + 'px';
I found that setting a height in CSS worked just fine but my case is to height always be set as "auto", so I use js to get the current height from my div and subtract by 1.
Worked like a charm!
Upvotes: 0
Reputation: 259
For anyone experiencing this issue still in 2024, none of the forementioned issues will probably work across all devices etc. It happens because it rasterizes the element and scales it from the height it rasterized at.
To fix this the solution I created was creating a wrapper with transform: scale(2, 2)
& pointer-events: none
then on the inner element set the transform: scale(0.5, 0.5)
and pointer-events: all
, then you can adjust your hover scaling respective of the inner element scale. This will rasterize your element 2x the natural scale, making it a higher quality. If your element needs to scale above 2
adjust your wrapper scale accordingly.
.wrapper {
transform: scale(2, 2);
pointer-events: none;
}
.element {
transform: scale(0.5, 0.5);
pointer-events: all;
}
.element:hover {
transform: scale(1, 1);
}
<div className="wrapper">
<div className="element" />
</div>
Upvotes: 0
Reputation: 256
highest rated solution works but not for <h1...6> tags, had to specify font-size for them to work.
Upvotes: 0
Reputation: 1
For me, my solution had a bit of luck involved. My solution only works in certain scenarios. My browser is chrome 120.0.6099.110. I solved this problem by adding
content-visable:auto
to the text wrapping layer. I have tried all the above-mentioned upvoted answers, but to no avail. My interface is a table. For product comparison, the transform:scaleY(-1) element needs to be flipped and reduced in the vertical direction, that is, upside down. When there are more than 8 products compared, the DOM content of the page will be very large, with many columns and rows of data, then there will be problems with Chrome rendering, and the problem of blurred fonts will occur. By adding content-visable:auto, the browser will reduce some rendering content, this is my understanding. I have a horizontal scroll bar to drag and display all the content, because one screen cannot display everything. No problem dragging, great content-viable
Upvotes: -1
Reputation: 613
Try adding this rule seperately to transformed element. both are working:
border:0 !important;
or
border-radius:0 !important;
Upvotes: 0
Reputation: 1144
To improve the blurriness, esp. on Chrome, try doing this:
transform: perspective(1px) translateZ(0);
backface-visibility: hidden;
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;
Upvotes: 34
Reputation: 5996
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.
Upvotes: 123
Reputation: 101
I was using box-shadow on my card and that is why it was causing me trouble after removing that box-shadow i was able to see crisp text after scaling.
Upvotes: 0
Reputation: 1
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();
.
Upvotes: 0
Reputation: 11
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.
Upvotes: 0
Reputation: 750
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;
}
Upvotes: 1
Reputation: 31
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:
I hope it can be helpful for some of you folks :)
Upvotes: 2
Reputation: 37
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.
Upvotes: 0
Reputation: 5132
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).
Upvotes: 0
Reputation: 33
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.
Upvotes: 0
Reputation: 1830
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
Upvotes: 2
Reputation: 1
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);
}
})}
Upvotes: 0
Reputation: 41
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!
Upvotes: 2
Reputation: 51
I have this same problem. I fixed this using:
.element {
display: table
}
Upvotes: 5
Reputation: 438
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/
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.
Upvotes: 5
Reputation: 109
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;
}
Upvotes: 2
Reputation: 117
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.
Upvotes: 1
Reputation: 149
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.
Upvotes: 4
Reputation: 413
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);
}
Upvotes: 1
Reputation: 41
I removed this from my code - transform-style: preserve-3d;
and added this- transform: perspective(1px) translateZ(0);
the blur went away!
Upvotes: 1
Reputation: 751
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.
Upvotes: 64