Home > Mobile >  CSS3 transform: matrix3d gives other results in Chrome, Edge & Safari vs Firefox
CSS3 transform: matrix3d gives other results in Chrome, Edge & Safari vs Firefox

Time:12-06

I am trying to place 2 images on top of each other in an SVG using the css transform matrix3d. In Firefox this looks fine, but in Chrome, Safari & Edge I get a different result.

Anyone has got any idea what I am doing wrong or if there are some sort of limitations?

Relevant code:

<svg width="1920" height="1080" >
    <image xlink:href="/images/psv/screenreplace/exposure-led-wall.jpg" width="1920" height="1080"></image>
    <image id="screen-image-0" xlink:href="https://youreka-virtualtours.be/screenreplacer/362/1/logos/wallpaper4-1670251089552.jpg" width="640" height="252"></image>
    <defs>
        <style>
            #screen-image-0 {
                transform:matrix3d(1.52966, 0.704576, 0, 0.00068864, -0.0772169, 1.48607, 0, -0.00014322, 0, 0, 1, 0, 910, 299, 0, 1);
            } 
        </style>
    </defs>
</svg>

The result in Firefox: Firefox

The result in the other browsers: Chrome etc

CodePudding user response:

The issue is that Safari and Chrome do convert your 3D matrix to a 2D one.
It's not entirely clear who is right here.

Some CSS attributes must map to SVG presentation attributes. transform is one of these, so it's normal you can set an SVG element's transform through CSS. However, the SVG transform attribute is far from being clear. Current specs state

8.5. The ‘transform’ property

User agents must support the transform property and presentation attribute as defined in [css-transforms-1].

And when we follow this [css-transforms-1] we end on two links, both stating

This specification is the convergence of the CSS 2D Transforms and SVG transforms specifications.

Only this latter document does talk about 3D transforms. But the "convergence" documents, that do actually rule, completely ignore it.

Even the DOM interfaces that are supposed to reflect the current transformation matrix applied on the element are defined to be 2D only.

So what should happen when we apply a 3D matrix to an SVG element?

Interop issues apparently.

Chrome and Safari behavior kind of makes sense, they "filter" the matrix component to be only 2D just like what would happen if you were to modify the element's .transform.baseVal SVGTransformList. I.e they do map 1-1 CSS and presentation attributes. Firefox on the other hand does what one would probably want to happen, i.e they do respect the authored CSS rule.
Once again, I'm not entirely sure which is correct.

const button = document.querySelector("button");
const el = document.querySelector(".trans");
const list = el.transform.baseVal;
const matrix = new DOMMatrix("matrix3d(1.5, 0.7, 0, 0.0007, -0.07, 1.48, 0, -0.00014, 0, 0, 1, 0, -800, 0, 0, 1)");
let newTransform;
try {
  newTransform = list.createSVGTransformFromMatrix(matrix);
}
catch(err) {
  // Chrome doesn't support createSVGTransformFromMatrix(DOMMatrix)...
  const { a, b, c, d, e, f } = matrix;
  const mat = document.querySelector("svg").createSVGMatrix();
  Object.assign(mat, { a, b, c, d, e, f });
  newTransform = list.createSVGTransformFromMatrix(mat);
}
button.onclick = (evt) => {
  el.classList.remove("trans");
  list.clear();
  list.appendItem(newTransform); // Won't change anything in Chrome and Safari
                                 // Will make Firefox behave like the others
};
svg { height: 500px }
.trans {
  transform: matrix3d(1.5, 0.7, 0, 0.0007, -0.07, 1.48, 0, -0.00014, 0, 0, 1, 0, -800, 0, 0, 1);
}
<button>apply matrix</button><br>
<svg width="1920" height="1080" viewBox="0 0 1900 1200">
  <rect  width="640" height="252"/>
</svg>

Note that both Safari and Chrome do support 3D transforms on the root <svg> element, so you might be able to achieve the same result by using an other <svg> just to render that transformed image, but that enters the hack area and might not be trivial to get it right.

CodePudding user response:

It looks like you are using the CSS transform property to apply a 3D transformation matrix to the #screen-image-0 element. This property should work consistently across modern web browsers, but there are a few reasons why you might be seeing different results in different browsers.

One possible reason is that the browsers you are using have different levels of support for the transform property and the matrix3d() function. While most modern browsers support these features, there may be some differences in how they handle certain values or calculations.

Another reason could be that the images themselves are different sizes or have different aspect ratios, which can affect how they are transformed and displayed. For example, if one image is wider or taller than the other, it may appear distorted or skewed when transformed using the same matrix.

One solution to this problem would be to make sure that both images are the same size and have the same aspect ratio, so that they can be consistently transformed using the same matrix. Another solution would be to use a different CSS transform function, such as scale(), translate(), or rotate(), which may produce more consistent results across different browsers.

It's also worth noting that the transform property and the matrix3d() function are not supported in older browsers, such as Internet Explorer 9 and earlier. If you need to support these browsers, you may need to use a different approach to apply your transformations.

  • Related