otsukare Thoughts after a day of work

CSS zoom, a close up on issues

CSS zoom is a non-standard feature.

It was initially implemented by Microsoft Internet Explorer, then was reversed engineered by Apple Safari team for WebKit, and exist in Google Chrome on Blink. Chris talks briefly about the origin.

Back in the days of IE6, zoom was used primarily as a hack. Many of the rendering bugs in both IE6 and IE7 could be fixed using zoom. As an example, display: inline-block didn't work very well in IE6/7. Setting zoom: 1 fixed the problem. The bug had to do with how IE rendered its layout. Setting zoom: 1 turned on an internal property called hasLayout, which fixed the problem.

In Apple docs:

Children of elements with the zoom property do not inherit the property, but they are affected by it. The default value of the zoom property is normal, which is equivalent to a percentage value of 100% or a floating-point value of 1.0.

Changes to this property can be animated.

There is no specification describing how it is working apart of the C++ code of WebKit and Blink. It predates the existence of CSS transforms, which is the right way of doing it. But evidently, the model is not exactly the same.

Firefox (Gecko) doesn't implement it. There is a very old open bug on Bugzilla about implementing CSS Zoom, time to time, we duplicate webcompat issues against it. Less often now than previously.

On the webcompat side, the fix we recommend to websites is to use CSS transform. A site which would have for example:

section {zoom: 1}

could replace this with

section {
    transform-origin: 0 0;
    transform: scale(100%)
}

And that would do the trick most of the time.

On October 2019, Emilio made an experiment trying to implement CSS zoom using only CSS transform, on the same model that the webcompat team is recommending. And we tested this for a couple of weeks in Nightly Firefox 72 until… it created multiple regressions such as this one.

After removing the rest of the rules, this the core of the issue:

.modal.modal--show .modal-container {

    transform: translate(-50%,-50%);
    zoom: 1;
}

so the fix would replace this by:

.modal.modal--show .modal-container {

    transform: translate(-50%,-50%);
    transform-origin: 0 0;
    transform: scale(100%)
}

hence cancelling the previous rule translate(-50%,-50%) and breaking the layout.

Emilio had to disable the preference and we need to think a better way of doing it.

Otsukare!