css – 如何在页面上的特定位置淡入移动元素?

我正在尝试创建一个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>

以下是更好地了解所发生情况的说明:

《css – 如何在页面上的特定位置淡入移动元素?》

橙色矩形是剪裁区域.它应该从标记开始(30vmin)并在结束时考虑元素的宽度(90vmin 10vmin = 100vmin).这意味着最初我们不会看到该元素.

该区域应保持固定在我们的视角,以便能够仅在到达标记时才能看到元素,因此我们应该在对方方向移动它,并且这样做我们只需更改剪辑路径.

完成动画后,我们将拥有:

《css – 如何在页面上的特定位置淡入移动元素?》

修剪区域应该在元素的末尾(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浏览器.

点赞