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

Responsive Background Image (animated fade loop) that will span full height of page content?

迭代 1 :

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

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

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

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

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

这样无论有滚动条还是没有滚动条都看起来不错?最好是响应式的,就像现在一样,您可以在其中调整 window 的大小,并且背景图像会相应地动态调整。如果可能的话,我非常希望将其保留为仅 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 占据其 parent 的高度(当该元素的高度为自动时)工作。

因此,转向将图像作为背景放在 body 本身上,使用伪前元素使图像淡入和之后淡出它有效。 Body 高度设置为自动,但 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 :

跟进 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 在 body 标签上巧妙地使用“before”和“after”伪造,以即使页面内容超过查看端口的高度,也可以将背景图像动画正确缩放到页面。而且,它还包括我在上一次迭代中整合的相同资源节省方法。

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

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

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

我们现在开始制作下层的“before”层幻灯片动画,如下...

动画 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”是起始点精确关键帧计时所需的连续第三位小数,以及需要百分号),$pos + $aniSeg . "%" 用于结束点百分比计时,$imgDir . $images[$i] 用于当前图像的位置(即 /images/image001.jpg)。 for 循环使用这些变量构建关键帧动画命令列表;在此特定示例中,images 数组中的每个图像对应一个。

我们再对上面的“after”层淡入动画做类似的处理,如下...

动画 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% 连接,这是起点上精确关键帧计时所需的小数点后第三位,以及所需的百分号 - 结束点简单地连接在一起%)...

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

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

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

而且,这就是很多。

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

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

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

这样,您可以向该目录添加任意数量的图像文件,删除一些,替换一些,交换它们,或者任何您喜欢的,无论文件名是什么,结果会自动更新在您的网站上,无需再次触摸代码。

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

这是代码!享受吧!

CSS 包含 PHP 个元素: 要将其集成到您的网站中,要么将其粘贴到 .php 文件的 <head> 中的 <style></style> 标记中,要么将其作为单独的 CSS 文件包含扩展名为 .php.

* {
    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>