我有<div>
我用作幻灯片放映图像容器。将在容器中显示的图像具有不同的大小并应用为背景图像,而不是容器内的<img>
元素,以便:
我有background-size:cover
和background-clip:content-box
这些正确地将图像保存在容器的所需区域内,确保正确剪裁多余的图像。
第一个问题是在CSS动画期间,当一个图像过渡到另一个图像时,新图像会在该关键帧的定时过程中调整大小。我想要的是将下一个图像转换为(已经适当的尺寸),而不会看到它调整大小。
实际上,我甚至不确定为什么首先会出现交叉淡入淡出可视化,因为我没有指示这样做(可能是内置的-webkit-
动画?)。我原以为你只会看到从一张图片到另一张图片的即时更改。我实际上喜欢交叉淡入淡出,但不知道它的来源让我觉得它与调整大小问题有关。
第二个问题是在幻灯片放映的第一次迭代(仅)期间,图像闪烁,并且简要地显示容器元素的白色背景颜色。因为这只发生在第一次迭代中,我认为这可能是图像初始下载时间的问题,这也就是它在后续迭代中消失的原因。但是,当我在幻灯片放映开始之前添加一些JavaScript来预加载图像并发现同样的问题时,事实证明并非如此。此外,一旦你运行节目,你有缓存中的图像和刷新页面(这将只是从你的缓存中获取图像,是的,我通过从我自己的测试服务器获取文件来测试它,所以他们将正确缓存)闪烁再次发生。
我已经看过一些关于使用preserve3d
这样的各种CSS属性设置消除闪烁的帖子,但这些都没有帮助。
我在Windows 10上使用Chrome 62.0.3202.94桌面。
#outerFrame {
background-color: #22130c;
box-shadow: inset 0 1px 1px 1px hsla(0,0%,100%,.2),
inset 0 -2px 1px hsla(0,0%,0%,.4),
0 5px 50px hsla(0,0%,0%,.25),
0 20px 20px -15px hsla(0,0%,0%,.2),
0 30px 20px -15px hsla(0,0%,0%,.15),
0 40px 20px -15px hsla(0,0%,0%,.1);
padding: 1.5em;
overflow: auto;
float: left;
margin: 0 1em 1em 0;
}
#innerFrame {
background-color: #fff5e5;
box-shadow: 0 2px 1px hsla(0,0%,100%,.2),
0 -1px 1px 1px hsla(0,0%,0%,.4),
inset 0 2px 3px 1px hsla(0,0%,0%,.2),
inset 0 4px 3px 1px hsla(0,0%,0%,.2),
inset 0 6px 3px 1px hsla(0,0%,0%,.1);
padding: 1.5em;
}
/* This is the relevant style: */
#innermostFrame {
padding: .75em;
background-color: #fff;
box-shadow: 0 -1px 0 2px hsla(0, 0%, 0%,.03);
background-position: 50% 50%;
background-repeat: no-repeat;
background-size:cover;
background-clip: content-box;
animation: cycle 8s ease-in-out infinite;
width: 30vw;
height:40vh;
min-width: 200px;
max-width: 900px;
}
@keyframes cycle {
0% { background-image: url("https://picsum.photos/200/300/?random"); }
25% { background-image: url("https://picsum.photos/640/480/?random"); }
50% { background-image: url("https://picsum.photos/1900/1200/?random"); }
75% { background-image: url("https://picsum.photos/480/200/?random"); }
100% { background-image: url("https://picsum.photos/600/300/?random"); }
}
&#13;
<div id="outerFrame">
<div id="innerFrame">
<div id="innermostFrame"></div>
</div>
</div>
&#13;
我意识到我可以使用其他各种技术(即JavaScript,堆叠<img>
元素和管理opaccity
等)来解决这些问题,但我真的想了解造成这些问题的原因两个问题。
答案 0 :(得分:3)
<强> 1。交叉衰减:强>
这是因为浏览器尝试在关键帧之间设置动画。如果我们看看你的@keyframes周期,我们会看到你每25%创建一个关键帧。这意味着浏览器的动画范围为0%到25%。它的动画是什么?背景改变了。它将如何制作动画?交叉淡入淡出。此外,背景的大小再次覆盖div(使用的图片格式不同 - 如果使用相同的格式 - 这可能不会发生)。
@keyframes cycle {
0% { background-image: url("https://picsum.photos/200/300/?random"); }
25% { background-image: url("https://picsum.photos/640/480/?random"); }
50% { background-image: url("https://picsum.photos/1900/1200/?random"); }
75% { background-image: url("https://picsum.photos/480/200/?random"); }
100% { background-image: url("https://picsum.photos/600/300/?random"); }
}
解决方案A(无交叉渐变和白色背景)
你可以通过让动画几乎瞬间发生来摆脱调整大小:
0% { background-image: url("https://picsum.photos/200/300/?random"); }
24.99% { background-image: url("https://picsum.photos/200/300/?random"); }
25% { background-image: url("https://picsum.photos/640/480/?random"); }
关键帧0%中的背景在关键帧24.99%处是相同的,因此它不会设置动画。然后它变化为25%(这看起来像是一个瞬间变化)见下面的工作片段:
#outerFrame {
background-color: #22130c;
box-shadow: inset 0 1px 1px 1px hsla(0,0%,100%,.2),
inset 0 -2px 1px hsla(0,0%,0%,.4),
0 5px 50px hsla(0,0%,0%,.25),
0 20px 20px -15px hsla(0,0%,0%,.2),
0 30px 20px -15px hsla(0,0%,0%,.15),
0 40px 20px -15px hsla(0,0%,0%,.1);
padding: 1.5em;
overflow: auto;
float: left;
margin: 0 1em 1em 0;
}
#innerFrame {
position: relative;
background-color: #fff5e5;
box-shadow: 0 2px 1px hsla(0,0%,100%,.2),
0 -1px 1px 1px hsla(0,0%,0%,.4),
inset 0 2px 3px 1px hsla(0,0%,0%,.2),
inset 0 4px 3px 1px hsla(0,0%,0%,.2),
inset 0 6px 3px 1px hsla(0,0%,0%,.1);
padding: 1.5em;
}
/* This is the relevant style: */
#innermostFrame{
padding: .75em;
background-color: #fff;
box-shadow: 0 -1px 0 2px hsla(0, 0%, 0%,.03);
background-position: 50% 50%;
background-repeat: no-repeat;
background-size:cover;
background-clip: content-box;
animation: cycle 8s ease-in-out infinite;
width: 30vw;
height:40vh;
min-width: 200px;
max-width: 900px;
}
@keyframes cycle {
0% { background-image: url("https://picsum.photos/200/300/?random"); }
24.99% { background-image: url("https://picsum.photos/200/300/?random"); }
25% { background-image: url("https://picsum.photos/640/480/?random"); }
49.99% { background-image: url("https://picsum.photos/640/480/?random"); }
50% { background-image: url("https://picsum.photos/1900/1200/?random"); }
74.99% { background-image: url("https://picsum.photos/1900/1200/?random"); }
75% { background-image: url("https://picsum.photos/480/200/?random"); }
99.99% { background-image: url("https://picsum.photos/480/200/?random"); }
100% { background-image: url("https://picsum.photos/200/300/?random"); }
}
<div id="outerFrame">
<div id="innerFrame">
<div id="innermostFrame"></div>
</div>
</div>
注意!最后一个关键帧(100%)应该设置为与第一个关键帧(0%)相同的值,因为我们希望循环从它停止的位置开始。实际上,这意味着在这个例子中你只有4个不同的背景图像(如果你想要5个 - 取代20%的步骤)。
我们通过调整大小背景来解决问题。作为副作用,我们还“修复”了交叉渐变。真正的缺点是我们在动画第一次播放时仍然具有白色背景。
<强> 2。白色背景
我认为出现白色背景是因为需要先装入图像。它们仅在动画运行时加载。这就是为什么第一次运行低谷有白色背景的原因。
解决方案B(交叉渐变且无白色背景)
我们可以使用辅助div来获得交叉渐变效果。但我们必须在keframe中设置不透明度。我们可以在显示另一个div的同时在关键帧中设置背景图像 - 因此它有更多的时间加载并且不会出现白色背景。请参阅以下代码段:
#outerFrame {
background-color: #22130c;
box-shadow: inset 0 1px 1px 1px hsla(0,0%,100%,.2),
inset 0 -2px 1px hsla(0,0%,0%,.4),
0 5px 50px hsla(0,0%,0%,.25),
0 20px 20px -15px hsla(0,0%,0%,.2),
0 30px 20px -15px hsla(0,0%,0%,.15),
0 40px 20px -15px hsla(0,0%,0%,.1);
padding: 1.5em;
overflow: auto;
float: left;
margin: 0 1em 1em 0;
}
#innerFrame {
position: relative;
background-color: #fff5e5;
box-shadow: 0 2px 1px hsla(0,0%,100%,.2),
0 -1px 1px 1px hsla(0,0%,0%,.4),
inset 0 2px 3px 1px hsla(0,0%,0%,.2),
inset 0 4px 3px 1px hsla(0,0%,0%,.2),
inset 0 6px 3px 1px hsla(0,0%,0%,.1);
padding: 1.5em;
}
/* This is the relevant style: */
#innermostFrame,
#innermostFrame2{
padding: .75em;
background-color: #fff;
box-shadow: 0 -1px 0 2px hsla(0, 0%, 0%,.03);
background-position: 50% 50%;
background-repeat: no-repeat;
background-size:cover;
background-clip: content-box;
animation: cycle 8s ease-in-out infinite;
width: 30vw;
height:40vh;
min-width: 200px;
max-width: 900px;
}
#innermostFrame2{
position: absolute;
top: 1.5em; /* padding of innerFrame */
animation: cycle2 8s infinite;
background-image: url("https://picsum.photos/200/300/?random");
}
@keyframes cycle {
0% { background-image: url("https://picsum.photos/640/480/?random"); }
50% { background-image: url("https://picsum.photos/640/480/?random"); }
51% { background-image: url("https://picsum.photos/480/200/?random"); }
100% { background-image: url("https://picsum.photos/480/200/?random"); }
}
@keyframes cycle2 {
15% { opacity: 1;}
25% { opacity: 0; background-image: url("https://picsum.photos/200/300/?random"); }
26% { background-image: url("https://picsum.photos/1900/1200/?random");}
40% { opacity: 0;}
50% { opacity: 1;}
65% { opacity: 1;}
75% { opacity: 0; background-image: url("https://picsum.photos/1900/1200/?random");}
76% { background-image: url("https://picsum.photos/200/300/?random");}
90% { opacity: 0;}
100% { opacity: 1;}
}
<div id="outerFrame">
<div id="innerFrame">
<div id="innermostFrame"></div>
<div id="innermostFrame2"></div>
</div>
</div>
解决方案B解释:
这个想法是让背景图像在显示之前加载。因此,有2个div具有2个@keyframe
动画,导致背景平滑交替。
#innermostFrame2
获得与#innermostFrame
相同的宽度和高度,并且位于绝对位置(正上方)。 #innermostFrame2
的显示和隐藏时间为动画持续时间的25%。以下是可见的:
25% 25% 25% 25%
[ #innermostFrame2 - #innermostFrame - #innermostFrame2 - #innermostFrame ]
<强>百分比:强>
已为#innermostFrame2
本身设置了背景图片 - 使其尽可能快地加载。在@keyframes cycle2
中,不需要0%,因为背景已经设置并且可见。
我们希望图像显示25%的动画(4张图像)。现在我决定在这个例子中10%的交叉淡入淡出看起来很好(8秒动画的10%是0.8秒)。你可以做得更少或更多,因为这是一个品味的问题。这就是为什么动画的不透明度为1的15%和0的25%。在div不可见之后,我们立即将背景图像更改为26%,因此可以将其加载到CSS对象模型中。
#innermostFrame
的背景现在可见(因为隐藏了#innermostFrame2
)。我们希望在动画持续时间的25%内显示此信息。因此,在50%时,我们希望#innermostFrame2
再次以新背景显示。因为我决定在动画持续时间的10%内交叉淡入淡出,所以我们以opacity: 0;
开始40%。在#innermostFrame2
完全显示(50%)后,我们立即更改#innermostFrame
的背景以加载它。这种情况发生在@keyframes cycle