CSS bad rendering in translateZ( ) vs scale( )

2020-08-17 08:08发布

问题:

I noticed that there is a big quality difference when transforming text in this 2 ways:

.text1 {
  width: 200px;
  height: 22px;
  position: absolute;
  top: 40%;
  left: 0;
  transform-origin: 50% 50%;
  transform: scale(2); /* here */
  color: red;
  text-align: center;
  font-size: 22px;
}
.text2 {
  width: 200px;
  height: 22px;
  position: absolute;
  top: 60%;
  left: 0;
  transform-origin: 50% 50%;
  transform: translateZ(400px); /* here */
  text-align: center;
  font-size: 22px;
}
.perspective {
  width: 200px;
  height: 200px;
  perspective: 800px;
  transform-style: preserve-3d;
}
<div class="perspective">
  <div class="text1">Text</div>
  <div class="text2">Text</div>
</div>

Is there a way to force a better rendering when displacing text on the Z axis?

回答1:

the reason the text blurs when you're transforming with translateZ(400px) is that this is a 3D transformation ; the browser treats the element as textures instead of vectors in order to provide hardware 3d acceleration.
So basically the resolution will be lower when increasing size.

On the other hand transforming with scale is a 2D transformation, the browser treats the element as vector and blurring doesn't occur.


take a look at what happens to scale as soon as we kick in with 3d, without actually setting any translateZ value:

.text1 {
    width: 200px;
    height: 22px;
    position: absolute;
    top: 40%;
    left: 0;
    transform-origin: 50% 50%;
    transform: scale(2);
    /* here */
    color: red;
    text-align: center;
    font-size: 22px;
}
.text1a {
    width: 200px;
    height: 22px;
    position: absolute;
    top: 40%;
    left: 50%;
    transform-origin: 50% 50%;
    transform: translateZ(0) scale(2);
    /* here */
    color: blue;
    text-align: center;
    font-size: 22px;
}
.text2 {
    width: 200px;
    height: 22px;
    position: absolute;
    top: 60%;
    left: 0;
    transform-origin: 50% 50%;
    transform: translateZ(400px);
    /* here */
    text-align: center;
    font-size: 22px;
}
.perspective {
    width: 200px;
    height: 200px;
    perspective: 800px;
    transform-style: preserve-3d;
}
<div class="perspective">
    <div class="text1">Text</div>
    <div class="text1a">Text</div>
    <div class="text2">Text</div>
</div>


the only workaround I can think of at the moment is checking the stylesheet through JS and overriding translateZ with transform: scale

var styles = document.styleSheets;

//patterns
var perspPat = /perspective\s*?:\s*?(\d+)/;
var transZPat = /translateZ\(\s*?(\d+)/;

var perspective;
var translateZ = [];
[].slice.call(styles).forEach(function (x) {
    [].slice.call(x.rules).forEach(function (rule) {
        if (perspPat.test(rule.cssText)) {
            perspective = perspPat.exec(rule.cssText)[1]
        };
        if (transZPat.test(rule.cssText)) {
            translateZ.push([
            rule.selectorText,
            transZPat.exec(rule.cssText)[1]]);
        }


    });

})


translateZ.forEach(function (x) {
    document.querySelector(x[0]).style.transform = 'scale(' + perspective / x[1] + ')';

})

fiddle

As you can see, even if it does work, a lot of optimization is needed.. (I wouldn't consider it production ready in it's current state ).



回答2:

You can add font-smooth (for firefox), and antialiasing for webkit

 .text2 {
    -webkit-font-smoothing: antialiased;
    font-smooth: always;
 }

https://developer.mozilla.org/en-US/docs/Web/CSS/font-smooth

http://davidwalsh.name/font-smoothing