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%宽度, 样式分别如下:


 

 

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


 

 


 

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

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

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


 

七个元素平均分布, 占据了父元素的全部横向空间. 其中中间的元素应用了 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;
            }
        }
初始化完成后效果图如下:


 

此时每个卡片的 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闪亮登场的时候了!~

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;
                }
            });
        }
再给按钮或者键盘增加事件监听, 这样就完成啦!

总结一下:

flex-box 可以让你的元素变得 flex , 轻松实现根据元素数目重载! 各种属性让你任意操作 flex 元素!

transform 实现漂亮的3D变换效果!

-webkit-box-reflect 实现更加酷炫的倒影效果!

最后JS来补刀, 让我们的卡片们动起来!

时间: 2024-09-29 01:55:21

CSS+JS实现苹果cover flow效果示例的相关文章

JS简单实现浮动窗口效果示例_javascript技巧

本文实例讲述了JS简单实现浮动窗口效果.分享给大家供大家参考,具体如下: HTML部分: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> &l

用CSS+JS实现的进度条效果效果_javascript技巧

进度条,就是在用户进入你的网站的时候,能让用户看到网页下载了多少,这个的作用非常明显---就是让用户的等待时间变长,可以有效的弥补空间慢的缺点(当然,你空间太慢,还是建议你换下空间,呵呵) 好了,现在我先来举两个例子 一个是用FLASH实现的 (这个网上很多网站都是,不说了) 一个是用动态的GIF实现的 (这个你可以看微软官方的下载页面,也不说了) 这里,我们的重点是用 CSS+JS 实现这个效果 好了,废话不多说,我们开始 首先,写一段HTML代码 <div id="loading&qu

JS实现图片翻书效果示例代码_javascript技巧

picture.html 复制代码 代码如下: <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>JS实现图片翻书效果</title> <META http-equiv=imag

js实现一个轮播效果示例

轮播这种组件是大部分网站都会存在的了,绝大部分都是 js 来实现逻辑控制的,它的原理就不多阐述了,因为我们现在要做的是不用 js 来实现一个轮播组件! 前提是只兼容现代浏览器. 原理 这里我们主要用的原理: CSS3 element+element 选择器(相邻兄弟选择器),element+element 选择器用于选取第一个指定的元素之后(不是内部)紧跟的元素. CSS3 element1~element2 选择器,element1~element2 选择 element1 之后出现的所有 e

不使用jquery实现js打字效果示例分享

 js打字效果示例js打字效果示例,data-period设置从打字返回删字的时间,data-rotate可加减中英文词语,不用jquery支持       代码如下: <h1>Libraries give you  <span class="txt-rotate fw700" data-period=500" data-rotate='[ "knowledge", "community", "an outl

注释-css +js 实现轮播效果?、

问题描述 css +js 实现轮播效果?. 利用计时器 css 等实现 简单的照片轮播效果,求大神 指点指点 再讲讲 如何实现 加点注释 谢谢 我是 菜鸟 解决方案 js实现图片轮播效果CSS+JS实现的静态页面翻页效果图片轮播JS效果 解决方案二: 无非就是设置scrollLeft,scrollTop,opacity等实现移动和透明转换效果之类的jquery焦点图模仿淘宝,拍拍图片效果 解决方案三: 通过定时器更换指定图片的显示或隐藏即可. 解决方案四: 你可以写一个定时器,将图片进行定时的显

JS+CSS实现仿支付宝菜单选中效果代码_javascript技巧

本文实例讲述了JS+CSS实现仿支付宝菜单选中效果代码.分享给大家供大家参考.具体如下: 这是一个漂亮的JS+CSS仿支付宝菜单,总体风格和形式与支付宝的菜单没什么两样,细心会发现这是一个CSS爱好者自己手功完成的,自己美化图片,重写CSS代码,为作者给我们奉献这么好的菜单而表示感谢. 运行效果截图如下: 在线演示地址如下: http://demo.jb51.net/js/2015/js-css-f-alipay-style-menu-codes/ 具体代码如下: <!DOCTYPE html

JS+CSS实现滑动切换tab菜单效果_javascript技巧

本文实例讲述了JS+CSS实现滑动切换tab菜单效果.分享给大家供大家参考.具体如下: 这是风格简单的一款JS+CSS滑动门特效代码,当鼠标滑过菜单的时候,二级菜单自动切换,鼠标不需要点击,滑动门效果是个比较流行的网页菜单效果,在网上经常可看到这种菜单的身影.本菜单在火狐.IE8.Chrome下测试通过,代码兼容性还可以,自己用的化再美化一下风格. 运行效果截图如下: 在线演示地址如下: http://demo.jb51.net/js/2015/js-css-move-cha-tab-menu-

JS+DIV+CSS实现仿表单下拉列表效果_javascript技巧

本文实例讲述了JS+DIV+CSS实现仿表单下拉列表效果.分享给大家供大家参考.具体如下: JS+DIV+CSS实现仿表单下拉列表效果,是完全用CSS技术再配合JS实现的效果,用来代替传统的Select下拉框,虽然目前来说,此代码还有些粗糙,但对于美化列表的样式来说,可能以后会更方便,要比Select方便的多. 运行效果截图如下: 在线演示地址如下: http://demo.jb51.net/js/2015/js-div-css-fselect-codes/ 具体代码如下: <!DOCTYPE