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来补刀, 让我们的卡片们动起来!
相关文章
- 今天小编在这里就来给Painter的这一款软件的使用者们来说一说绘制红衣喝酒男水粉画效果的教程,各位想知道具体绘制步骤的使用者,那么下面就快来跟着小编一起看一看教程...2016-09-14
- “一起,让我们将这个世界变得更好。”苹果首席执行官蒂姆 库克对着台下5000多名开发者说道,声音略有些沙哑和颤抖。...2016-07-04
- php语言实现redis的客户端与服务端有一些区别了因为前面介绍过服务端了这里我们来介绍客户端吧,希望文章对各位有帮助。 为了更好的了解redis协议,我们用php来实现...2016-11-25
- 今天小编在这里就来给photoshop的这一款软件的使用者们来说说利用各种素材合成闪电侠效果的制作教程,各位想知道具体制作步骤的使用者们,那么下面就快来跟着小编一起看...2016-09-14
- 有时我们在页面上需要选择数值范围,如购物时选取价格区间,购买主机时自主选取CPU,内存大小配置等,使用直观的滑块条直接选取想要的数值大小即可,无需手动输入数值,操作简单又方便。HTML首先载入jQuery库文件以及jRange相关...2015-03-15
- 本文实例讲述了JS实现的简洁纵向滑动菜单(滑动门)效果。分享给大家供大家参考,具体如下:这是一款纵向布局的CSS+JavaScript滑动门代码,相当简洁的手法来实现,如果对颜色不满意,你可以试着自己修改CSS代码,这个滑动门将每一...2015-10-21
- 腾讯科技讯,据外媒报道,苹果似乎在瑞士悄悄建了一个研究所,可能跟公司的自动驾驶汽车项目有关。...2017-07-06
- 今天小编在这里就来给美图秀秀的这一款软件的使用者们来说下把普通照片快速转换成卡通效果的教程,各位想知道具体制作步骤的使用者们,那么下面就快阿里跟着小编一起看一...2016-09-14
- 本文实例讲述了JS实现双击屏幕滚动效果代码。分享给大家供大家参考,具体如下:这里演示双击滚屏效果代码的实现方法,不知道有觉得有用处的没,现在网上还有很多还在用这个特效的呢,代码分享给大家吧。运行效果截图如下:在线演...2015-10-30
jQuery+slidereveal实现的面板滑动侧边展出效果
我们借助一款jQuery插件:slidereveal.js,可以使用它控制面板左右侧滑出与隐藏等效果,项目地址:https://github.com/nnattawat/slideReveal。如何使用首先在页面中加载jquery库文件和slidereveal.js插件。复制代码 代码如...2015-03-15- 今天小编在这里就来给photoshop的这一款软件的使用者们来说说调出时尚个性青色人像照片效果的调色教程,各位想知道到底该怎么调色的,那么下面就快来跟着小编一起看一看...2016-09-14
- 翻板抽奖的实现流程:前端页面提供6个方块,用数字1-6依次表示6个不同的方块,当抽奖者点击6个方块中的某一块时,方块翻转到背面,显示抽奖中奖信息。看似简单的一个操作过程,却包含着WEB技术的很多知识面,所以本文的读者应该熟...2015-10-21
SQLMAP结合Meterpreter实现注入渗透返回shell
sqlmap 是一个自动SQL 射入工具。它是可胜任执行一个广泛的数据库管理系统后端指印, 检索遥远的DBMS 数据库等,下面我们来看一个学习例子。 自己搭建一个PHP+MYSQ...2016-11-25- 复制代码 代码如下: // 第一种写法 $da = date("w"); if( $da == "1" ){ echo "今天是星期一"; }else if( $da == "2" ){ echo "今天是星期二"; }else if( $da == "3" ){ echo "今天是星期三"; }else if( $da == "4"...2013-10-04
- ps软件是现在很多人比较喜欢的,有着非常不错的使用效果,这次文章就给大家介绍下ps怎么制作图片阴影效果,还不知道制作方法的赶紧来看看。 ps图片阴影效果怎么做方法/...2017-07-06
- ps软件是现在很多人比较喜欢使用的,有着非常不错的功能。这次文章就给大家介绍下ps立体倒影效果制作方法,还不知道怎么制作的赶紧来看看。 最终效果  1...2017-07-06
- js里面设置DOM节点透明度的函数属性:filter= "alpha(opacity=" + value+ ")"(兼容ie)和opacity=value/100(兼容FF和GG)。 先来看看设置透明度的兼容性代码: 复制代码 代码如下: function setOpacity(ele, opacity) { if (...2014-06-07
- 本文章分享一篇关于Photoshop打造科幻片中的人物粒子化消失效果,教程重点是画笔的应用,人物身上产生的碎块,颗粒等都是用自定或下载的笔刷来完成,制作之前最好先下载一些...2016-09-14
- ps软件是现在非常受大家喜欢的一款软件,有着非常不错的制作效果。下面文章就给大家介绍下ps制作立体文字效果教程,感兴趣的一起来看看。 ps文字立体效果怎么做最终...2017-07-06
- 这篇文章主要介绍了jQuery实现的文字hover颜色渐变效果,以完整实例形式分析了jQuery实现文字颜色渐变效果的相关技巧,涉及jQuery插件jquery-ui-1.8.16.custom.min.js的使用,需要的朋友可以参考下...2016-02-23