CSS transition scale()-怪异的延迟

Mar*_*ioD 3 css css3 css-transitions css-transforms

运行下面的代码片段-单击圆圈以切换动画。应该发生的是,当父容器缩放时,子级应该看起来好像没有移动。

这可以通过按放大父级的相同比例缩小子级分量(父级缩放到4,子级缩放到0.25)来实现。

动画制作完成后,缩放比例是正确的,但是在动画制作过程中,它们似乎并没有一起缩放。

几乎就像父级先缩放,然后完成子级缩放一样。

这是某种浏览器限制吗?还是我做错了什么?

谢谢!

const outer = document.querySelector('.outer');

outer.addEventListener('click', () => {
  outer.classList.toggle('outer--active');
});
Run Code Online (Sandbox Code Playgroud)
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: transform 1s;
  cursor: pointer;
  border: 1px solid black;
}

.outer--active {
  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: transform 1s;
}

.outer--active .inner {
  transform: scale(0.25) translate(-50%, -50%);
}
Run Code Online (Sandbox Code Playgroud)
<div class="outer">
  <div class="inner"></div>
</div>
Run Code Online (Sandbox Code Playgroud)

Pio*_*ski 7

问题

您所看到的不是“浏览器错误”,而是对两个组合缩放比例的计算工作原理的误解。

为简单起见,让我们假设转换函数是linear(而不是ease,这是默认的计时函数)。在这种情况下,两个比例的图将如下所示: 缩放功能

由于我们要使内部元素的最终比例保持恒定,因此对于所有时间参数,(比例放大函数)×(比例缩小函数)= 1。不幸的是,如果我们进行乘法运算,结果得到一个平方函数(在我们的例子中是-¾x²+ 3x +¾)。这是您在过渡过程中可以看到的最终缩放比例的提高。为了避免这种情况,scale(n)我们需要缩放min scale(1/m)css规则,而不是转换值。不幸的是,我们不能做到这一点,即使我们使用CSS的变量,因为这些不(还)允许转换(见这个答案)

为了减轻这种情况,我们可以设计一个自定义的cubic-bezier计时函数,该函数将与平方函数相反,但我无法手动执行,并且可能cubic-bezier无法给出所有时间值的精确曲线,尤其是当我们想要获得基本计时功能除了linear

解决方案

方法1:代替缩放,我们可以更改外部div的尺寸,如下所示:

const outer = document.querySelector('.outer');

outer.addEventListener('click', () => {
  outer.classList.toggle('outer--active');
});
Run Code Online (Sandbox Code Playgroud)
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;
}
Run Code Online (Sandbox Code Playgroud)
<div class="outer">
  <div class="inner"></div>
</div>
Run Code Online (Sandbox Code Playgroud)

优点:保留当前的html标记结构

缺点:由于浏览器有关亚像素过渡平滑的错误(例如firefox错误报告),动画不稳定


方法2:使用剪贴蒙版制作圆形抠图效果,为边框添加div:

const outer = document.querySelector('.outer');

outer.addEventListener('click', () => {
  outer.classList.toggle('outer--active');
});
Run Code Online (Sandbox Code Playgroud)
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);
}
Run Code Online (Sandbox Code Playgroud)
<div class="outer">
  <div class="inner"></div>
  <div class="rim"></div>
</div>
Run Code Online (Sandbox Code Playgroud)

优点:扩展顺畅

缺点:需要为圆形边框/边缘添加另一个html标签。边缘有时看起来与内部图像脱节。