我正在尝试创建一个CSS动画,它可以在屏幕上移动元素,并使其在空间中的特定点处淡入淡出.由于使用了不同的缓和功能,我无法确定它何时会到达那里.
这是一个适用于Chromium但不适用于Firefox的示例:
.mover, .marker {
position: relative;
width: 10vmin;
height: 10vmin;
}
@keyframes mover {
from {
left: 0vmin;
opacity: -3;
}
to {
left: 90vmin;
opacity: 6;
}
}
.mover {
background: red;
animation: mover 10s infinite;
}
.marker {
background: blue;
left: 30vmin;
}
<div class="mover" style="animation-timing-function: linear;"></div>
<div class="mover" style="animation-timing-function: ease-in;"></div>
<div class="mover" style="animation-timing-function: ease-out;"></div>
<div class="marker"></div>
在Chromium中,红色块全部在蓝色块的正上方淡入,这要归功于在[0,1]的预期范围之外插入不透明度.似乎Chromium首先插入不透明度,然后才将其钳制到范围[0,1].这是一个肮脏的伎俩,但它有点工作.
然而,似乎Firefox做了相反的事情:它在应用插值之前首先钳位到[0,1].结果是从轨道的最左侧到最右侧平滑淡入.
我可以通过动画转换而不是左转来使它在Chromium中断,所有逻辑都不应该产生影响:
.mover, .marker {
position: relative;
width: 10vmin;
height: 10vmin;
}
@keyframes mover {
from {
transform: translate(0vmin, 0);
opacity: -3;
}
to {
transform: translate(90vmin, 0);
opacity: 6;
}
}
.mover {
background: red;
animation: mover 10s infinite;
}
.marker {
background: blue;
left: 30vmin;
}
<div class="mover" style="animation-timing-function: linear;"></div>
<div class="mover" style="animation-timing-function: ease-in;"></div>
<div class="mover" style="animation-timing-function: ease-out;"></div>
<div class="marker"></div>
哪个浏览器在这里正确?更重要的是,如何在不诉诸JavaScript的情况下实现此效果?
精确的浏览器版本:
> Chromium 71.0.3578.98(官方版)Arch Linux(64位)
> Firefox 64.0(64位)
最佳答案 考虑到您想要慢慢显示内容的事实,我会使用不同的方式来实现与不透明度相似的效果.我会考虑使用另一个动画隐藏在元素上方的叠加层.
这里的想法是使用具有相同度量的动画,以便与移动器动画同步,并仅在空间的所需点显示元素.
为此,我将考虑一个伪元素,其宽度等于路径的宽度(90vmin – 0vmin = 90vmin),它将在相反的方向上获得动画.这个元素将具有渐变色,这种色彩将创造魔力.
这是一个例子:
.mover, .marker {
position: relative;
width: 10vmin;
height: 10vmin;
z-index:0;
overflow:hidden;
color:#fff;
}
.mover:before {
content:"";
position:absolute;
z-index:99;
top:-1px;
bottom:-1px;
left:0;
width:90vmin;
background:linear-gradient(to right,#fff 33%,transparent);
animation: fader 10s infinite;
animation-timing-function:inherit;
}
.mover {
background: red;
animation: mover 10s infinite;
}
.marker {
background: blue;
left: 30vmin;
}
@keyframes mover {
from {
left: 0vmin;
}
to {
left: 90vmin;
}
}
@keyframes fader {
to {
transform:translateX(-100%);
}
}
<div class="mover" style="animation-timing-function: linear;">1</div>
<div class="mover" style="animation-timing-function: ease-in;">2</div>
<div class="mover" style="animation-timing-function: ease-out;">3</div>
<div class="marker"></div>
为了更好地了解发生了什么,让我们改变颜色并删除overlfow:
.mover, .marker {
position: relative;
width: 10vmin;
height: 10vmin;
z-index:0;
color:#fff;
/*overflow:hidden;*/
}
.mover:before {
content:"";
position:absolute;
z-index:99;
top:-1px;
bottom:-1px;
left:0;
width:90vmin;
background:linear-gradient(to right,green 33%,transparent);
animation: fader 10s infinite;
animation-timing-function:inherit;
}
.mover {
background: red;
animation: mover 10s infinite;
}
.marker {
background: blue;
left: 30vmin;
}
@keyframes mover {
from {
left: 0vmin;
}
to {
left: 90vmin;
}
}
@keyframes fader {
to {
transform:translateX(-100%);
}
}
<div class="mover" style="animation-timing-function: linear;">1</div>
<div class="mover" style="animation-timing-function: ease-in;">2</div>
<div class="mover" style="animation-timing-function: ease-out;">3</div>
<div class="marker"></div>
我们可以清楚地看到伪元素没有移动,因为它只是在与主元素相反的方向上以相同的速度移动.从我们的角度来看,它是固定的.然后我们将元素着色到33%,这是30vmin,因此我们的元素将在此时开始显示.
通过添加溢出并使用与主背景相同的颜色,我们创建了淡化幻觉.当然,如果主背景不是纯色,那么这个技巧就行不通了.
另一个想法是仅通过调整和动画背景大小/背景位置来依赖背景,因此伪元素将具有与主元素相同的大小:
.mover, .marker {
position: relative;
width: 10vmin;
height: 10vmin;
z-index:0;
overflow:hidden;
color:#fff;
}
.mover:before {
content:"";
position:absolute;
z-index:99;
top:-1px;
bottom:-1px;
left:0;
right:0;
background-image:linear-gradient(to right,#fff 33%,transparent);
background-size:90vmin 100%;
background-position:left;
animation: fader 10s infinite;
animation-timing-function:inherit;
}
.mover {
background: red;
animation: mover 10s infinite;
}
.marker {
background: blue;
left: 30vmin;
}
@keyframes mover {
from {
left: 0vmin;
}
to {
left: 90vmin;
}
}
@keyframes fader {
to {
background-position:right;
}
}
<div class="mover" style="animation-timing-function: linear;">1</div>
<div class="mover" style="animation-timing-function: ease-in;">2</div>
<div class="mover" style="animation-timing-function: ease-out;">3</div>
<div class="marker"></div>
为了控制褪色效果,我们将背景大小增加90vmin的任何倍数
.mover, .marker {
position: relative;
width: 10vmin;
height: 10vmin;
z-index:0;
overflow:hidden;
color:#fff;
}
.mover:before {
content:"";
position:absolute;
z-index:99;
top:-1px;
bottom:-1px;
left:0;
right:0;
background-image:linear-gradient(to right,#fff 33%,transparent);
background-size:calc(var(--m,1)*90vmin) 100%;
background-position:left;
animation: fader 10s infinite;
animation-timing-function:inherit;
}
.mover {
background: red;
animation: mover 10s infinite;
}
.marker {
background: blue;
left: 30vmin;
}
@keyframes mover {
from {
left: 0vmin;
}
to {
left: 90vmin;
}
}
@keyframes fader {
to {
background-position:right;
}
}
<div class="mover" style="animation-timing-function: linear;">1</div>
<div class="mover" style="animation-timing-function: ease-in;--m:5">2</div>
<div class="mover" style="animation-timing-function: ease-out;--m:20">3</div>
<div class="marker"></div>
尺寸越大,我们越接近不透明效果.
UPDATE
这是另一个想法,你可以有透明度,但没有褪色效果.诀窍是使用我们设置动画的剪辑路径,以便在所需位置显示元素.
.mover, .marker {
position: relative;
width: 10vmin;
height: 10vmin;
color:#fff;
}
.mover {
background: red;
animation: mover 10s infinite,
fader 10s infinite;
}
.marker {
background: blue;
left: 30vmin;
}
@keyframes mover {
from {
left: 0vmin;
}
to {
left: 90vmin;
}
}
@keyframes fader {
from {
clip-path:polygon(30vmin 0%, 100vmin 0%,
100vmin 100%,
30vmin 100% );
}
to {
clip-path:polygon(-60vmin 0%, 10vmin 0%,
10vmin 100%,
-60vmin 100% );
}
}
html {
background:radial-gradient(pink,yellow);
}
<div class="mover" style="animation-timing-function: linear;">1</div>
<div class="mover" style="animation-timing-function: ease-in;">2</div>
<div class="mover" style="animation-timing-function: ease-out;">3</div>
<div class="marker"></div>
以下是更好地了解所发生情况的说明:
橙色矩形是剪裁区域.它应该从标记开始(30vmin)并在结束时考虑元素的宽度(90vmin 10vmin = 100vmin).这意味着最初我们不会看到该元素.
该区域应保持固定在我们的视角,以便能够仅在到达标记时才能看到元素,因此我们应该在对方方向移动它,并且这样做我们只需更改剪辑路径.
完成动画后,我们将拥有:
修剪区域应该在元素的末尾(10vmin)结束,它应该保持相同的尺寸,因此需要从(-60vmin)开始.
我们现在可以像使用background-size一样增加剪辑路径区域来控制淡入淡出效果,我们可以添加不透明度动画并更接近初始要求.
.mover, .marker {
position: relative;
width: 10vmin;
height: 10vmin;
color:#fff;
}
.mover {
background: red;
animation: mover 10s infinite,
fader 10s infinite;
}
.marker {
background: blue;
left: 30vmin;
}
@keyframes mover {
from {
left: 0vmin;
}
to {
left: 90vmin;
}
}
@keyframes fader {
from {
clip-path:polygon(300vmin 0%, 1000vmin 0%, /* x10*/
1000vmin 100%,
300vmin 100% );
opacity:0;
}
to {
clip-path:polygon(-600vmin 0%, 100vmin 0%,
100vmin 100%,
-600vmin 100% );
opacity:1;
}
}
html {
background:radial-gradient(pink,yellow);
}
<div class="mover" style="animation-timing-function: linear;">1</div>
<div class="mover" style="animation-timing-function: ease-in;">2</div>
<div class="mover" style="animation-timing-function: ease-out;">3</div>
<div class="marker"></div>
值得注意的是,剪辑路径仍未得到广泛支持(https://caniuse.com/#search=clip-path),您需要添加-webkit-前缀以覆盖Safari浏览器.