Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wobbly text on transform scale

Tags:

html

css

When I try to scale a div on mouse hover, the text wobbles/jitters and the animation is not smooth. This is especially apparent in FireFox, but can also be seen in Chrome.

Are there any changes I can do to make the animation smooth?

JS Fiddle: https://jsfiddle.net/jL4dbxf9/

.mtw { 
  max-width: 200px;
  margin: 0 auto; 
}
.mt .mp {
  text-align: center;
}
.mt .mp .ma {
  color: #fff;
  font: 800 40px OpenSansBold, Arial, Helvetica, sans-serif;
  min-height: 60px;
}
.mt .header-blue {
  background: blue;
}
.mt {
  transition: all 0.4s linear;
}
.mt:hover{
  z-index: 1;	
  transform: scale(1.1);
  -webkit-transform: scale(1.1);
  -moz-transform: scale(1.1);
  -o-transform: scale(1.1);
  -ms-transform: scale(1.1);	
}
<div class="mtw">
  <div class="mt">
    <div class="header-blue">
      <h2 class="mp">
        <span class="ma">49</span>
      </h2>
    </div>
  </div>
</div>
like image 444
jjdem Avatar asked Oct 08 '18 18:10

jjdem


People also ask

How do you fix a blurry picture on a transform scale?

I had this problem with SVG scaling and blurry images. I scaled up a background image to 4.5 and the image rendered very blurry while scaling up. I read that you can scale down first transform: scale(0.7) and then scale up to transform: scale(1.0) . In my case this meant a huge rebuild of my animation.

How does a transform scale work?

This scaling transformation is characterized by a two-dimensional vector. Its coordinates define how much scaling is done in each direction. If both coordinates are equal, the scaling is uniform (isotropic) and the aspect ratio of the element is preserved (this is a homothetic transformation).


Video Answer


1 Answers

So you've got multiple things going on here, and unfortunately it's going to require various things between browsers as you tackle some of the nuances of the measure / arrange passes, anti-aliasing, hardware acceleration, perspective, etc...

.mtw {
  max-width: 200px;
  margin:0 auto; 
}
.mt .mp { text-align: center }
.mt .mp .ma {
  color: #fff;
  font: 800 40px OpenSansBold, Arial, Helvetica, sans-serif;
  min-height: 60px;
}
.mp { margin: 0 }
.mt .header-blue {
  background: blue;
}
.mt {
  transition: all 0.4s linear;
  backface-visibility: hidden;
  -webkit-font-smoothing: subpixel-antialiased;
}
.mt:hover {
  z-index: 1;
  -webkit-transform: scale(1.1) translate3d( 0, 0, 0) perspective(1px);
     -moz-transform: scale(1.1) translate3d( 0, 0, 0) perspective(1px);
       -o-transform: scale(1.1) translate3d( 0, 0, 0) perspective(1px);
      -ms-transform: scale(1.1) translate3d( 0, 0, 0) perspective(1px);
          transform: scale(1.1) translate3d( 0, 0, 0) perspective(1px);
}

/* --- cleaner way --- */
#boom {
  color: #fff;
  background-color: blue;
  font: 800 40px OpenSansBold, Arial, Helvetica, sans-serif;
  min-height: 60px;
  max-width:200px;
  margin:0 auto;
  text-align: center;
  transition: transform 0.4s linear;
  backface-visibility: hidden;
  -webkit-font-smoothing: subpixel-antialiased;
  will-change: transform;  
}
#boom:hover {	
  -webkit-transform: scale(1.1) translate3d( 0, 0, 0) perspective(1px);
     -moz-transform: scale(1.1) translate3d( 0, 0, 0) perspective(1px);
       -o-transform: scale(1.1) translate3d( 0, 0, 0) perspective(1px);
      -ms-transform: scale(1.1) translate3d( 0, 0, 0) perspective(1px);
          transform: scale(1.1) translate3d( 0, 0, 0) perspective(1px);
}

/* --- Another way --- */
#weee {
  color: #fff;
  background-color: blue;
  font: 800 40px OpenSansBold, Arial, Helvetica, sans-serif;
  min-height: 60px;
  max-width:200px;
  margin:0 auto;
  text-align: center;
  transition: font-size 0.4s linear;
  backface-visibility: hidden;
  -webkit-font-smoothing: subpixel-antialiased;
  will-change: font-size;
}
#weee:hover {
  font-size: 120px;
}
<div class="mtw">
  <div class="mt">
    <div class="header-blue">
      <h2 class="mp">
        <span class="ma">49</span>
      </h2>
    </div>
  </div>
</div>

<br/><br/>

Or, cleaner way....
<div id="boom">50</div>

<br/><br/>

Or, an entirely different way...
<div id="weee">51</div>

So if we look through the changes, we see some things added...

backface-visibility: hidden; = The user doesn't care about the back, remove it from the compositor consideration...

-webkit-font-smoothing: subpixel-antialiased; = I'm sure the font is cool, but you re-try redrawing all the pixel specific shading crap on the fly smoothly....

translate3d( 0, 0, 0) = 'ol hack to force hardware acceleration in some instances and let the gpu help out.

margin: 0 = on your h2 to remove the user agent margin garbage from consideration...

perspective(1px) = Because you're transforming, remind it where home is...

Between these hopefully you should see the result you're expecting, hope it helps, cheers!

Oh, and just a quick PS: You don't need that many elements to accomplish the same thing (unless there's more to your example than what we see), I would try to shake that habit. One element and some text could deliver the same result with a cleaner DOM and less for the compositor thread to care about while doing its thing.

ADDENDUM; Eventually with scale you're going to run into a resolution loss as it's resizing an elements dimensions and its children on a 2d plane with a rasterization. Avoiding blurry effect the larger something is scaled is inevitable (as far as I know today) unless you want refactor into say a canvas with zoom, or easier yet treat the instance for what it is and instead just target the font in this scenario since it's the only thing actually needing to stay legible. So see the added example, which is targeting font-size as a vector instead. Cheers!

like image 114
Chris W. Avatar answered Nov 16 '22 02:11

Chris W.