如何使用CSS+JS帮你实现苹果cover flow效果

发布时间:2021-11-12 10:48:48 作者:小新
来源:亿速云 阅读:143

小编给大家分享一下如何使用CSS+JS帮你实现苹果cover flow效果,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!

<!DOCTYPE html> <html lang="en"> <head>     <meta charset="UTF-8">     <title>coverflow-demo</title>     <style>         div.innerWrapper{             perspective: 300px;             width: 600px;             height: 300px;             margin: 100px auto;             display: flex;              align-items:flex-start;             background-color: #000;              overflow: hidden;              padding-top: 5%;         }         div.cover{             height: 50%;              flex-grow:1;             transition: all .5s ease;             background-size: 100% 100%;              background-repeat:no-repeat;             margin: 0;              -webkit-box-reflect:below 5% linear-gradient(transparent, white);             border: 1px solid #fff;          }         div.cover:nth-child(1){             background-image: url('covers/computergraphics-album-covers-2014-15.jpg');         }         div.cover:nth-child(2){             background-image: url('covers/Funkadelic-Maggot-Brain-album-covers-billboard-1000x1000.jpg');         }         div.cover:nth-child(3){             background-image: url('covers/Green-Day-American-Idiot-album-covers-billboard-1000x1000.jpg');         }         div.cover:nth-child(4){             background-image: url('covers/insurgency-digital-album-cover-design.jpg');         }         div.cover:nth-child(5){             background-image: url('covers/Pink-Floyd-Dark-Side-of-the-Moon-album-covers-billboard-1000x1000.jpg');         }         div.cover:nth-child(6){             background-image: url('covers/sonic-quiver-time-and-space1-1000x1000.jpg');         }         div.cover:nth-child(7){             background-image: url('covers/tumblr_inline_nydppi1Mp91t7tdyh_500.jpg');         }         button[required='required']{             background-color: #000;          }     </style> </head> <body>     <div class='container'>         <div class="innerWrapper">             <div></div>             <div></div>             <div></div>             <div></div>             <div></div>             <div></div>             <div></div>         </div>     </div>     <button required='required'>222</button>     <script>     ;(function(parent){         var cards = parent.querySelectorAll('div'), coverCount = cards.length, middleIndex = (coverCount-1)/2, middleCover = cards[middleIndex], parentWidth = middleCover.parentNode.clientWidth, currentIndex = middleIndex;          var maxRotate = 42, stepper = maxRotate/middleIndex, maxZIndex = middleIndex + 1;          var rotateReg = /rotateY\((\-?\d{1,3}\.?\d*)deg\)/, translateReg = /translateX\((\-?\d{1,3}\.?\d*)px\)/;          // debugger;          for(var i = 0; i<coverCount; i++){             var elem = cards[i];              elem.classList.add('cover');              elem.style.transform = 'translateX(0px) rotateY(' + (maxRotate-(i*stepper).toFixed(0)) + 'deg)';              elem.style.flexGrow = 1;              if(i<middleIndex){                 elem.style.zIndex = i+1;              }else if(i == middleIndex){                 elem.style.zIndex = i+1;                  elem.style.flexGrow = 2;              }else{                 elem.style.zIndex = coverCount - i;              }         }         function move(direction){             if(currentIndex==(direction=='right'?0:coverCount-1))return;              direction=='right'?currentIndex--:currentIndex++;              maxZIndex++;              [].forEach.call(cards, function(element, index) {                 var previousRotate = parseInt(element.style.transform.match(rotateReg)[1]);                  var previousTranslate = parseInt(element.style.transform.match(translateReg)[1]);                 // translateX + 80 px one right button is clicked                 var currentRotate, currentTranslate;                  if(direction=='right'){                     currentRotate = previousRotate-stepper;                      currentTranslate = previousTranslate+(parentWidth/(coverCount+1));                  }else{                     currentRotate = previousRotate+stepper;                      currentTranslate = previousTranslate-(parentWidth/(coverCount+1));                  }                 element.style.transform = 'translateX(' + currentTranslate + 'px) rotateY('+ currentRotate +'deg)'                 // element.style.zIndex =                  if(index == currentIndex){                     element.style.flexGrow = 2;                      element.style.zIndex = maxZIndex;                   }else{                     element.style.flexGrow = 1;                  }             });         }         document.addEventListener('keyup', function(e){             if(e.which == 37){                 move('right');              }else if(e.which == 39){                 move('left');              }         })     })(document.querySelector('.innerWrapper'));      </script> </body> </html>

稍微解释下这里用到的几个知识点:

1. flex-box.

什么是flex-box捏, 它是为了适应当前设备屏幕大小不一而提出的一种display方法. 当一个父元素的显示被设定为display:flex时,  它内部的子元素们会被平均分配占满父元素的空间, 并且当父元素的尺寸变化时, 子元素的尺寸也会相应变化! 是不是很神奇呢? 不仅如此,  你还可以任意分配子元素们的排列顺序, 如果觉得某个子元素需要突出显示, 就可以给这个子元素以特殊身份, 让它相比其他子元素大一些, 或者小一些!  由于其的自适应特性, flex是移动开发的一把利器, 我们先来看看一个小应用:

设计一个对话框函数, 当传入一个回调函数时, 只显示一个'确定'按钮, 占100%宽度; 当传入两个回调函数(确定和取消)时,  分别显示'确定'和'取消'按钮, 各占50%宽度, 样式分别如下:

如何使用CSS+JS帮你实现苹果cover flow效果

如何使用CSS+JS帮你实现苹果cover flow效果

怎么实现呢? 我们当然可以用JS来做, 但是(凡事就怕一个但是哈哈)! 我们作为有追求的前端, 战斗在CSS探索的***线,  现在有了如此好用的flex属性, 为毛不立马用起来呢? 说走咱就走, 按钮容器和按钮本身的CSS如下:

如何使用CSS+JS帮你实现苹果cover flow效果

如何使用CSS+JS帮你实现苹果cover flow效果


关键是按钮的width:100%属性. 有了它, 当容器里只有一个按钮时, 它的宽度会拓展为容器的100%宽度; 而当容器里有两个按钮时,  按钮的宽度都为100%, 怎么办呢? 由于两个按钮势均力敌, 它们只好平分秋色, 各占50%的空间了!

有的同学要问了: 要是我不想按钮把空间占满怎么办呢? 这时候, 可以设定按钮的宽度各为45%,  然后在父元素上设置justify-content:center, 意思是两个子元素只占了90%的横向空间, 那怎么分配剩下的10%空间呢?  那就两边各分配5%吧! 除此之外, 该属性的其它值, 可以让子元素左右对齐, 更多flexbox的神奇应用, 请参考这篇文章~

A Complete Guide to Flexbox

回到我们的例子. 在卡片们没有被应用transform属性之前, 它们看起来是这个样子的:

如何使用CSS+JS帮你实现苹果cover flow效果

七个元素平均分布, 占据了父元素的全部横向空间. 其中中间的元素应用了flex-grow:2的属性, 使得它比其他元素高人一等,  面积是其他元素的两倍~~

2. transform

其实有了上一幅图, 初始页面的雏形就已经差不多了~现在只需要给父元素设置视角(关于视角, 3D变换等内容, 请见我的这一篇文章).  为了得到比较明显3D效果, 设置了父元素的perspective为较小的值300px, 就相当于从距离3D变换平面300px的距离看.  perspective的值越大, 相当于从越远的距离看, 3D效果越不明显, 平面化效果越强烈~

设置好了视角, 接下来该给元素们设置3D效果了. ***步很简单: 假设有7个元素, 沿Y轴***旋转角度为42度, 则0,1,2号元素分别旋转42, 28,  14度, 3号元素旋转0度同时变大2倍,4,5,6号元素分别旋转-14, -28, -42度. 用一个简单的for循环就可以完成这项任务, 代码如下:

for(var i = 0; i<coverCount; i++){             var elem = cards[i];              elem.classList.add('cover');              // 设置元素的translateX为0px, 旋转角度为***旋转角度-目录值*步进值             elem.style.transform = 'translateX(0px) rotateY(' + (maxRotate-(i*stepper).toFixed(0)) + 'deg)';              elem.style.flexGrow = 1;              // 设置元素的z-index以区分前后顺序, 并将中间元素设置大一些             if(i<middleIndex){                 elem.style.zIndex = i+1;              }else if(i == middleIndex){                 elem.style.zIndex = i+1;                  elem.style.flexGrow = 2;              }else{                 elem.style.zIndex = coverCount - i;              }         }

初始化完成后效果图如下:

如何使用CSS+JS帮你实现苹果cover flow效果 

此时每个卡片的translateX为0, 这个值要预先写好, 才能通过改变该值来实现卡片的左右移动效果; rotateY的值分别为42, 28, 14,  0, -14, -28, 42度; flex-grow(相对于其它子元素的大小)分别为1, 1, 1, 2, 1, 1, 1

3.-webkit-box-reflect

那么漂亮的倒影是怎么实现的呢? 哈哈其实一行CSS就能搞定, 那就是强大的-webkit-box-reflect, 值为below 5%  linear-gradient(transparent, white). 相信聪明的小伙伴看到这里已经明白了大概了, 为了避免误解,  稍稍再解释一下~below是倒影在盒子下方, 5%表示offset, 和盒子的距离是盒子宽度的5%, linear-gradient(transparent,  white)指的是倒影的颜色, 从透明到完全不透明. 渐变语法的颜色在这里起作用的只有透明度, 白色的颜色是不会显出来的~到这里, 我们用的大部分都是CSS,  效果图如下:

如何使用CSS+JS帮你实现苹果cover flow效果

然而静态的展示是不够的, 我们的目标是! 要让它动起来! 来回左右动! 到这里CSS已经无能为力, 改JS闪亮登场的时候了!~

4.JS控制

控制左右移动的函数如下, 接受一个参数left或者right表示要移动的方向~

// 定义提取旋转角度和translateX值的正则, 例如 -> $0.style.transform.match(/rotateY\((\-?\d{1,3}\.?\d*)deg\)/) <- ["rotateY(14deg)", "14"]        var rotateReg = /rotateY\((\-?\d{1,3}\.?\d*)deg\)/, translateReg = /translateX\((\-?\d{1,3}\.?\d*)px\)/;         function move(direction){            // 当前值为0或者当前值为卡片数目时, 返回            if(currentIndex==(direction=='right'?0:coverCount-1))return;             // 当前值自增或者自减            direction=='right'?currentIndex--:currentIndex++;             // ***Z-index自增            maxZIndex++;             [].forEach.call(cards, function(element, index) {                // 提取变换之前的旋转角度                var previousRotate = parseInt(element.style.transform.match(rotateReg)[1]);                 // 提取变换之前的translateX                var previousTranslate = parseInt(element.style.transform.match(translateReg)[1]);                var currentRotate, currentTranslate;                 if(direction=='right'){                    // 计算rotatey的值                    currentRotate = previousRotate-stepper;                     // 计算平移的距离                    currentTranslate = previousTranslate+(parentWidth/(coverCount+1));                 }else{                    currentRotate = previousRotate+stepper;                     currentTranslate = previousTranslate-(parentWidth/(coverCount+1));                 }                // 写入元素属性                element.style.transform = 'translateX(' + currentTranslate + 'px) rotateY('+ currentRotate +'deg)'                // element.style.zIndex =                 if(index == currentIndex){                    element.style.flexGrow = 2;                     // 不断写入maxZIndex, 确保翻过的元素始终在最前面                    element.style.zIndex = maxZIndex;                  }else{                    element.style.flexGrow = 1;                 }            });        }

再给按钮或者键盘增加事件监听, 这样就完成啦!

看完了这篇文章,相信你对“如何使用CSS+JS帮你实现苹果cover flow效果”有了一定的了解,如果想了解更多相关知识,欢迎关注亿速云行业资讯频道,感谢各位的阅读!

推荐阅读:
  1. 帮你培养类型思维TypeScript(一)
  2. React DND如何实现的卡片排序功能

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

javascript css

上一篇:怎么使用html2canvas将HTML内容写入Canvas生成图片

下一篇:Django中的unittest应用是什么

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》