问题
您看到的不是“浏览器错误”,而是对计算两个组合缩放的工作原理的误解。
为简单起见,我们假设转换函数是linear(而不是ease,这是默认的计时函数)。在这种情况下,两个尺度的图如下:

由于我们希望内部元素的最终比例保持不变,因此所有时间参数的(放大功能)×(缩小功能)= 1。不幸的是,如果我们进行乘法运算,结果我们会得到一个平方函数(在我们的例子中是 -¾x² + 3x + ¾)。这是您可以在过渡过程中看到的最终缩放的凸起。为了避免这种情况scale(n),我们需要缩放min scale(1/m)css 规则,而不是转换值。不幸的是,即使我们使用了 css 变量,我们也不能这样做,因为这些变量(还)不允许转换(见这个答案)
为了缓解这种情况,我们可以制作一个自定义的cubic-bezier计时函数,它是平方函数的倒数,但我无法手动完成,并且可能cubic-bezier不会给出所有时间值的准确曲线,特别是如果我们想要基本计时功能除了linear.
解决方案
方法一:我们可以改变外部 div 的尺寸,而不是缩放,如下所示:
const outer = document.querySelector('.outer');
outer.addEventListener('click', () => {
outer.classList.toggle('outer--active');
});
body { overflow: hidden; }
.outer {
width: 100px;
height: 100px;
overflow: hidden;
border-radius: 100%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
transform-origin: top left;
transition: all 1s;
cursor: pointer;
border: 1px solid black;
}
.outer--active {
width: 400px;
height: 400px;
}
.inner {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 400px;
height: 400px;
background: url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/49240/14.jpg') center repeat;
transform-origin: top left;
transition: transform 1s;
}
<div class="outer">
<div class="inner"></div>
</div>
优点:保留当前的 html 标记结构
缺点:由于有关亚像素过渡平滑的浏览器错误(例如firefox 错误报告) ,动画不连贯
方法2:使用剪贴蒙版制作圆形抠图效果,为边框添加div:
const outer = document.querySelector('.outer');
outer.addEventListener('click', () => {
outer.classList.toggle('outer--active');
});
body { overflow: hidden; }
.outer {
width: 100px;
height: 100px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
transform-origin: top left;
cursor: pointer;
}
.rim {
width: 100px;
height: 100px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border-radius: 100%;
border: 1px solid black;
transition: all 1s;
transform-origin: top left;
}
.outer--active .rim {
transform: scale(4) translate(-50%, -50%);
}
.inner {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 400px;
height: 400px;
background: url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/49240/14.jpg') center repeat;
transform-origin: top left;
transition: all 1s;
clip-path: circle(50px at 200px 200px);
}
.outer--active .inner {
clip-path: circle(200px at 200px 200px);
}
<div class="outer">
<div class="inner"></div>
<div class="rim"></div>
</div>
优点:平滑扩展
缺点:需要为圆形边框/边缘添加另一个 html 标签。边缘有时可能看起来与内部图像脱节。