效果预览

在线演示

按下右侧的“点击预览”按钮可以在当前页面预览,点击链接可以全屏预览。

https://codepen.io/comehope/pen/gBKWdW

可交互视频

此视频是可以交互的,你可以随时暂停视频,编辑视频中的代码。

请用 chrome, safari, edge 打开观看。

第 1 部分:
https://scrimba.com/p/pEgDAM/cazRgcL

第 2 部分:
https://scrimba.com/p/pEgDAM/ceDK7cB

源代码下载

本地下载

每日前端实战系列的全部源代码请从 github 下载:

https://github.com/comehope/front-end-daily-challenges

代码解读

定义 dom,包含 5 个子元素,分别代表 iphone, mini, ipad, macbook, imac 这 5 种设备:


<div class="container"><div class="device iphone"></div><div class="device mini"></div><div class="device ipad"></div><div class="device macbook"></div><div class="device imac"></div>
</div>

居中显示:


body {margin: 0;height: 100vh;display: flex;align-items: center;justify-content: center;background-color: #aaa;
}

设置容器中子元素的布局方式:


.container {position: relative;display: flex;flex-direction: column;align-items: center;
}

设置设备的共有属性,线性渐变图案将作为屏幕的背景:


.device {box-sizing: border-box;position: relative;display: flex;justify-content: center;background: linear-gradient(120deg, #ddd 30%, #ccc 30%);
}.device::before,
.device::after {content: '';position: absolute;
}

iphone, mini, ipad 的造型相似,都有顶部摄像头、传感器开口和底部按钮,所以这些共有属性可以一起设置,用 ::before 伪元素画出顶部细节,::after 伪元素画出底部按钮:


.iphone::before,
.mini::before,
.ipad::before {width: 2px;height: 2px;border-style: solid;border-color: #a5adbe;border-width: 0 12px 0 2px;
}.iphone::after,
.mini::after,
.ipad::after {width: 8px;height: 8px;background-color: white;border-radius: 50%;
}

接下来逐个画出设备。先画出 iphone 的轮廓:


.iphone {width: 59px;height: 124px;border: #484f5e solid;border-width: 18px 4px;border-radius: 6px;
}

定位 iphone 的顶部和底部细节:


.iphone::before {top: -10px;
}.iphone::after {bottom: -13px;
}

类似地,画出 mini:


.mini {width: 93px;height: 138px;border: #484f5e solid;border-width: 14px 5px;border-radius: 10px;
}.mini::before {top: -8px;
}.mini::after {bottom: -11px;
}

再画出 ipad:


.ipad {width: 134px;height: 176px;border: #484f5e solid;border-width: 18px 13px;border-radius: 12px;
}.ipad::before {top: -10px;
}.ipad::after {bottom: -13px;
}

接下来画 macbook,先画屏幕:


.macbook {width: 234px;height: 155px;border: 8px solid #484f5e;border-radius: 7px 7px 0 0;
}

::before 伪元素画出摄像头:


.macbook::before {width: 294px;height: 14px;background-color: #e8ebf0;top: calc(100% + 8px);border-radius: 0 0 14px 14px;
}

::after 伪元素画出主机:


.macbook::after {width: 3px;height: 3px;background-color: #a5adbe;top: -6px;border-radius: 50%;
}

接下来画 imac,先画屏幕,屏幕的左、上、右的黑色边框没有用 border 属性画,是因为 border 会在端点处遗留一个斜角,所以改用 box-shadow 实现:


.imac {width: 360px;height: 215px;border-radius: 10px;box-shadow: inset 0 14px #484f5e,inset 14px 0 #484f5e,inset -14px 0 #484f5e;border-bottom: 33px solid #e8ebf1;transform: translateY(14px);
}

::before 伪元素画出梯形的底座:


.imac::before {width: 90px;height: 0;top: calc(100% + 33px);border: solid transparent;border-bottom-color: #e2e4e8;border-width: 0 10px 47px 10px;
}

::after 伪元素画出顶部的摄像头和屏幕底部的按钮,注意按钮是用 box-shadow 实现的:


.imac::after {width: 4px;height: 4px;background-color: #a5adbe;top: 5px;border-radius: 50%;box-shadow: 0 191px 0 4px #464e5d;
}

至此,设备全部绘制完成。
删除除 iphone 之外的其他设备的 dom 元素,只保留 1 个 dom 元素,后面的动画效果都在这个 dom 元素上变化:


<div class="container"><div class="device iphone"></div><!-- <div class="device mini"></div><div class="device ipad"></div><div class="device macbook"></div><div class="device imac"></div> --></div>

设置容器尺寸,子元素垂直居中,设备的高度占容器高度的 75%:


.container {width: 360px;height: 350px;justify-content: center;
}.device {transform: translateY(-25%);
}

在 dom 中增加 2 个按钮元素,分别用 .left.right 表示:


<div class="container"><div class="device iphone"></div><div class="buttons"><span class="left"></span><span class="right"></span></div>
</div>

定位按钮的位置:


.buttons {position: absolute;width: inherit;font-size: 30px;height: 2em;bottom: 0;display: flex;justify-content: space-around;
}.buttons > * {position: relative;width: 4em;
}

按钮为向左和向右的箭头:


.buttons > *::before {position: absolute;
}.buttons .left::before {content: '←';right: 0;
}.buttons .right::before {content: '→';
}

设置按钮样式为圆形:


.buttons > *t::before {position: absolute;width: 2em;height: 2em;background-color: #484f5e;color: silver;text-align: center;line-height: 2em;border-radius: 1em;cursor: pointer;
}

增加鼠标悬停效果:


.buttons > *::before {transition: 0.2s;
}.buttons .left:hover::before {width: 4em;content: '⟵';
}.buttons .right:hover::before {width: 4em;content: '⟶';
}

增加按钮点击效果:


.buttons > *:active {transform: scale(0.9);filter: brightness(0.8);
}

至此,按钮制作完毕,接下来创建交互脚本。

定义一个获取元素的函数 $

const $ = (className) => document.getElementsByClassName(className)[0]
```

定义一个存放设备名称的数组:

let devices = ['iphone', 'mini', 'ipad', 'macbook', 'imac']
```

定义点击行为对数据的加工方法,当点击左侧按钮时,把数组最左边的 1 个元素移到最右边,相反地,当点击右侧按钮时,把数组最右边的 1 个元素移到最左边,这样就可以从 2 个方向循环遍历数组了:

let loop = {'left': () => devices.unshift(devices.pop()),'right': () => devices.push(devices.shift())
}
```

定义点击事件,根据数组的变化切换设备:

Array.from($('buttons').children).forEach(element =>element.addEventListener('click', function(e) {loop[e.target.className]()$('device').className = 'device ' + devices[0]})
)
```

最后,设置设备切换的缓动效果:


.device,
.device::before,
.device::after {transition: 0.4s cubic-bezier(0.5, 1.7, 0.5, 1.2);
}

大功告成!

原文地址:https://segmentfault.com/a/1190000016750591

如何用 CSS 和原生 JS 创作一个展示苹果设备的交互动画相关推荐

  1. 前端每日实战:116# 视频演示如何用 CSS 和原生 JS 开发一个监控网络连接状态的页面...

    效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/oPjWvw 可交互视频 此视频是可 ...

  2. 前端每日实战:163# 视频演示如何用原生 JS 创作一个多选一场景的交互游戏(内含 3 个视频)...

    效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/LXMzRX 可交互视频 此视频是可 ...

  3. 前端每日实战:164# 视频演示如何用原生 JS 创作一个数独训练小游戏(内含 4 个视频)...

    效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/mQYobz 可交互视频 此视频是可 ...

  4. 前端每日实战:160# 视频演示如何用纯 CSS 创作一个打开内容弹窗的交互动画...

    效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/GYXvez 可交互视频 此视频是可 ...

  5. HTML+CSS+原生JS写一个简易的音乐播放器(仅播放一首歌)

    用HTML+CSS+原生JS写一个简易的音乐播放器(仅播放一首歌) 效果如下:(鼠标点击按钮可以实现播放或暂停,按钮会旋转,实现了歌词同步,功能还需改进) 代码如下: <!DOCTYPE htm ...

  6. 原生js完成一个简单的抽奖功能

    文章目录 前言 实现过程 1.前期准备 2.CSS美化 3.使用 js 完成抽奖功能 3.1 随机数模块 3.2 随机奖品 3.3 开始抽奖 3.4 点击开始抽奖 完整代码 HTML部分 CSS部分 ...

  7. 原生JS实现一个简单的打字小游戏

    原生JS实现一个简单的打字小游戏 利用javascript制作一个简单的打字小游戏 之前写了一个贪吃蛇小游戏好像反响不错 今天我来写一个比贪吃蛇更low更简单的打字小游戏 打字小游戏原理 接下来咋们直 ...

  8. 原生JS实现球面展示特效

    分享一个由原生JS实现的球面展示效果,效果如下: 实现代码如下: <!DOCTYPE html> <html><head><meta http-equiv=& ...

  9. 原生JS实现影集展示特效

    分享一个用原生JS实现的影集展示特效,效果如下: 实现的代码如下: <!doctype html> <html><head><meta charset=&qu ...

最新文章

  1. CA证书服务器(4) 证书、CA、PKI
  2. 2013年十大IT发展趋势预测
  3. 031_mysql事务的安全隐患
  4. Linux内核进程管理基本概念-进程、运行队列、等待队列、进程切换、进程调度
  5. 实时通信RTC技术栈之:视频编解码
  6. ​亚马逊出品:非均匀扰动的对抗鲁棒性理论分析
  7. 【基础】ORACLE中on commit preserve rows和 on commit delete rows的区别
  8. linux 查看ip_如何在 Linux 中查看可用的网络接口 | Linux 中国
  9. c++ 字典_Python自学笔记(五):字典
  10. 特殊权限 set_uid、set_gid、stick_bit,软链接文件,硬链接文件
  11. c语言强制停止程序,C语言实现程序的暂停
  12. SwitchHosts
  13. 安捷伦or是德信号源+频谱仪操作: 从程控到自动测试 (三)互调检测的程控实现
  14. App微信支付(Java)
  15. 如何修改VsCode的背景图片
  16. 一次装系统惨痛的翻车经历
  17. 有趣的计算机课的作文,有趣的电脑课作文300字
  18. Python从视频中提取音频
  19. CouchDB与MongoDB对比
  20. 易语言 Visual Basic 6.0 (VB6)

热门文章

  1. Linux第八课samba服务器搭载
  2. BIGEMAP如何导出含高程值的标注点(线路高程提取)
  3. Flutter - dio 简单二次封装
  4. linux查询raid信息,linux查看raid信息
  5. 曙光服务器制作raid文档,曙光服务器做RAID步骤
  6. Linux学习日记4——ftp、lftp、nfs
  7. doe五步法_minitab中实验设计(doe).pdf
  8. 刚过去的520,大家都在送什么礼物,Python用可视化图告诉你
  9. 推荐系统(一)召回阶段
  10. crontab无法执行定时任务的问题:/var/spool/cron/#tmp.root.XXXXEzRLBb: Permission denied