Next step, we’ll use the zoom value that we got, in order to scale the text.

Sounds simple, right? Let’s give it a try.

First Try: Changing font-size

Let’s try multiplying the element’s font-size property with the zoom level.

In addition, I added support for changing the position of the text, by using transform property with translate value.

const FONT_SIZE = 30;

const pos = { x: 0, y: 0}; function renderText() {

textElement.style.fontSize = `${FONT_SIZE * zoom}px`;

const translate = `translate(${pos.x}px, ${pos.y}px)`;

textElement.style.transform = translate;

}

It depends on which browser you run this code, but in Chrome, for example, the result looks like this:

Changing font-size — Running on Chrome

Well, that’s not good. We got a really jaggy result. It looks like the text is “jumping”.

The reason for that is based on the final font-size value that we get.

As you can see in the code:

textElement.style.fontSize = `${FONT_SIZE * zoom}px`;

If, let’s say, zoom === 10 then font-size is a whole number, then we are golden. But if the result is a float number, for example zoom === 10.13 , the computed font-size might be rounded to the nearest integer. Eventually these operations might cause unwanted jumps as we change the zoom level.

Different web browsers have different “rounding” rules. You can read about it here.

Looks like we need to find a different approach.

Second Try: Changing scale

I love using transform properties. It is the most efficient way to translate , rotate or scale your elements, because these operations converts into a single matrix, that get applied on the GPU. So this time, we’ll keep the original font-size , and apply a scale transformation to the element.

function renderText() {

textElement.style.fontSize = `${FONT_SIZE}px`; const translate = `translate(${pos.x}px, ${pos.y}px)`; const scale = `translate(-50%, -50%)

scale(${zoom})

translate(50%, 50%)`; textElement.style.transform = translate + scale;

}

Keep in mind that in order to scale properly, we need to translate the element to its center will be on (0, 0). Otherwise, the position won’t be as expected.

This time, I really thought I made it. The zoom looks smooth on Chrome, Firefox, even on IE11!

BUT, Look at the result on Safari:

Changing scale — Running on Safari

This sucks…

Apparently, on Safari, the scale transformation is applied only after the text is already rendered to a texture. This is why the result looks like a low-res stretched image.

Looks like scale is not the solution for our case either.

So what it the trick?

Combination: font-size + scale

That’s right, the trick is combining the two methods.

We increase font-size to the closest whole number to the desired size.

Then, in order to take care of the remains, we use a tiny scale (Do the math with actual values — it’s a really tiny scale).

function renderText() {

const preciseFontSize = FONT_SIZE * zoom; // Desired font size

const roundedSize = Math.floor(preciseFontSize);

const s = preciseFontSize / roundedSize; // Remaining scale



textElement.style.fontSize = `${roundedSize}px`; const translate = `translate(${pos.x}px, ${pos.y}px)`; const scale = `translate(-50%, -50%)

scale(${s})

translate(50%, 50%)`; textElement.style.transform = translate + scale;

}

Now, this is the result you get on all of the common browsers: