3

[SOLUTION]
Solution is to use the will-change CSS property taht forces GPU rendering:

will-change: transform;

[ORIGINAL QUESTION]
I've been digging a lot internet and found no solution to a problem that seems rather simple which is, translating a holder containing text, and having this text moving smoothly.

Here is an example of the problem, you can see the text is following its holder step by step, not smoothly:

enter image description here

I also made a small codepen to see the effect live :

https://codepen.io/Durss/pen/ExgBzVJ?editors=1111

var angle = 0;
var radius = 100;
function renderFrame() {
        requestAnimationFrame(renderFrame);
    var cx = document.documentElement.clientWidth / 2;
    var cy = document.documentElement.clientHeight / 2;
    var div = document.getElementById("text");
    var px = cx + Math.cos(angle) * radius;
    var py = cy + Math.sin(angle) * radius;
    angle += .001;
    div.style.transform = "translate3d("+px+"px, "+py+"px, 0)";
}

renderFrame();
body {
  background-color:black;
  width:100%;
  height:100%;
}

#text {
  position:absolute;
  left:0;
  top:0;
  border: 2px solid white;
  background-color: #2f9da7;
  padding: 10px;
  border-radius:20px;
  color: white;
  font-weight: bold;
}
<div id="text">blah blah</div>

Basically, the problem is that the holder is moving at a subpixel level but the text position seems rounded no matter what i try. I used translate3d() so it uses GPU rendering which fixes the holder's displacement but not its text content.

div.style.transform = "translate3d("+px+"px, "+py+"px, 0)";

I've seen here and there the following CSS "solutions" that didn't work for me:

text-rendering: geometricPrecision;
-webkit-font-smoothing: antialiased;
transform-style: preserve-3d;
backface-visibility: hidden;
-webkit-font-smoothing:none;

I've had this problem many time in the past but always gave up fixing it,i think it's time to seek for help as a last bullet !

Thanks for reading me!

Durss
  • 306
  • 2
  • 11
  • 1
    The trouble is that the time element is actually text. And the browser is trying to optimise it for you by making it fall into subpixels as sharp as possible. Good! But you don't want that. Have you tried to use the text within an SVG element? Maybe the browser won't optimise an SVG. (Sorry if I haven't tried it myself) – Adriano Jan 26 '21 at 05:52
  • Good idea but it doesn't change anything :/ https://codepen.io/Durss/pen/BaLXLEQ – Durss Jan 26 '21 at 13:41
  • Btw; a solution would be to render the text in a canvas and display that canvas in the holder. The canvas being a bitmap would probably benefit the subpixel rendering, but...come on... it's 2021, i hoped i could avoid such a mess ^^' – Durss Jan 26 '21 at 13:45

3 Answers3

2
will-change: contents;

resolved my own jittery text issues when doing transform rotations. This tells the browser that the contents of an element are expected to change therefore should not be cached.

This must be applied immediately before the transform.

Lee John Moore
  • 128
  • 1
  • 1
  • 7
1

CSS transitions help on making sub-pixels animations smoother.

transition: all 0.001s linear;

It works fine on chrome, but seems a bit less effective on firefox. This article may help : Firefox CSS Animation Smoothing (sub-pixel smoothing)

JMPoth
  • 11
  • 1
0

As a workaround you can Math.round the px values. This would prevent the text from jittering on its own (makes the whole containing div jittery).

var angle = 0;
var radius = 100;
function renderFrame() {
        requestAnimationFrame(renderFrame);
    var cx = document.documentElement.clientWidth / 2;
    var cy = document.documentElement.clientHeight / 2;
    var div = document.getElementById("text");
    var px = Math.round(cx + Math.cos(angle) * radius);
    var py = Math.round(cy + Math.sin(angle) * radius);
    angle += .001;
    div.style.transform = "translate3d("+px+"px, "+py+"px, 0)";
}

renderFrame();
body {
  background-color:black;
  width:100%;
  height:100%;
}

#text {
  position:absolute;
  left:0;
  top:0;
  border: 2px solid white;
  background-color: #2f9da7;
  padding: 10px;
  border-radius:20px;
  color: white;
  font-weight: bold;
}
<div id="text">blah blah</div>
Vishal Biswas
  • 401
  • 2
  • 8
  • Rounding the position would indeed make the holder and its text move in sync but the whole holder would jitter instead of just the text which is, to me, even worse :/ – Durss Jan 26 '21 at 13:43