最近看到 B 站首页有一个有趣的效果,即鼠标滑动实现模糊:
我一直很好奇这玩意如何实现,和🐍友讨论了一下,害以为是用webgl弄的,直到今天看了下阿B的网页源码才发现。。。。
首先定位到这个div,我们发现它的class叫做 animated-banner
其下有6个子div,展开这些子div,可以发现是背景的图片:
这 6 张图片分别是:
那么他们按照顺序叠加,就可以组成一张完整的首页图片了。
我们从bilibili的网页源码中提取了他们的部分代码,下面的 html 代码演示了这一叠加的结果:
<!DOCTYPE html> <html> <head> <title></title> </head> <body> <div class="animated-banner"> <div class="layer"> <img src="https://i0.hdslb.com/bfs/vc/8e084d67aa18ed9c42dce043e06e16b79cbb50ef.png" data-height="250" data-width="3000" height="250" width="3000"> </div> <div class="layer"> <img src="https://i0.hdslb.com/bfs/vc/082e39ef757826401ef82da818310d42e05bc2de.png" data-height="275" data-width="3000" height="165" width="1800"> </div> <div class="layer"> <img src="https://i0.hdslb.com/bfs/vc/dbd5c17c4315714de9e4ee119694d2e9efaf9639.png" data-height="250" data-width="3000" height="250" width="3000"> </div> <div class="layer"> <img src="https://i0.hdslb.com/bfs/vc/cd9be0a2716adbae85fd899259381c4b2c2893c7.png" data-height="250" data-width="3000" height="150" width="1800"> </div> <div class="layer"> <img src="https://i0.hdslb.com/bfs/vc/88537437a7916ecde847fa46652b44fbd3cbbb06.png" data-height="275" data-width="3000" height="165" width="1800"> </div> <div class="layer"> <img src="https://i0.hdslb.com/bfs/vc/37d9a93baa55870506a6f3e6308e7a0c386b97c7.png" data-height="275" data-width="3000" height="178" width="1950"> </div> </div> </body> </html> <style> .animated-banner{position:absolute;top:0;bottom:0;left:0;right:0;overflow:hidden} .layer{position:absolute;left:0;top:0;height:100%;width:100%;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;} </style>注:如何提取外链css?在浏览器的开发者模式下选择network模式,然后一一检查请求到的css文件即可:
但是它是如何实现鼠标滑动模糊的呢?这里我尝试在浏览器开发者模式下,鼠标进行滑动,结果出乎我的意料!
如图所示,它是通过根据鼠标位置,动态地修改 css 的 blur 和 transform 属性来将图像做不同程度的模糊的:
注意右边蓝色高亮的标记,每当鼠标滑动的时候,css属性就会发生更新。那么现在就好办了,我们只要根据鼠标的位置,调整每个图层的位置和模糊程度和移动参数即可。
我们编写如下的 JavaScript 代码,并且插入上文提到的那段代码中,即可:
<script> // 限幅 function clamp(x, min, max) { if(x<min) return min; if(x>max) return max; return x; } // 鼠标移动回调 document.onmousemove = function(event) { var x = event.pageX; var y = event.pageY; // 设置不同图层img标签的模糊与移动 var imgs = document.getElementsByTagName("img"); imgs[1].setAttribute("style", "filter: blur(" + clamp(x/75 - 7, 0, 7) + "px); transform: translate(" + x/50 + "px, 0px) rotate(0deg);"); imgs[2].setAttribute("style", "filter: blur(" + clamp(x/125 - 5, 0, 5) + "px); transform: translate(" + x/40 + "px, 0px) rotate(0deg);"); imgs[3].setAttribute("style", "filter: blur(" + clamp(x/250 - 3, 0, 3) + "px); transform: translate(" + x/30 + "px, 0px) rotate(0deg);"); imgs[4].setAttribute("style", "filter: blur(" + clamp(3 - x/250, 0, 3) + "px); transform: translate(" + x/20 + "px, 0px) rotate(0deg);"); imgs[5].setAttribute("style", "filter: blur(" + clamp(3 - x/250, 0, 3) + "px); transform: translate(" + x/10 + "px, 0px) rotate(0deg);"); } </script>再次运行刚刚的html代码:
完整代码:
<!DOCTYPE html> <html> <head> <title></title> </head> <body> <div class="animated-banner"> <div class="layer"> <img src="https://i0.hdslb.com/bfs/vc/8e084d67aa18ed9c42dce043e06e16b79cbb50ef.png" data-height="250" data-width="3000" height="250" width="3000"> </div> <div class="layer"> <img src="https://i0.hdslb.com/bfs/vc/082e39ef757826401ef82da818310d42e05bc2de.png" data-height="275" data-width="3000" height="165" width="1800"> </div> <div class="layer"> <img src="https://i0.hdslb.com/bfs/vc/dbd5c17c4315714de9e4ee119694d2e9efaf9639.png" data-height="250" data-width="3000" height="250" width="3000"> </div> <div class="layer"> <img src="https://i0.hdslb.com/bfs/vc/cd9be0a2716adbae85fd899259381c4b2c2893c7.png" data-height="250" data-width="3000" height="150" width="1800"> </div> <div class="layer"> <img src="https://i0.hdslb.com/bfs/vc/88537437a7916ecde847fa46652b44fbd3cbbb06.png" data-height="275" data-width="3000" height="165" width="1800"> </div> <div class="layer"> <img src="https://i0.hdslb.com/bfs/vc/37d9a93baa55870506a6f3e6308e7a0c386b97c7.png" data-height="275" data-width="3000" height="178" width="1950"> </div> </div> </body> </html> <style> .animated-banner{position:absolute;top:0;bottom:0;left:0;right:0;overflow:hidden} .layer{position:absolute;left:0;top:0;height:100%;width:100%;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;} </style> <script> function clamp(x, min, max) { if(x<min) return min; if(x>max) return max; return x; } document.onmousemove = function(event) { var x = event.pageX; var y = event.pageY; // 设置不同图层img标签的模糊与移动 var imgs = document.getElementsByTagName("img"); imgs[1].setAttribute("style", "filter: blur(" + clamp(x/75 - 7, 0, 7) + "px); transform: translate(" + x/50 + "px, 0px) rotate(0deg);"); imgs[2].setAttribute("style", "filter: blur(" + clamp(x/125 - 5, 0, 5) + "px); transform: translate(" + x/40 + "px, 0px) rotate(0deg);"); imgs[3].setAttribute("style", "filter: blur(" + clamp(x/250 - 3, 0, 3) + "px); transform: translate(" + x/30 + "px, 0px) rotate(0deg);"); imgs[4].setAttribute("style", "filter: blur(" + clamp(3 - x/250, 0, 3) + "px); transform: translate(" + x/20 + "px, 0px) rotate(0deg);"); imgs[5].setAttribute("style", "filter: blur(" + clamp(3 - x/250, 0, 3) + "px); transform: translate(" + x/10 + "px, 0px) rotate(0deg);"); } </script>