Getting CSS Translate values with JavaScript

Zell Liew đŸ€— - Jul 2 '20 - - Dev Community

How do you get a translateX, translateY or translateZ value in JavaScript?

Turns out, you need to read transform matrices. But it can be quite easy.

Matrices

Browsers turn transform values into 2d or 3d matrices depending on what transformations you applied.

  • Browsers create 3d matrices if you apply 3d transforms (X, Y, Z axes).
  • Browsers create 2d matrices if you apply 2d transforms (X, Y axes only).

We can get the matrix via JavaScript with getComputedStyle.

const style = window.getComputedStyle(element);
const matrix = style.transform || style.webkitTransform || style.mozTransform;
Enter fullscreen mode Exit fullscreen mode

Let's have a look at some examples:

.two-d {
  transform: translateX(10px) translateY(20px);
}
Enter fullscreen mode Exit fullscreen mode

2d transformation matrix

.three-d {
  transform: translateX(10px) translateY(20px) translateZ(30px);
}
Enter fullscreen mode Exit fullscreen mode

3d transformation matrix

2d vs 3d matrices

Pay attention to the matrix values above. You may notice this:

2d Matrix

A 2d matrix has 6 values.

  1. 5th value is translateX
  2. 6th value is translateY

2d transformation matrix

3d Matrix

A 3d matrix has 16 values.

  1. 13th value is translateX
  2. 14th value is translateY
  3. 15th value is translateZ

3d transformation matrix

Getting the translate values

Once we know the pattern, extracting the values is easy. First, we need to know which matrix we're dealing with.

const style = window.getComputedStyle(element);
const matrix = style.transform || style.webkitTransform || style.mozTransform;

// Can either be 2d or 3d transform
const matrixType = matrix.includes("3d") ? "3d" : "2d";
Enter fullscreen mode Exit fullscreen mode

If the Matrix is 2d, we can get values translateX and translateY values like this:

const matrixValues = matrix.match(/matrix.*\((.+)\)/)[1].split(", ");
if (matrixType === "2d") {
  const x = matrixValues[4];
  const y = matrixValues[5];
}
Enter fullscreen mode Exit fullscreen mode

If the Matrix is 3d, we can get values translateX, translateY, and translateZ values like this:

const matrixValues = matrix.match(/matrix.*\((.+)\)/)[1].split(", ");
if (matrixType === "3d") {
  const x = matrixValues[12];
  const y = matrixValues[13];
  const z = matrixValues[14];
}
Enter fullscreen mode Exit fullscreen mode

I packed this up into a nice function for us to use.

/**
 * Gets computed translate values
 * @param {HTMLElement} element
 * @returns {Object}
 */
function getTranslateValues(element) {
  const style = window.getComputedStyle(element);
  const matrix = style.transform || style.webkitTransform || style.mozTransform;

  // No transform property. Simply return 0 values.
  if (matrix === "none") {
    return {
      x: 0,
      y: 0,
      z: 0,
    };
  }

  // Can either be 2d or 3d transform
  const matrixType = matrix.includes("3d") ? "3d" : "2d";
  const matrixValues = matrix.match(/matrix.*\((.+)\)/)[1].split(", ");

  // 2d matrices have 6 values
  // Last 2 values are X and Y.
  // 2d matrices does not have Z value.
  if (matrixType === "2d") {
    return {
      x: matrixValues[4],
      y: matrixValues[5],
      z: 0,
    };
  }

  // 3d matrices have 16 values
  // The 13th, 14th, and 15th values are X, Y, and Z
  if (matrixType === "3d") {
    return {
      x: matrixValues[12],
      y: matrixValues[13],
      z: matrixValues[14],
    };
  }
}
Enter fullscreen mode Exit fullscreen mode

Using it:

const { x, y, z } = getTranslateValues(element);
Enter fullscreen mode Exit fullscreen mode

đŸ’„.

Simple transforms only

getTranslateValues works only if translate is declared before other transforms. This is because transform values stack onto each other.

Let's explain this with a 2d matrix example.

Let's say you have this element.

.element {
  transform: translateX(10px) translateY(20px);
}
Enter fullscreen mode Exit fullscreen mode

2d transformation matrix

You already know these:

  • 5th number is 10 which is the same value as translateX
  • 6th number is 20, which is the same value as translateY

Now let's add a rotate transformation behind translateX and translateY.

.element {
  transform: translateX(10px) translateY(20px) rotate(10deg);
}
Enter fullscreen mode Exit fullscreen mode

Translate then rotate.

There's no difference in the 5th and 6th values:

  • 5th number is 10 which is the same value as translateX
  • 6th number is 20, which is the same value as translateY

But watch what happens if you rotate first.

.element {
  transform: rotate(10deg) translateX(10px) translateY(20px);
}
Enter fullscreen mode Exit fullscreen mode

Rotate then translate.

  • 5th number is 6.37511 which is the NOT what we wrote for translateX
  • 6th number is 21.4326, which is the NOT what we wrote for translateY

Just take note of this!

Getting other transform values in JavaScript

I haven't had the chance to deal with scale, skew, and rotate yet, but I was curious. So I googled and found some answers:

I believe the calculations work with individual transforms. I'm not so sure they work if transformations are stacked on top of each other. (For example, skew -> rotate gives a very different value compared to rotate -> skew).

Keep it simple, I guess!

Useful JavaScript Snippets repository

I added this code to a Github repository that contains JavaScript snippets I found useful. You may be interested in checking it out.


Thanks for reading. This article was originally posted on my blog. Sign up for my newsletter if you want more articles to help you become a better frontend developer.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .