hello,民娜桑~~我又来开新坑了( ̄ε(# ̄)╰╮o( ̄皿 ̄///),这次尽量保证把这个坑填完~

本系列我会分四篇来完成主题,分别是① DIV+CSS的实现,② canvas2D的简单实现,③ canvas2D的进阶实现,④ webgl+着色器的实现 以及 ⑤ 包装成jquery插件并发布为npm模块 。

这是整个系列完成以后的最终效果:

开始阅读之前请确保您对高中的三角函数还有一定的印象以及了解基本的canvas绘图操作——当然如果你确实不了解也没事,这篇文章是使用div和css的实现,暂时没有用到以上的知识。

首先讲一下实现的原理,拿到一张图片后,获取其宽度,然后在性能允许的情况下,切成尽可能细的竖直切片,每个切片都用同一张背景图片并将背景图片的位置移动到切片的对应位置,然后通过css3关键帧动画使切片元素以不同的时间轴来进行上下移动。很简单是吧,如果你觉得so easy或者想根据原理自己试着实现一遍,那本文的后面你就可以直接跳过了。

html结构很简单:

<!doctype html>
<html lang="zh-cn">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>飘动的旗帜~</title><style>* {margin: 0;padding: 0;}html, body {height: 100%;width: 100%;background-color: lightgrey;}body {text-align: center;position: relative;}ul, li {list-style: none;}#flag {position: absolute;left: 50%;top: 50%;}/* 这里是核心css样式 */</style>
</head>
<body>
<ul id="flag"></ul>
<script>(function () {// 这里是js代码})();
</script>
</body>
</html>

然后,准备一张图片,比如这张艹猫路飞团的海盗旗,哎呀手滑,是草帽路飞团 (๑•̀ㅂ•́)و

接下来添加核心css代码:

/* 这里是核心css样式 */#flag > li {height: 100%;float: left;background-image: url("./img/flag.jpg");background-size: auto 100%;animation: flag ease-in-out infinite;
}

是的,你没看错,就是这么点~~事实上并非如此,为了实现代码的灵活性,比如自定义周期数、周期长度、振幅、切片数量等,我使用js代码动态创建了style标签,并将属性计算后写入。

下面是js代码,图片地址我暂时是写死的,通过上传图片自动生成动画我会在最后一节封装插件时作为补充来说明。

// 这里是js代码
var flagEle = document.getElementById('flag')
var image = new Image()
image.src = './img/flag.jpg'var IMG_MAX_WIDTH = 600
var IMG_MAX_HEIGHT = 600
var imgHeight
var imgWidth
image.onload = function () {imgWidth = image.widthimgHeight = image.heightvar ratio = image.width / image.heightif (imgWidth > IMG_MAX_WIDTH) {imgWidth = IMG_MAX_WIDTHimgHeight = imgWidth / ratio}if (imgHeight > IMG_MAX_HEIGHT) {imgHeight = IMG_MAX_HEIGHTimgWidth = imgHeight * ratio}flagEle.style.width = imgWidth + 'px'flagEle.style.height = imgHeight + 'px'flagEle.style.marginLeft = -imgWidth / 2 + 'px'flagEle.style.marginTop = -imgHeight / 2 + 'px'splitImg(100, 20, 2, 2)
}

虽然在图片加载后有一堆代码,但是除了 splitImg(100, 20, 2, 2) ,事实上其他都无关紧要,前面那段代码的主要作用是定义一个容器的最大宽高,如果超过将会被等比例缩放。(不过并不推荐使用大图,性能会是一个大问题)

下面使这段程序的核心方法——splitImg:

 /*** 分割图片* @param sliceCount 切片数量* @param amplitude 振幅* @param period 固定周期个数* @param duration 一个周期的时长*/function splitImg (sliceCount, amplitude, period, duration) {var styleEle = document.createElement('style')// styleEle.innerHTML = 'body{background: red}'var styleHtmlAry = []var sliceCountPerPeriod = Math.floor(sliceCount / period)var sliceWidth = imgWidth / sliceCountvar formula = sliceCountPerPeriod + 'n+'var interval = duration * period / sliceCount// 添加动画延时for (var i = 0; i < sliceCount; i++) {if (i < sliceCountPerPeriod) {styleHtmlAry.push('#flag > li:nth-child(' + formula + i + ') { ')styleHtmlAry.push('animation-delay: -' + (interval * (sliceCountPerPeriod - i)) + 's;')styleHtmlAry.push('}')}styleHtmlAry.push('#flag > li:nth-child(' + i + ') { background-position: -' + (i * sliceWidth) + 'px 0; }') // 设置切片背景}// 添加关键帧动画styleHtmlAry.push('@keyframes flag {')styleHtmlAry.push('0% { transform: translate3d(0, ' + amplitude + 'px, 0); }')styleHtmlAry.push('50% { transform: translate3d(0, -' + amplitude + 'px, 0); }')styleHtmlAry.push('100% { transform: translate3d(0, ' + amplitude + 'px, 0); }')styleHtmlAry.push('}')// 切片样式styleHtmlAry.push('#flag > li {')styleHtmlAry.push('animation-duration: ' + duration + 's;') // 添加周期时长styleHtmlAry.push('width: ' + (imgWidth / sliceCount) + 'px;') // 设置切片宽度styleHtmlAry.push('}')styleEle.innerHTML = styleHtmlAry.join('')// 创建切片元素flagEle.innerHTML = new Array(sliceCount + 1).join('<li></li>')document.documentElement.appendChild(styleEle)}

① 这里的波形图是使用的cos函数的表示形式,添加了三个关键帧:从波峰到波谷,再回到波峰。

② 因为使用了ease-in-out的动画曲线,所以可以模拟出三角函数的波形图

③ 原理和代码都比较简单,可能比较需要注意的是这句 styleHtmlAry.push('#flag > li:nth-child(' + formula + i + ') { '),对css3了解的朋友应该知道:nth-child的用法,括号里面的是一个等差数列表达式,项数规定用n表示,那么公差是多少呢,由于我们的动画是周期性的,所以公差应该是每个周期包含的切片数量(正整数),即 var sliceCountPerPeriod = Math.floor(sliceCount / period)。

写完以上代码,我们的基本雏形就出来了,这是切片数为80份,振幅20单位,2个周期,周期时长为2秒 时的效果图:

是不是看着有点不对劲?旗子不是应该一边固定的么?怎么两边一起动了?

办法也简单,只要我们在容器上加一个反方向的运动不就好了?

修改#flag样式,添加如下样式:animation: flag-reverse ease-in-out infinite;

#flag {position: absolute;left: 50%;top: 50%;transform: translate3d(-50%,-50%,0);animation: flag-reverse ease-in-out infinite;
}

如下位置添加js代码:

// 添加关键帧动画
...// 添加反向关键帧动画
styleHtmlAry.push('@keyframes flag-reverse {')
styleHtmlAry.push('0% { transform: translate3d(0, ' + (-amplitude) + 'px, 0); }')
styleHtmlAry.push('50% { transform: translate3d(0, ' + amplitude + 'px, 0); }')
styleHtmlAry.push('100% { transform: translate3d(0, ' + (-amplitude) + 'px, 0); }')
styleHtmlAry.push('}')// 容器应用flag-reverse动画
styleHtmlAry.push('#flag {')
styleHtmlAry.push('animation-duration: ' + duration + 's;') // 添加周期时长
styleHtmlAry.push('animation-delay: -' + (interval * sliceCountPerPeriod) + 's;')
styleHtmlAry.push('}')// 切片样式
...

似乎没问题了,看看效果:

纳尼?怎么两边都固定了?原来是因为我们指定2个周期,只要不是周期的整数倍就行了,在原来的基础上改为1.5个周期试试:

到这里我们的dom+css的实现方式就结束啦,这种方式的优点很明显,就是实现简单;缺点也不少,比如无法添加高光效果,整体振幅一致不符合常理,切片过多容易造成的页面阻塞与内存泄露,下一节 我会用canvas2D像素级的操作实现该效果,可以很大程度上避免这些问题。

完整代码戳这里

Demo:See the Pen flag waving by dom+css by Kay (@oj8kay) on CodePen.

原文发布时间为:2018年07月03日
原文作者:oj8kay

本文来源:开源中国 如需转载请联系原作者

前端实现旗帜飘动效果系列 (Ⅰ):dom+css实现相关推荐

  1. 前端实现旗帜飘动效果系列 (Ⅲ):canvas2D实现(2)

    2019独角兽企业重金招聘Python工程师标准>>> 本讲我们在上一讲的基础上,给旗子添加高光,使其看起来更加有立体感.我会用两种方式来分别实现这个效果,然后比较一下优劣,还是先讲 ...

  2. 【前端实例代码】霓虹灯按钮动画效果悬停| html CSS特效 惊艳| 前端开发 网页制作 基础入门教程

    b站视频演示效果: [web前端特效源码]霓虹灯按钮动画效果悬停| html CSS特效 惊艳| 前端开发 网页制作 基础入门教程 效果图: 完整代码: <!DOCTYPE html> & ...

  3. 初学RenderMonkey做一面旗帜飘动的效果

    这几天在捣鼓一个游戏 骑马与砍杀 不知道有没有人玩过.官方出了个shader包,可以自定义shader,于是就开始学起来了,学了一点,简单的实现了一直想弄的动态世界.这期间一直在用RenderMonk ...

  4. 【前端实例代码】使用 HTML 和 CSS 如何实现惊人的透明登录框页面毛玻璃效果| 前端开发 网页制作 基础入门教程

    b站视频演示效果: [web前端特效源码]使用 HTML 和 CSS 如何实现惊人的透明登录框页面毛玻璃效果| 前端开发 网页制作 基础入门教程 效果图: 完整代码: <!DOCTYPE htm ...

  5. 非常漂亮的Web前端波形点击效果

    非常漂亮的Web前端波形点击效果 介绍一种Web前端波形点击效果,第一次发文,大佬勿喷. 我的博客 介绍 Waves 这需要 Waves ,但是作者早在2018年就停止了对他的更新. 官网:Waves ...

  6. 视频教程-HTML + CSS零基础经典教程系列-HTML5/CSS

    HTML + CSS零基础经典教程系列 全栈开发工程师,现职于北京一家学院的全栈教学主任. 8年前端开发经验.4年移动端开发经验.4年UI设计经验.3年一线教学经验. 精通Node.JS.PHP.Ja ...

  7. 【前端面试知识题】- 3. HTML CSS

    序列号 内容 链接 1 前端知识面试题 - http&https(2022版) https://blog.csdn.net/qq_43061290/article/details/126651 ...

  8. div为空的时候 浮动没有效果_3种CSS清除浮动的方法

    点击上方 "前端技术精选" 关注,星标或者置顶 12点00分准时推送,第一时间送达 作者:html中文网 | 编辑:前端妹 来源:html.cn/web/css/19613.htm ...

  9. css显示内容越来越模糊_纯干货,前端学者的福音!如何使用css滤镜改变图片颜色...

    说到对图片进行处理,我们经常会想到PS,美图秀秀这类的图像处理工具.作为前端,全栈开发者,我们经常会需要处理一些特效,例如根据不同的状态,让图片显示不同的颜色.或者是hover的时候,对图片的对比度, ...

最新文章

  1. 博客大事记之迁移博客到香港主机
  2. java enter_Java UI.enter方法代码示例
  3. matlab mle pci为nan,matlab - 使用mle()估计自定义分布的参数 - 堆栈内存溢出
  4. 《敏捷制造——敏捷集成基础结构设计》——1.2相关问题的国内外研究现状
  5. 手把手教你薅羊毛,1 元体验业内领先AI技术!
  6. C# 简单方式运行powershell文件/使用cmd命令运行ps1
  7. 为JAVA性能而设计(一)
  8. 为别人软件加入广告或者密码(特别思路)
  9. 【nodejs】安装browser-sync 遇到错误提示
  10. 【Oracle】恢复重做日志组
  11. Java 工程与 Eclipse 高级用法
  12. 丢弃法(基于MXNet)
  13. 【PotPlayer】敲好用的本地视频播放器
  14. 课堂笔记_图形学基础课程_简单认知00
  15. laravel seeder 数据填充
  16. PhantomJS的安装
  17. 【项目管理工具】—— Microsoft Office Project 介绍
  18. 2020年书法落款_散文书法落款-2020年书法落款怎么写?
  19. 编译小米2s CyanogenMod 版本遇到的几个问题
  20. 如何消除下一代Wi-Fi 6E设备的延迟

热门文章

  1. 三维地图开发平台-支持离线地图开发
  2. MFC中VC6.0工程项目中文乱码的显示处理
  3. java 捕获sigkill,如何杀死由kill或kill -9上的脚本启动的进程生成的所有子进程
  4. Bilibili批量取消关注
  5. 用汇编语言程序设计实现c=a b,西安交通大学18年3月课程考试《汇编语言程序设计》作业考核试题...
  6. 查壳去壳和加壳的使用指南
  7. LeetCode 13 罗马符号转化为数字(难度: Easy)
  8. HTML5简明教程系列之HTML5基础(一)
  9. LightOJ 1395 A Dangerous Maze (II) (概率dp)
  10. 微信小程序实现文字识别-ocr插件