响应式背景图像(动画淡入淡出循环),将跨越页面内容的整个高度



迭代 1 :

我在后台有一个非常愉快的动画。它是响应式的,可以动态填充视口(您可以调整窗口大小并进行调整)。但是,如果页面上的内容超过视口的高度,我会得到一个滚动条(如预期的那样);但是当我向下滚动时,我看到的是网站的黑色背景(而不是背景图像)。

如果您转到页面并调整窗口大小,使视口短于内容,然后滚动,您将明白我的意思:https://www.vortex42studios.com

是否不可能将背景图像缩放到页面的高度或视口高度,两者中的任何一个恰好在任何给定时刻的 px 最长?

IE :如果页面内容为 1000 像素,视口为 700 像素,则背景的高度跨度为 1000 像素。

而且,如果页面内容为 500px,视口为 750px,则背景图像将跨越到视口的 750px 高度。

这样它看起来都不错,当有滚动条时,而不是滚动条?最好是响应式的,就像现在一样,您可以在其中调整窗口大小,并且背景图像会动态相应地调整。如果可能的话,我非常想将其保留为仅限 CSS 的解决方案。

这当然是可能的。我显然错过了一些东西,但无法弄清楚。帮助将不胜感激。

@charset "utf-8";
/* CSS Document */
* {
margin: 0;
}
html {
background-color: #000000;
color: #FFFFFF;
font-family: Constantia, "Lucida Bright", "DejaVu Serif", Georgia, "serif";
font-size: 3vw;
}
html,
body {
height: 100%;
}
.wrapper {
height: 100%;
display: flex;
flex-direction: column;
}
.header {}
.content {
font-size: 2vw;
flex: 1;
}
.footer {}
plateBG {
animation-name: imageAnimation;
animation-iteration-count: infinite;
animation-duration: 25s;
height: 100%;
background-size: cover;
background-repeat: no-repeat;
background-position: center center;
background-attachment: scroll;
position: absolute;
top: 0px;
left: 0px;
width: 100%;
opacity: 0%;
z-index: -1;
overflow: visible;
}
plateBG:nth-child(1) {
background-image: url(https://www.vortex42studios.com/source/img/BG01_1080P.JPG);
}
plateBG:nth-child(2) {
animation-delay: 5s;
background-image: url(https://www.vortex42studios.com/source/img/BG02_1080P.JPG);
}
plateBG:nth-child(3) {
animation-delay: 10s;
background-image: url(https://www.vortex42studios.com/source/img/BG03_1080P.JPG);
}
plateBG:nth-child(4) {
animation-delay: 15s;
background-image: url(https://www.vortex42studios.com/source/img/BG04_1080P.JPG);
}
plateBG:nth-child(5) {
animation-delay: 20s;
background-image: url(https://www.vortex42studios.com/source/img/BG05_1080P.JPG);
}
@keyframes imageAnimation {
0% {
opacity: 0;
}
20% {
opacity: 1;
}
40% {
opacity: 0;
}
60% {
opacity: 0;
}
80% {
opacity: 0;
}
100% {
opacity: 0;
}
}

}
<plateBG></plateBG>
<plateBG></plateBG>
<plateBG></plateBG>
<plateBG></plateBG>
<plateBG></plateBG>
<div class="wrapper">
<div class="header">
<p>vortex42studios</p>
<p>Film and Animation Effects Studios</p>
</div>
<div class="content">
<p>This is content</p>
<p>This is content</p>
<p>This is content</p>
<p>This is content</p>
<p>This is content</p>
<p>This is content</p>
<p>This is content</p>
<p>This is content</p>
</div>
<div class="footer">
<p>Relaunching soon</p>
<p>Facilities in Scotland and Denmark</p>
</div>
</div>

迭代 2 :

我无法使在 SO 上找到的任何方法来强制绝对div 采用其父级的高度(当该元素的高度是自动时)工作。

因此,转向将图像作为背景放在身体本身上,使用伪 before 元素用于淡入图像,使用伪 before 元素淡入,使用伪元素淡出,它有效。身体高度设置为自动,但带有min-height: 100vh.

但是,它需要很多GPU,甚至超过(在撰写本文时)https://www.vortex42studios.com,所以让我们希望有人能想出更好的东西。否则,我们有可能耗尽用户的移动电池或他们的笔记本电脑烧焦他们的膝盖。

* {
margin: 0;
padding: 0;
}
body {
height: auto;
min-height: 100vh;
width: auto;
overflow: visible;
position: relative;
}
body::before, body::after {
display: inline-block;
top: 0;
left: 0;
position: relative;
position: absolute;
content: '';
animation: none 25s infinite ease;
animation-fill-mode: forwards;
width: 100%;
height: 100%;
min-height: 100vh;
z-index: -1;
overflow: visible;
background-size: cover;
background-position: center center;
}
body::before {
animation-name: fadein;
}
body::after {
animation-name: fadeout;
}
@keyframes fadein {
0% {
opacity: 0;
background-image: url(https://www.vortex42studios.com/source/img/BG01_1080P.JPG);
}
20% {
opacity: 1;
background-image: url(https://www.vortex42studios.com/source/img/BG01_1080P.JPG);
}
20.001% {
opacity: 0;
background-image: url(https://www.vortex42studios.com/source/img/BG02_1080P.JPG);
}
40% {
opacity: 1;
background-image: url(https://www.vortex42studios.com/source/img/BG02_1080P.JPG);
}
40.001% {
opacity: 0;
background-image: url(https://www.vortex42studios.com/source/img/BG03_1080P.JPG);
}
60% {
opacity: 1;
background-image: url(https://www.vortex42studios.com/source/img/BG03_1080P.JPG);
}
60.001% {
opacity: 0;
background-image: url(https://www.vortex42studios.com/source/img/BG04_1080P.JPG);
}
80% {
opacity: 1;
background-image: url(https://www.vortex42studios.com/source/img/BG04_1080P.JPG);
}
80.001% {
opacity: 0;
background-image: url(https://www.vortex42studios.com/source/img/BG05_1080P.JPG);
}  
100% {
opacity: 1;
background-image: url(https://www.vortex42studios.com/source/img/BG05_1080P.JPG);
}
}
@keyframes fadeout {
0% {
opacity: 1;
background-image: url(https://www.vortex42studios.com/source/img/BG05_1080P.JPG);
}
20% {
opacity: 0;
background-image: url(https://www.vortex42studios.com/source/img/BG05_1080P.JPG);
}
20.001% {
opacity: 1;
background-image: url(https://www.vortex42studios.com/source/img/BG01_1080P.JPG);
}
40% {
opacity: 0;
background-image: url(https://www.vortex42studios.com/source/img/BG01_1080P.JPG);
}
40.001% {
opacity: 1;
background-image: url(https://www.vortex42studios.com/source/img/BG02_1080P.JPG);
}
60% {
opacity: 0;
background-image: url(https://www.vortex42studios.com/source/img/BG02_1080P.JPG);
}
60.001% {
opacity: 1;
background-image: url(https://www.vortex42studios.com/source/img/BG03_1080P.JPG);
}
80% {
opacity: 0;
background-image: url(https://www.vortex42studios.com/source/img/BG03_1080P.JPG);
}
80.001% {
opacity: 1;
background-image: url(https://www.vortex42studios.com/source/img/BG04_1080P.JPG);
}  
100% {
opacity: 0;
background-image: url(https://www.vortex42studios.com/source/img/BG04_1080P.JPG);
}
}
.wrap {
height: auto;
width: 100%;;
}
<div class="wrap">some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br></div>

迭代 3 :

A Haworth 的出色解决方案(上面的迭代 2)之后,在 body 标签上使用"之前"和"之后"伪图层以确保背景图像始终可见,即使页面内容超过视口长度,这里进一步改进,大大减少了 GPU 资源占用。

在 A Hawthorn 的例子中,他让图像 #2 淡入,同时图像 #1 淡出。这确实会消耗大量资源。但是,它看起来也不那么令人愉悦,因为随着两个图像同时褪色,背景颜色会显示出来。

相反,在此版本中,较低的"之前"层仅以完全不透明的方式显示图像的幻灯片。而且,淡入动画只发生在上层的"之后"层。"之前"图层的动画延迟为 5 秒,以便先前淡入的图像位于下一个淡入的图像下方。

它看起来非常令人愉悦,并且资源密集度要低得多。

* {
margin: 0;
padding: 0;
}
body {
height: auto;
min-height: 100vh;
width: auto;
overflow: visible;
position: relative;
background-color: #000000;
}
body::before, body::after {
display: inline-block;
top: 0;
left: 0;
position: relative;
position: absolute;
content: '';
width: 100%;
height: 100%;
min-height: 100vh;
z-index: -1;
overflow: visible;
background-size: cover;
background-position: center center;
}
/*ANIMATIONS - LOWER : HOLDS DELAYED 5 SECONDS*/
body::before {
animation: lowerHold 25s ease-in 5s infinite none;
}       
@keyframes lowerHold {
0%, 100%        { opacity : 1;  }
0%, 20%         { background-image: url(https://www.vortex42studios.com/source/img/BG01_1080P.JPG); }
20.001%, 40%    { background-image: url(https://www.vortex42studios.com/source/img/BG02_1080P.JPG); }
40.001%, 60%    { background-image: url(https://www.vortex42studios.com/source/img/BG03_1080P.JPG); }
60.001%, 80%    { background-image: url(https://www.vortex42studios.com/source/img/BG04_1080P.JPG); }
80.001%, 100%   { background-image: url(https://www.vortex42studios.com/source/img/BG05_1080P.JPG); }
}
/*ANIMATIONS - UPPER : FADES*/      
body::after {
animation: upperFadeIn 25s ease-in 0s infinite none;
}
@keyframes upperFadeIn {
/*FADE : IMAGE 01*/
0%, 20%     { background-image: url(https://www.vortex42studios.com/source/img/BG01_1080P.JPG); }
0%          { opacity: 0;   }
10%         { opacity: 1;   }
20%         { opacity: 1;   }
/*FADE : IMAGE 02*/
20.001%,40% { background-image: url(https://www.vortex42studios.com/source/img/BG02_1080P.JPG); }
20.001%     { opacity: 0;   }
30%         { opacity: 1;   }
40%         { opacity: 1;   }
/*FADE : IMAGE 03*/
40.001%,60% { background-image: url(https://www.vortex42studios.com/source/img/BG03_1080P.JPG); }
40.001%     { opacity: 0;   }
50%         { opacity: 1;   }
60%         { opacity: 1;   }
/*FADE : IMAGE 04*/
60.001%,80% { background-image: url(https://www.vortex42studios.com/source/img/BG04_1080P.JPG); }
60.001%     { opacity: 0;   }
70%         { opacity: 1;   }
80%         { opacity: 1;   }
/*FADE : IMAGE 05*/
80.001%,100%{ background-image: url(https://www.vortex42studios.com/source/img/BG05_1080P.JPG); }
80.001%     { opacity: 0;   }
90%         { opacity: 1;   }
100%        { opacity: 1;   }
}
.wrap {
height: auto;
width: 100%;
color: #FFFFFF;
}
<div class="wrap">some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br></div>

迭代 4 :

这是完成此小项目的最后一次迭代。

这一次,我使用 PHP 来填充 CSS,以便从指定目录的内容动态构建背景图像和动画。

这个"最终"迭代包括前一个迭代的所有好处,包括A Haworth 在正文标签上出色地使用了"之前"和"之后"伪词,即使页面内容超过查看端口的高度,也能将背景图像动画正确缩放到页面。而且,它还包括我在上一次迭代中提出的相同资源节省方法。

不幸的是,由于 StackOverflow 不允许在代码片段中使用 PHP,因此您无法在此处运行它以查看其工作情况。但是,我包含下面的代码,并将在这里解释它在做什么......

CSS 中的 PHP 代码在指定的目录$imgDir中搜索指定格式的图像文件,jpeg|jpg|png|gif,无论文件扩展名是大写还是小写,并构建一个$images其文件名的数组。然后,它使用shuffle($images)以便每次加载页面时,图像都以不同的顺序显示。

根据数组$imgNum = count($images)中的文件名数量和每个图像应显示的时间量(在变量$imgDur中设置为5秒),PHP 然后确定动画$aniDur = $imgNum * $imgDur的总持续时间。然后,计算每个图像将占用总动画$aniSeg的百分比段(即10%)(即100%),并使用number_format()给出$aniSeg两个小数位(即10.00百分比 - 这对于以后准确的关键帧计时很重要)。

我们现在从较低的"之前"层幻灯片动画开始,如下所示...

动画lowerHold使用$aniDur表示animation-duration属性,$imgDur表示$animation-delay属性。此幻灯片动画延迟 5 秒,以便当前图像在此下层上保持可见,而下一个图像在上层"后"动画中淡入。

接下来,设置lowerHold动画的关键帧。

首先,将不透明度设置为1,在整个动画中,使用0.001%, 100% { opacity : 1; }。"position"的新变量$pos设置为0 - $aniSeg,然后使用number_format()给出两个小数位。然后,可以使用$pos变量以百分比形式设置关键帧时序(此处将其设置为负数,以允许在数组的下一个循环中进行干净的增量)。

然后,使用for(){ ... }循环,基于增量变量$i(最初设置为0)与告诉数组中有多少文件名的$imgNum变量进行比较。

for 循环首先通过向其添加$aniSeg来递增$pos。然后,for 循环继续执行单个echo命令,该命令使用$pos . "1%"作为起点百分比计时(此处的"1"是起点上精确关键帧计时所需的串联第 3 位小数,以及所需的百分号),$pos + $aniSeg . "%"用于终点百分比计时,$imgDir . $images[$i]对于当前图像的位置(即/images/image001.jpg)。使用这些变量,for 循环会构建关键帧动画命令列表;在此特定示例中,images数组中的每个图像对应一个。

然后,我们对上层"后"层淡入动画执行类似的过程,如下所示...

动画upperFadeIn使用$aniDur表示animation-duration

属性,使用$imgDur - $imgDur表示$animation-delay属性。从自身中减去$imgDur会导致0,这意味着此动画会立即播放(与前一个动画延迟 5 秒不同),因此每个图像都淡入当前显示在下层"之前"幻灯片动画上的前一个图像之上。

接下来,设置upperFadeIn动画的关键帧。

之前用于"位置"的$pos变量被重置回0 - $aniSeg,并使用number_format()给出两个小数位,以准备以百分比设置关键帧时序(再次 - 它在这里设置为负数,以允许在数组的下一个循环中干净地递增)。

然后,使用for(){ ... }循环,基于增量变量$i(最初设置为0)与告诉数组中有多少文件名的$imgNum变量进行比较。

for 循环首先通过向其添加$aniSeg来递增$pos。然后,for 循环继续执行五个echo命令,这些命令使用涉及变量$pos$aniSeg的大量计算来获取动画中各个步骤的起点和终点、百分比计时(如上一个 for 循环,起点与1%连接,这是起点上精确关键帧计时所需的第 3 位小数, 和所需的百分号 - 端点只需用%连接)...

  1. 第一个echo只是一个注释掉的标签,描述什么是 发生。
  2. 第二个echo使用 定位器变量$imgDir . $images[$i]如 上一个动画。
  3. 第 3echo设置起点关键帧 对于不透明度0.
  4. 第 4echo设置 不透明度到1.
  5. 第 5echo设置 的终点关键帧 不透明度也1.

for 循环对images数组中的每个图像重复这一系列关键帧动画命令。

请注意,有一个包含n和一些空格的变量$new,它们在 for 循环中的整个命令中使用,只是为了整理代码。

而且,这就是很多。

因此,使用此代码,您可以设置这三个变量...

  1. $imgDur设置为显示每个图像的秒数(即5)。
  2. $imgDir设置为包含背景图像的目录(即/images/)。
  3. $imgExt设置为要拖网的文件类型(即jpeg|jpg|png|gif)。

。然后,代码将自动构建在指定目录中找到的图像的文件名数组$imgDir,随机播放它们,并根据您希望图像显示$imgDur的时间设置整体动画持续时间,并动态构建两个动画的所有单独关键帧计时, 并显示背景动画,所有这些都基于目录中找到的图像文件。

通过这种方式,您可以根据需要将任意数量的图像文件添加到该目录中,删除一些,替换一些,交换它们,或者任何您喜欢的内容,无论文件名是什么,结果都会在您的网站上自动更新,所有这些都无需再次触摸代码。

您甚至可以在网站上设置更改$imgDir值的按钮,以便每个按钮从不同的目录加载背景图像。一切都非常方便。

这是代码!享受!

CSS在整个过程中带有PHP元素要将其集成到您的网站中,请将其粘贴在.php文件<head><style></style>标签中,或者将其作为扩展名为.php的单独CSS文件包含在内。

* {
margin: 0;
padding: 0;
}
body {
height: auto;
min-height: 100vh;
width: auto;
overflow: visible;
position: relative;
background-color: #000000;
}
body::before, body::after {
display: inline-block;
top: 0;
left: 0;
position: relative;
position: absolute;
content: '';
width: 100%;
height: 100%;
min-height: 100vh;
z-index: -1;
overflow: visible;
background-size: cover;
background-position: center center;
}
<?php       
//REQUIRED VARS
$imgDur = 5;                                //SET DISPLAY TIME FOR EACH IMAGE IN SECONDS
$imgDir = "/source/img/";                   //SET DIRECTORY TO TRAWL FOR IMAGES
$imgExt = "jpeg|jpg|png|gif";               //SET THE IMAGE EXTENSIONS YOU ARE TRAWLING FOR
$imgPth = getcwd() . $imgDir;               //PATH TO IMAGE DIRECTORY (NOT INCLUDING $webUrl !!!)
//CREATE ARRAY OF ALL IMAGES IN DIRECTORY THEN SHUFFLE ORDER
$images = preg_grep("~.(" . $imgExt . ")$~i", array_values(preg_grep("/^([^.])/", scandir($imgPth))));
shuffle($images);
//FURTHER REQUIRED VARS
$imgNum = count($images);                                   //NUMBER OF IMAGES IN ARRAY
$aniDur = $imgNum * $imgDur;                                //TOTAL ANIMATION DURATION IN SECONDS 
$aniSeg = number_format((float)100 / $imgNum, 2, '.', '');  //PERCENTAGE OF ANIMATION PER IMAGE
$new = "n          "; //NEW LINE + WHITESPACE FOR USE CLEANING UP FOR LOOPS
?>
/*ANIMATIONS - LOWER : HOLDS DELAYED 5 SECONDS*/
body::before {
animation: lowerHold <?php echo $aniDur . "s" ?> ease-in <?php echo $imgDur . "s" ?> infinite none;
}
@keyframes lowerHold {
0.001%, 100% { opacity : 1; } 
<?php
$pos = 0 - $aniSeg;
$i = 0;
for ($i = 0; $i < $imgNum; $i++) {
$pos += $aniSeg;
$pos = number_format((float)$pos, 2, '.', '');
echo $new . $pos . "1%, " . ($pos+$aniSeg) . "% { background-image: url(" . $imgDir . $images[$i] . ");}";
}
?>
}
/*ANIMATIONS - UPPER : FADES*/      
body::after {
animation: upperFadeIn <?php echo $aniDur . "s" ?> ease-in <?php echo $imgDur - $imgDur . "s" ?> infinite none;
}
@keyframes upperFadeIn {
<?php
$pos = 0 - $aniSeg;
$i = 0;
for ($i = 0; $i < $imgNum; $i++) {
$pos += $aniSeg;
$pos = number_format((float)$pos, 2, '.', '');
echo $new . "/*FADE : IMAGE " . ($i + 1) . "*/";
echo $new . $pos . "1%, " . ($pos + $aniSeg) . "% { background-image: url(" . $imgDir . $images[$i] . ");}";
echo $new . $pos . "1% { opacity: 0; }";
echo $new . ($pos + ($aniSeg / 2)) . "% { opacity: 1; }";
echo $new . ($pos + $aniSeg) . "% { opacity: 1; }";
}
?>
}
.wrap {
height: auto;
width: 100%;
color: #FFFFFF;
}

.HTML

<div class="wrap">some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br>some stuff<br></div>

最新更新