CSS 变换、过渡、动画实现案例
MarcCrane
8年前
<p>以下所有效果的实现方式均为个人见解,如有不对的地方还请一一指出。</p> <h3>目录</h3> <ul> <li>方块“Z”字形运动</li> <li>线段围绕盒子运动</li> <li>饼图[动图, 固定比例,如20%]</li> <li>移动端录音旋转小按钮效果实现[渐变色][初始原型]</li> </ul> <h3>方块“Z”字形运动</h3> <p>要求:5s钟循环五次;每次的执行时间为2s;每一次执行到底部后反方向执行;最后停留在最后一帧</p> <p>考察:animation基本属性值</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/3168d9cad35a554a7e98610fce3eb0c8.png"></p> <p><a href="/misc/goto?guid=4959742536046999237" rel="nofollow,noindex">点击查看效果</a></p> <p>重点代码说明:</p> <pre> <code class="language-css">animation: move 2s linear 0s 5 alternate forwards;</code></pre> <table> <thead> <tr> <th>参数</th> <th>含义</th> </tr> </thead> <tbody> <tr> <td>move</td> <td>animation-name 动画名称</td> </tr> <tr> <td>2s</td> <td>animation-duration 动画持续时间, 注意加上单位</td> </tr> <tr> <td>linear</td> <td>animation-timing-function 动画过渡类型,linear:线性过渡</td> </tr> <tr> <td>0s</td> <td>animation-delay 动画延迟时间,注意加上单位</td> </tr> <tr> <td>5</td> <td>animation-iteration-count 动画循环次数, infinite表示无限循环</td> </tr> <tr> <td>alternate</td> <td>animation-direction 动画是否有反向运动, normal:正向运行; reverse:反向运行; alternate:先正向后反向; alternate-reverse:先反向后正向</td> </tr> <tr> <td>forwards</td> <td>animation-fill-mode 动画时间之外的状态, none: 不设置; forwards:设置为结束时的状态; backwords:设置为开始时的状态; both:动画结束或开始的状态</td> </tr> </tbody> </table> <p>详细代码示例:</p> <pre> <code class="language-css">dom结构: <div class="box"> <div class="square"></div> </div> 基本样式: .box{ position: relative; width: 200px; height: 200px; background-color: #fb3; } .box .square{ position: absolute; width: 30px; height: 30px; background-color: #58a; animation: move 2s linear 0s 5 alternate forwards; //动画,这里要注意,时间必须带上单位 } move动画定义 @keyframes move { 0% { transform: translateX(0); } 33% { transform: translateX(170px); } 66% { transform: translate(0, 170px); } 100% { transform: translate(170px, 170px); } }</code></pre> <h3>线段围绕盒子运动</h3> <p>要求:线段围绕盒子运动</p> <p>考察:clip的用法</p> <p>这个动画效果使用animation并不能很好的实现,最终实现方法是使用了 clip 属性,该属性用来剪裁对象。动画实现的原理是用line-box盒子覆盖住box盒子,line-box无背景只设置边框,然后使用clip进行剪裁。</p> <p>clip语法:rect(number number number number),依据上-右-下-左的顺序剪裁,如设置为auto则该边不剪裁。</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/9769238035525d9851695fe702160ebb.png"></p> <p><a href="/misc/goto?guid=4959742536129416031" rel="nofollow,noindex">点击查看效果</a></p> <p>代码示例:</p> <pre> <code class="language-css">dom结构: <div class="box"> <div class="line-box"></div> </div> 基本样式: .box{ position: relative; width: 200px; height: 200px; background-color: #fb3; } .box .line-box{ position: absolute; width: 220px; //多出来的20像素为线段到盒子的边距 height: 220px; left: 0; top: 0; margin-left: -10px; margin-top: -10px; border: 2px solid #58a; background-color: #58a; box-sizing: border-box; animation: move 5s linear infinite; } move动画定义 @keyframes move { 0% { clip: rect(0 220px 2px 0); //依据上-右-下-左的顺序剪裁 } 25% { clip: rect(0 0 220px 2px); } 50% { clip: rect(2px 220px 0 0); } 75% { clip: rect(0 2px 220px 0); } }</code></pre> <h3>饼图</h3> <p>动态饼图</p> <p><a href="/misc/goto?guid=4959742536202909245" rel="nofollow,noindex">点击查看效果</a></p> <p>实现方法:</p> <ul> <li>首先绘制饼图基本形状,使用使用渐变色生成背景 代码:</li> </ul> <pre> <code class="language-css">.box { border-radius: 50%; background: linear-gradient(to right, #58a 50%, #fb3 0); }</code></pre> <p>效果:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/12cec60c8bad758927595d303edb488b.png"></p> <ul> <li>借助伪元素盖住右侧背景,且需要设置 <strong>圆角</strong> ( <a href="/misc/goto?guid=4959742536285947303" rel="nofollow,noindex">Border详解</a> )。</li> <li>更改旋转中心</li> <li>设置动画,动画在旋转到50%时,需更改伪元素的背景由蓝色变成黄色。</li> </ul> <p>代码示例:</p> <pre> <code class="language-css">.box:before { content: ''; position: absolute; width: 50%; height: 100%; background-color: #58a; right: 0; border-radius: 0 100% 100% 0 / 50%; transform-origin: left center; animation: rotate 6s linear infinite, changeColor 12s step-end infinite; } @keyframes rotate{ to{ transform: rotate(180deg); } } @keyframes changeColor{ 50%{ background-color: #fb3; } }</code></pre> <p>任意大小饼图</p> <p><a href="/misc/goto?guid=4959742536363343248" rel="nofollow,noindex">预览效果</a></p> <p>如果知道animation-delay一个比较神奇的用法,那这个效果就很容易实现了。</p> <p>注意:一个负值的延时值是合法的,与0s的延迟类似,它意味着动画会立即开始播放,但会自动前进到延时值的绝对值处,就好像动画在过去已经播放了指定的时间一样。因此实际效果就是动画跳过指定时间而从中间开始播放了。</p> <p>所以我们只需增加伪元素的代码:</p> <pre> <code class="language-css">.box:before { ... animation-delay: -3s; animation-play-state: paused; }</code></pre> <p>最终代码如下:</p> <pre> <code class="language-css">.box { position: relative; width: 200px; height: 200px; margin: 0 auto; margin-top: 50px; border-radius: 50%; background: linear-gradient(to right, #58a 50%, #fb3 0); animation-delay: -7.5s; } .box:before { content: ''; position: absolute; width: 50%; height: 100%; background-color: #58a; right: 0; border-radius: 0 100% 100% 0 / 50%; transform-origin: left center; animation: rotate 6s linear infinite, change 12s step-end infinite; animation-delay: inherit; animation-play-state: paused; } @keyframes rotate{ to{ transform: rotate(180deg); } } @keyframes change{ 50%{ background-color: #fb3; } }</code></pre> <h3>移动端录音旋转小按钮效果实现[渐变色]</h3> <p>类似移动端的点击录音按钮的效果,或者是loading的原始效果,[初始原型,有待优化]。</p> <p>效果图:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/1f2b4523128983ed460d0ee7cb976c93.png"></p> <p><a href="/misc/goto?guid=4959742536447816106" rel="nofollow,noindex">预览效果</a></p> <p>实现方法[个人见解]:左侧与右侧分别控制,分别旋转。</p> <p>dom结构:</p> <pre> <code class="language-css"><div class="box"> <div class="item-left"></div> <div class="item-right"></div> <div class="item-center">60s</div> </div></code></pre> <ul> <li>item-right, 右侧需设置渐变色背景且为半圆形,选择一个灰色作为渐变色的中间点,这里选择的是#666,效果图如下:</li> </ul> <p style="text-align:center"><img src="https://simg.open-open.com/show/d014cf8b38da0d230d8a68ab023e76c5.png"></p> <p>代码:</p> <pre> <code class="language-css">.box .item-right { position: absolute; width: 50%; height: 100%; top: 0; right: 0; border-radius: 0 100% 100% 0/50%; /*设置圆角以实现半圆效果*/ background: linear-gradient(#fff, #666); /*渐变色背景*/ }</code></pre> <ul> <li>item-right, 使用伪元素覆盖住原本的颜色,这里需要注意的是,为了使伪元素更好的覆盖住item-right的颜色,可使用等比放大或者加阴影等方法,这里选择的是阴影。</li> </ul> <pre> <code class="language-css">.box .item-right:before{ content: ''; position: absolute; width: 100%; height: 100%; top: 0; left: 0; border-radius: inherit; background-color: #fff; box-shadow: 3px 0 2px 2px #fff; }</code></pre> <ul> <li>左侧同理,但是要注意圆角和颜色需更改:</li> </ul> <pre> <code class="language-css">border-radius: 100% 0 0 100%/50%; background: linear-gradient(#000, #666);</code></pre> <ul> <li>item-center主要是实现中间的小圆,可在这个圆上进行多种操作:</li> </ul> <pre> <code class="language-css">.box .item-center{ position: absolute; width: 190px; height: 190px; border-radius: 50%; background-color: #fff; top: 5px; left: 5px; line-height: 190px; }</code></pre> <ul> <li>下面开始实现旋转。</li> <li>右侧选中中心在左侧中间,而左侧的旋转中心在右侧中间,所以需要分别设置 transform-origin 属性。</li> <li>右侧先开始旋转,第一个动画设置旋转动画,第二个动画则设置当旋转结束时,右侧伪元素的颜色为透明色,以便左侧旋转。</li> </ul> <pre> <code class="language-css">animation: rotate 30s linear infinite, changeColor 60s step-end infinite;</code></pre> <ul> <li>左侧旋转需设置延迟时间,右侧旋转结束方可开始。</li> </ul> <pre> <code class="language-css">animation: rotate 30s 30s linear infinite;</code></pre> <p>两个动画的代码:</p> <pre> <code class="language-css">@keyframes rotate { to { transform: rotate(180deg); } } @keyframes changeColor{ 50%{ background-color: transparent; } }</code></pre> <p> </p> <p>来自:https://github.com/junruchen/junruchen.github.io/wiki/CSS-变换-过渡-动画使用案例</p> <p> </p>