b站首页banner景深移动特效 bilibili秋

看到b站的animation-banner效果太妙了,就自己也想仿写一个.去查了查资料鼓捣出来一个.

首先是成品展示
在这里插入图片描述
大家可能觉得这个效果看起来很复杂,其实拆开来看比较简单.
他的效果就是实现了一个镜头聚焦,那么我们分步骤进行讲解

step1

首先,让图层跟随鼠标进行移动,大家应该已经想到怎么办了,但是有个问题,每个图层跟随鼠标移动的距离不能相同,这里可以用循环进行移动距离的迭代.

step2

其次是让图层跟随鼠标的移动距离进行清晰度的变化,和上述的办法类似,也是构造一个函数来计算清晰度,可以看到,随着鼠标的移动,最后和靠前的图层清晰度都变低(后面称之为失焦点),而靠中间的图层清晰度变高(后面称之为聚焦点).我们可以知道,这个偏移距离和焦点的转移是有关系的

在这里插入图片描述
实际上这个函数有很好的选择,就是我们小学二年级就 学过的的二次函数,两端的数值大,中间的数值小,符合我们的要求.
然后我们利用图层的index把六个图层按顺序排列在x轴上,得到的y值就符合我们的要求了

这就是最核心的思路啦,那么我们就开始

首先获得六个图层
这里我就直接用b站的图了,因为咱菜鸡画不出来

放出来方便大家练习,侵删在这里插入图片描述在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

<!-- 这就是我的html结构,很简单 -->
  <header>
    <div><img src="./img/bilibili-autumn-1.webp"></div>
    <div><img src="./img/bilibili-autumn-2.webp"></div>
    <div><img src="./img/bilibili-autumn-3.webp"></div>
    <div><img src="./img/bilibili-autumn-4.webp"></div>
    <div><img src="./img/bilibili-autumn-5.webp"></div>
    <div><img src="./img/bilibili-autumn-6.webp"></div>
  </header>
    body{
      margin: 0;//经典margin0
    }
    header{
      height: 155px;//给容器一个高度,防止高度坍塌
      position: relative;//开定位,六个图层需要以容器为坐标进行左右移动
      overflow: hidden;//因为图层需要移动,所以图层要略大于容器,容器要做溢出隐藏
    }
    header>div{
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      display: flex;//直接flex居中,太美了这东西
      justify-content: center;
      align-items: center;
      --offset: 0px;//这里定义css的变量方便后面js的处理
      --blur: 2px;
    }
    header>div>img{
      display: block;
      width: 110%;//放大点,移动的时候不会有空白溢出
      height: 100%;
      object-fit: cover;
      transform: translateX(var(--offset));//变量的使用
      filter: blur(var(--blur));
    }

接下来就是js代码,可能我写的比较繁琐,但是实现的效果我觉得和b站的很像

var startX = 0
const images = document.querySelectorAll('header>div>img')//拿到img元素的数组

document.querySelector('header').addEventListener('mouseover', (e)=>{
  startX = e.clientX//在鼠标移入的时候记录初始位置
  for (let [index, image] of images.entries()) {
    image.style.transition = 'none'//在每次鼠标进入的时候让每一项的渐变效果为none,防止鼠标移动时看起来不连贯
  }
})

document.querySelector('header').addEventListener('mousemove', (e)=>{
  let offsetX = e.clientX - startX + 482//这里是保证初始值为482
  if(Math.abs(offsetX - 482) < 10)offsetX = 482//鼠标刚刚移动上去会产生很小的偏移,看起来效果就好像图层突然变换了位置,所以做了一个移动最小值检测,这样就没有问题了
  let percentage = offsetX / window.outerWidth//计算移动距离占视窗宽度的百分比,其实我们的主要目的是拿到这个东西
  let offset = 15 * percentage//把百分比放大合适的比例就能带入公式了
  let blur = 20//这里是二次函数公式中二次项的系数,20是比较合适的
  for (let [index, image] of images.entries()) {
    offset *= 1.3//每次循环对偏移位置进行迭代
    let blurValue = (Math.pow(((index / images.length - percentage)), 2) * blur)//每次循环对清晰度进行迭代,这里就使用了刚刚提到的二次函数的形式
    image.style.setProperty('--offset',`${offset}px`)//赋值回去,实现效果
    image.style.setProperty('--blur',`${blurValue}px`)
  }
})

document.querySelector('header').addEventListener('mouseout', ()=>{
//其实这里完全就是偷了个懒,直接用程序去计算初始位置,我测出来当offset为482的时候,初始效果看起来是最棒的,就不用看了下面的就是上面的公式而已
  let offsetX = 482
  let blur = 20
  let percentage = offsetX / window.outerWidth
  let offset = 15 * percentage
  for (let [index, image] of images.entries()) {
    offset *= 1.3
    blurValue = (Math.pow((index / images.length - percentage), 2) * blur)
    image.style.setProperty('--offset',`${offset}px`)
    image.style.setProperty('--blur',`${blurValue}px`)
    image.style.transition = 'all .3s ease'//给每一项加上渐变效果,图层会平滑回到初始位置,视觉效果不会太突兀
  }
})
window.addEventListener('load', () => {
//这里就是在开始加载时计算初始位置.
  let offsetX = 482
  let blur = 20
  let percentage = offsetX / window.outerWidth
  let offset = 15 * percentage
  for (let [index, image] of images.entries()) {
    offset *= 1.3
    blurValue = (Math.pow((index / images.length - percentage), 2) * blur)
    image.style.setProperty('--offset',`${offset}px`)
    image.style.setProperty('--blur',`${blurValue}px`)
  }
})

其实上面完全没必要写那么冗长的代码,给每一项设置一个初始的偏移位置和初始清晰度就好了,这样代码也能简洁.大家可以自己想想怎么改,其实很简单.

参考了b站的
CodingStartup起码课

下面放出本人的完整代码

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    body{
      margin: 0;
    }
    header{
      height: 155px;
      position: relative;
      overflow: hidden;
    }
    header>div{
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      display: flex;
      justify-content: center;
      align-items: center;
      --offset: 0px;
      --blur: 2px;
    }
    header>div>img{
      display: block;
      width: 110%;
      height: 100%;
      object-fit: cover;
      transform: translateX(var(--offset));
      filter: blur(var(--blur));
    }
  </style>
</head>
<body>
  <header>
    <div><img src="./img/bilibili-autumn-1.webp"></div>
    <div><img src="./img/bilibili-autumn-2.webp"></div>
    <div><img src="./img/bilibili-autumn-3.webp"></div>
    <div><img src="./img/bilibili-autumn-4.webp"></div>
    <div><img src="./img/bilibili-autumn-5.webp"></div>
    <div><img src="./img/bilibili-autumn-6.webp"></div>
  </header>
  <script>
    var startX = 0
const images = document.querySelectorAll('header>div>img')

document.querySelector('header').addEventListener('mousemove', (e)=>{
  let offsetX = e.clientX - startX + 482
  let percentage = offsetX / window.outerWidth
  let offset = 15 * percentage
  let blur = 20
  for (let [index, image] of images.entries()) {
    offset *= 1.3
    let blurValue = (Math.pow(((index / images.length - percentage)), 2) * blur)
    image.style.setProperty('--offset',`${offset}px`)
    image.style.setProperty('--blur',`${blurValue}px`)
  }
})
document.querySelector('header').addEventListener('mouseover', (e)=>{
  startX = e.clientX
  for (let [index, image] of images.entries()) {
    image.style.transition = 'none'
  }
})

document.querySelector('header').addEventListener('mouseout', ()=>{
  let offsetX = 482
  let blur = 20
  let percentage = offsetX / window.outerWidth
  let offset = 15 * percentage
  for (let [index, image] of images.entries()) {
    offset *= 1.3
    blurValue = (Math.pow((index / images.length - percentage), 2) * blur)
    image.style.setProperty('--offset',`${offset}px`)
    image.style.setProperty('--blur',`${blurValue}px`)
    image.style.transition = 'all .3s ease'
  }
})
window.addEventListener('load', () => {
  let offsetX = 482
  let blur = 20
  let percentage = offsetX / window.outerWidth
  let offset = 15 * percentage
  for (let [index, image] of images.entries()) {
    offset *= 1.3
    blurValue = (Math.pow((index / images.length - percentage), 2) * blur)
    image.style.setProperty('--offset',`${offset}px`)
    image.style.setProperty('--blur',`${blurValue}px`)
  }
})
  </script>
</body>
</html>

thanks for reading