- 作者:陈大鱼头
- github: KRISACHAN
一声梧叶一声秋,一点芭蕉一点愁,三更归梦三更后。
大概是因为入秋的缘故,最近的感慨比较多。
很多的碎碎念都用都用 HTML 跟 CSS 来记录在我的codepen codepen.io/krischan77 至上,眼见积累到了一些了,就选出几个来与大家一同分享。
(免责声明:有些效果是我在网上看到觉得好,然后临摹下来的,创意不是原创,但是代码是自己手写的,如果有看到类似的效果,欢迎大家用来作对比。)
文章篇幅有限,因此有些太长的代码会进行压缩,请两句。
洋溢着青春的活力
这是两个带有弹性势能的弹跳盒,实现的主要思路就是利用 @keyframes
来控制 盒子的 scale
跟 translate
,从而在视觉上达成弹跳的效果。
(关于“洋溢着青春的活力”动效的说明,这个动效出处是第五届CSS大会上腾讯CDC高级前端开发陈在真老师以“CSS TIME”为主题的演讲中的讲解示例,主题链接在此:www.yuque.com/cssconf/5th… 当时鱼头我是想模仿下来来着,后来因为觉得关键帧调试麻烦,就直接CV了源码,时间一过就忘了这事,当成是原创的了。在这里对陈在真老师表示万分抱歉,同时也给读者们表示万分抱歉,是我的失误)
具体代码:
<style>
html,
body,
div {
margin: 0;
padding: 0;
}
html,
body {
width: 100%;
height: 100%;
}
.盒子组 {
width: 200px;
height: 200px;
position: absolute;
left: 50%;
top: 30px;
transform: translateX(-50%);
}
.大盒子 {
width: 100px;
height: 100px;
transform: scale(1, 1) translate(0, 0px);
animation: 大盒子跳 1s 0.3s linear infinite;
background: #3170a7;
margin: 100px auto;
}
.小盒子 {
width: 60px;
height: 60px;
transform: scale(1, 1) translate(0, 0px);
animation: 小盒子跳 1s 0.3s linear infinite;
background: #40a070;
margin: 0 auto;
position: relative;
top: -60px;
}
@keyframes 大盒子跳 {
0% {
transform: scale(1, 1) translate(0, 0px);
}
15% {
transform: scale(1.13, 0.87) translate(0, 0px);
}
30% {
transform: scale(0.92, 1.08) translate(0, -40px);
}
45% {
transform: scale(1.05, 0.95) translate(0, 0px);
}
60% {
transform: scale(0.93, 1.02) translate(0, -20px);
}
75% {
transform: scale(1, 1) translate(0, 0px);
}
100% {
transform: scale(1, 1) translate(0, 0px);
}
}
@keyframes 小盒子跳 {
0% {
transform: scale(1, 1) translate(0, 0px);
}
50% {
transform: scale(1, 1) translate(0, 0px);
}
60% {
transform: scale(1.13, 0.87) translate(0, 0px);
}
70% {
transform: scale(0.92, 1.08) translate(0, -40px);
}
80% {
transform: scale(1.05, 0.95) translate(0, 0px);
}
90% {
transform: scale(0.98, 1.02) translate(0, -20px);
}
100% {
transform: scale(1, 1) translate(0, 0px);
}
}
</style>
<div class="盒子组">
<div class="大盒子">
<div class="小盒子"></div>
</div>
</div>
你的手指在哪里
这是在很久之前一个网友面试时被问到的问题,当时题目是如何用纯CSS实现物体根据鼠标进入盒子的方向移动,一道挺有意思的题目,当时在群里各位大佬的讨论下,就有了这样的实现。
实现思路主要是在盒子四个不同的方位定位好子盒子,然后隐藏的同时让它们稍稍进入父盒子里一点,那么再鼠标划进去时,就能触发该方位隐藏的子盒子的 hover
事件,利用这个障眼法从而达到题目的效果。
代码如下:
<style>
body {
padding: 2em;
text-align: center;
}
.block {
position: relative;
display: inline-block;
overflow:hidden;
width: 10em;
height: 10em;
vertical-align: middle;
-webkit-transform: translateZ(0);
}
.block_hoverer {
position: absolute;
z-index: 1;
width: 100%;
height: 100%;
opacity: 0;
transition: all .3s ease;
}
.block_hoverer:nth-child(1) {
background: red;
top:-90%;
}
.block_hoverer:nth-child(2) {
background: lime;
top:90%;
}
.block_hoverer:nth-child(3) {
background: orange;
left:-90%;
}
.block_hoverer:nth-child(4) {
background: blue;
left:90%;
}
.block_hoverer:hover {
opacity:1;
top:0;
left:0;
}
.block_content {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
text-align: center;
line-height: 10em;
background: #333;
color: #FFF;
}
</style>
<p class="text">从不同方向使鼠标指针移过下面的内容</p>
<p>↓</p>
<span>→ </span>
<div class="block">
<div class="block_hoverer">1</div>
<div class="block_hoverer">2</div>
<div class="block_hoverer">3</div>
<div class="block_hoverer">4</div>
<div class="block_content">
Hover me!
</div>
</div>
<span> ←</span>
<p>↑</p>
摘下星星送给你
这是用纯CSS实现的一个评级功能,主要是利用了 label
标签跟 input
标签的联动性,以及 伪类:hover
跟 :focus
的操作性实现的。
代码如下:
<style>
html,
body,
div {
margin: 0;
padding: 0;
}
html,
body {
width: 100%;
height: 100%;
}
.container1,
.container2
{
font-size: 60px;
display: flex;
flex-direction: row-reverse;
justify-content: center;
}
.container1 input {
opacity: 0;
position: absolute;
}
.container1 label {
color: #aaa;
text-decoration: none;
-webkit-transition: color .4s;
-moz-transition: color .4s;
-o-transition: color .4s;
transition: color .4s;
}
.container1 label:hover ~ label,
.container1 input:focus ~ label,
.container1 label:hover {
color: #cc163a;
cursor: pointer;
}
.container2 label {
cursor: pointer;
font-size: 60px;
}
.container2 input {
opacity: 0;
position: absolute;
}
.container2 label:hover ~ label,
.container2 label:hover,
.container2 input:focus ~ label,
.container2 input:checked ~ label {
color: #cc163a;
}
</style>
<section class="container1">
<input name="star1" id="s1" type="radio" /><label for="s1">☆</label>
<input name="star1" id="s2" type="radio" /><label for="s2">☆</label>
<input name="star1" id="s3" type="radio" /><label for="s3">☆</label>
<input name="star1" id="s4" type="radio" /><label for="s4">☆</label>
<input name="star1" id="s5" type="radio" /><label for="s5">☆</label>
</section>
<section class="container2">
<input type="radio" name="star2" id="s6">
<label for="s6">☆</label>
<input type="radio" name="star2" id="s7">
<label for="s7">☆</label>
<input type="radio" name="star2" id="s8">
<label for="s8">☆</label>
<input type="radio" name="star2" id="s9">
<label for="s9">☆</label>
<input type="radio" name="star2" id="s10">
<label for="s10">☆</label>
</section>
客官今天要来点兔子吗?
这是一只兔子的路径动画,实现原理就是利用 animation
来操作 SVG path的 stroke-dashoffset
,从而实现路径动画。
代码如下:
<style>
path {
stroke-dasharray: 6600;
stroke-dashoffset: 6600;
animation: dash 4s linear alternate infinite;
fill: transparent;
}
@keyframes dash {
to {
stroke-dashoffset: 0;
fill: #d81e06;
}
}
</style>
<svg width="240" height="240" viewBox="0 0 1165 1024" version="1.1">
<path fill="transparent" stroke="#1296db" stroke-width="30" d="M0.000556 865.83469a66.118285 66.118285 0 0 0 65.93308 65.93308 69.08157 69.08157 0 0 0 39.63393-12.593959 222.246337 222.246337 0 0 0 111.123169 49.44981l26.113945 4.444927a232.247423 232.247423 0 0 0-5.370953 47.968168v2.222463h383.189726v-31.299693a123.717128 123.717128 0 0 0-62.043769-50.746247h-98.158799l-21.669018-15.927654 200.762525-50.931452 11.297522 17.594501 30.373666 79.823477 17.224092 52.227889H907.506434v-32.596129a144.83053 144.83053 0 0 0-38.893109-27.780793l-24.076687-11.667932-40.745161-62.969796v-112.790016a1069.375294 1069.375294 0 0 0 126.495207-140.015193l8.334237-0.926026 188.724182-49.635016h0.926026l36.11503-55.561584v-34.448182l-88.528124-97.417978a257.620546 257.620546 0 0 0-84.824019-61.117743l-13.519986-49.820221L944.54749 157.980105l-29.632845-67.414722L825.460495 10.556701A45.745704 45.745704 0 0 0 777.862737 3.889311a44.819678 44.819678 0 0 0-17.409296 13.33478l-7.408211-6.66739a46.30132 46.30132 0 0 0-74.082113 43.708446l60.376922 190.76144 72.785675 64.821849 12.96437 34.448182a371.706999 371.706999 0 0 0-58.710074 68.711159l-7.778622 11.482728-560.245976 107.048652a222.246337 222.246337 0 0 0-166.684753 267.066016c0 3.14849 1.666848 6.29698 2.592874 9.445469A65.377464 65.377464 0 0 0 0.000556 865.83469z" class="path"></path>
</svg>
滴水,亦能穿石
这个动效主要是利用了animation
来控制不同关键帧下的水滴状态,这里的滴水动画要注意的就是水滴下落的形变,以及到地上时引起的涟漪,主要是要尽量贴合物理现象。
代码如下:
<style>
.water-damage {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 200px;
height: 200px;
perspective: 600px;
transform-style: preserve-3d;
}
.water-drop {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 10;
width: 0;
height: 0;
border: 10px solid #30DFF3;
border-radius: 1000px;
margin-top: -10px;
margin-left: -10px;
opacity: 0;
transform-style: preserve-3d;
transform-origin: 50% 50%;
transform: translate(0, -100px) scale(1, 1);
animation: water-drop 3000ms cubic-bezier(.56, .18, .92, .69) infinite;
}
.water-drop::after {
content: "";
width: 0;
height: 0;
border-style: solid;
border-width: 0 7.5px 13.0px 7.5px;
border-color: transparent transparent #30DFF3 transparent;
position: absolute;
left: 50%;
top: -20px;
transform: translate(-50%, 0);
}
@keyframes water-drop {
0% {
opacity: 0;
z-index: 10;
transform: translate(0, -100px) scale(1, 1);
}
50% {
opacity: 1;
z-index: 10;
transform: translate(0, 0) scale(0.8, 1.2);
}
51% {
opacity: 1;
z-index: 10;
margin-top: -10px;
margin-left: -10px;
border-width: 10px;
transform: rotateX(70deg);
animation-timing-function: cubic-bezier(.12, .41, .63, .99);
}
100% {
opacity: 0;
z-index: 1;
margin-top: -200px;
margin-left: -200px;
border-width: 200px;
transform: rotateX(70deg);
animation-timing-function: cubic-bezier(.12, .41, .63, .99);
}
}
</style>
<div class="water-damage">
<div class="water-drop"></div>
</div>
即使故障,也要保持优雅
这是因为抖音而走红的故障风效果,实现原理就是通过animation
来用 clip-path: inset
对元素进行不同位置的切割,从而实现故障风动画。
代码如下:
<style>
.glitch-effect {
margin: auto;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
position: absolute;
top: 10px;
left: 0;
right: 0;
color: #FFF;
text-align: center;
font-size: 50px;
letter-spacing: 10px;
}
.ge-text {
position: relative;
color: #fff;
font-size: 72px;
line-height: 1;
letter-spacing: 0.01em;
transform: scale3d(1, 1, 1);
padding: 10px 50px;
background-image: linear-gradient( 135deg, #72EDF2 10%, #5151E5 100%);
overflow: hidden;
}
.ge-text::before, .ge-text::after {
content: attr(aria-title);
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
color: #fff;
background-image: linear-gradient( 135deg, #72EDF2 10%, #5151E5 100%);
clip-path: inset(79px 50px 43px 0px);
overflow: hidden;
}
.ge-text::before {
left: 7px;
text-shadow: 1px 0 #a1ffce;
animation: glitch-effect 3s infinite linear alternate-reverse;
}
.ge-text::after {
left: 3px;
text-shadow: -1px 0 #faffd1;
animation: glitch-effect 2s infinite linear alternate-reverse;
}
@keyframes glitch-effect {
0% {
clip-path: inset(4px 50px 61px 0px);
}
5% {
clip-path: inset(99px 50px 30px 0px);
}
10% {
clip-path: inset(100px 50px 90px 0px);
}
15% {
clip-path: inset(69px 50px 98px 0px);
}
20% {
clip-path: inset(51px 50px 18px 0px);
}
25% {
clip-path: inset(43px 50px 38px 0px);
}
30% {
clip-path: inset(67px 50px 71px 0px);
}
35% {
clip-path: inset(32px 50px 44px 0px);
}
40% {
clip-path: inset(98px 50px 96px 0px);
}
45% {
clip-path: inset(92px 50px 93px 0px);
}
50% {
clip-path: inset(23px 50px 84px 0px);
}
55% {
clip-path: inset(15px 50px 46px 0px);
}
60% {
clip-path: inset(53px 50px 9px 0px);
}
65% {
clip-path: inset(89px 50px 21px 0px);
}
70% {
clip-path: inset(47px 50px 1px 0px);
}
75% {
clip-path: inset(98px 50px 55px 0px);
}
80% {
clip-path: inset(86px 50px 81px 0px);
}
85% {
clip-path: inset(25px 50px 47px 0px);
}
90% {
clip-path: inset(49px 50px 87px 0px);
}
95% {
clip-path: inset(7px 50px 59px 0px);
}
100% {
clip-path: inset(79px 50px 43px 0px);
}
}
</style>
<div class="glitch-effect">
<h1 class="ge-text" aria-title="有趣的CSS">AWESOME</h1>
</div>
愿我如星君如月,夜夜流光相皎洁
这是用 display: grid
完成的心型布局,grid
真的是一个非常有用布局属性,建议还不熟的亲可以花时间去学习学习,这个心型布局实现的核心就是利用grid
的二维性来创建一个 columns 为11,rows 为10的盒子,然后按照心型的形状去定义子元素的 grid-area
,动画就是常规的显隐动画。
顺便安利下,这是一个在线生成GRID布局的神器:cssgrid-generator.netlify.com/,通过这个网站就可以自动生成你想要的布局。
代码如下:
<style>
html,
body,
div {
margin: 0;
padding: 0;
}
html,
body {
width: 100%;
height: 100%;
background: linear-gradient(to right, #141e30, #243b55);
}
.text {
text-align: center;
line-height: 3;
-webkit-text-fill-color: transparent;
background: linear-gradient(120deg, #a1c4fd 0%, #c2e9fb 100%);
-webkit-background-clip: text;
font-size: 30px;
}
.parent {
width: 700px;
height: 700px;
display: grid;
grid-template-columns: repeat(11, 1fr);
grid-template-rows: repeat(10, 1fr);
grid-column-gap: 10px;
grid-row-gap: 10px;
margin: auto;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.parent > div {
background: none;
border-radius: 10px;
animation-name: love;
animation-duration: 0.2s;
animation-timing-function: ease;
animation-iteration-count: 1;
animation-direction: normal;
animation-fill-mode: both;
animation-play-state: running;
}
.div1 { grid-area: 3 / 6 / 4 / 7; }
.div2 { grid-area: 2 / 7 / 3 / 8; }
.div3 { grid-area: 1 / 8 / 2 / 9; }
.div4 { grid-area: 1 / 9 / 2 / 10; }
.div5 { grid-area: 2 / 10 / 3 / 11; }
.div6 { grid-area: 3 / 11 / 4 / 12; }
.div7 { grid-area: 4 / 11 / 5 / 12; }
.div8 { grid-area: 5 / 11 / 6 / 12; }
.div9 { grid-area: 6 / 10 / 7 / 11; }
.div10 { grid-area: 7 / 9 / 8 / 10; }
.div11 { grid-area: 8 / 8 / 9 / 9; }
.div12 { grid-area: 9 / 7 / 10 / 8; }
.div13 { grid-area: 10 / 6 / 11 / 7; }
.div14 { grid-area: 9 / 5 / 10 / 6; }
.div15 { grid-area: 8 / 4 / 9 / 5; }
.div16 { grid-area: 7 / 3 / 8 / 4; }
.div17 { grid-area: 6 / 2 / 7 / 3; }
.div18 { grid-area: 5 / 1 / 6 / 2; }
.div19 { grid-area: 4 / 1 / 5 / 2; }
.div20 { grid-area: 3 / 1 / 4 / 2; }
.div21 { grid-area: 2 / 2 / 3 / 3; }
.div22 { grid-area: 1 / 3 / 2 / 4; }
.div23 { grid-area: 1 / 4 / 2 / 5; }
.div24 { grid-area: 2 / 5 / 3 / 6; }
@keyframes love {
from {
background: none;
}
to {
background: linear-gradient(120deg, #a1c4fd 0%, #c2e9fb 100%);
}
}
</style>
<div class="text">愿我如星君如月,夜夜流光相皎洁。</div><div class="parent"><div class="div1"></div><div class="div2"></div><div class="div3"></div><div class="div4"></div><div class="div5"></div><div class="div6"></div><div class="div7"></div><div class="div8"></div><div class="div9"></div><div class="div10"></div><div class="div11"></div><div class="div12"></div><div class="div13"></div><div class="div14"></div><div class="div15"></div><div class="div16"></div><div class="div17"></div><div class="div18"></div><div class="div19"></div><div class="div20"></div><div class="div21"></div><div class="div22"></div><div class="div23"></div><div class="div24"></div></div>
<script>
'use strict'
const div = [...document.querySelectorAll('.parent > div')]
div.forEach((d, i) => {
d.style = `animation-delay: ${(i + 1) * 0.2}s`
})
</script>
转动的时光,能否倒流
这是利用 transform
跟 transition
实现的一个3D轮播图,就是利用雪碧图思路将要轮播的背景切割给各个子盒子,然后子盒子进行Z轴变换。
代码如下:
<style>
html,
body,
div {
margin: 0;
padding: 0;
}
html,
body {
width: 100%;
height: 100%;
}
:root {
--base-color: #03A9F4;
--bg-color: #3cba92;
}
.center {
position: absolute;
margin: auto;
top: 50px;
right: 0;
left: 0;
}
.box {
width: calc(var(--base-size) * 4);
height: var(--base-size);
}
.slider {
width: var(--base-size);
height: var(--base-size);
color: var(--base-color);
perspective: 0px;
transform-style: preserve-3d;
position: absolute;
top: 0;
transform: rotateX(0deg);
}
.slider-1 {
left: calc(var(--base-size) * 0);
transition: all 1s linear 0s;
}
.slider-2 {
left: calc(var(--base-size) * 1);
transition: all 1s linear 0.5s;
}
.slider-3 {
left: calc(var(--base-size) * 2);
transition: all 1s linear 1s;
}
.slider-4 {
left: calc(var(--base-size) * 3);
transition: all 1s linear 1.5s;
}
.slider-page {
transform-style: preserve-3d;
width: var(--base-size);
height: var(--base-size);
position: relative;
}
.slider-main {
width: var(--base-size);
height: var(--base-size);
position:absolute;
box-sizing: border-box;
border: 1px solid currentcolor;
}
.slider-front {
transform: translateZ(calc(var(--base-size) / 2));
background-image: url(http://www.33lc.com/article/UploadPic/2012-8/2012891154949207.jpg);
border: none;
}
.slider-bottom {
transform: rotateX(-90deg) translateZ(calc(var(--base-size) / 2));
background-image: url(http://pic1.win4000.com/wallpaper/3/5858a0ab1ceb6.jpg);
border: none;
}
.slider-back {
transform: rotateZ(180deg) translateZ(calc(calc(-1 * var(--base-size)) / 2));
background-image: url(http://pic1.win4000.com/wallpaper/2/53cf2c1e5056b.jpg);
border: none;
}
.slider-top {
transform: rotateX(90deg) translateZ(calc(var(--base-size) / 2));
background-image: url(http://img.zcool.cn/community/03886cf575a66110000018c1b51ca27.jpg);
border: none;
}
.slider-right {
visibility: hidden;
transform: rotateY(90deg) translateZ(calc(var(--base-size) / 2));
}
.slider-left {
visibility: hidden;
transform: rotateY(-90deg) translateZ(calc(var(--base-size) / 2));
}
</style>
<div class="box center">
<div class="slider slider-1">
<div class="slider-page">
<div class="slider-main slider-front"></div>
<div class="slider-main slider-bottom"></div>
<div class="slider-main slider-back"></div>
<div class="slider-main slider-top"></div>
<div class="slider-main slider-right"></div>
<div class="slider-main slider-left"></div>
</div>
</div>
<div class="slider slider-2">
<div class="slider-page">
<div class="slider-main slider-front"></div>
<div class="slider-main slider-bottom"></div>
<div class="slider-main slider-back"></div>
<div class="slider-main slider-top"></div>
<div class="slider-main slider-right"></div>
<div class="slider-main slider-left"></div>
</div>
</div>
<div class="slider slider-3">
<div class="slider-page">
<div class="slider-main slider-front"></div>
<div class="slider-main slider-bottom"></div>
<div class="slider-main slider-back"></div>
<div class="slider-main slider-top"></div>
<div class="slider-main slider-right"></div>
<div class="slider-main slider-left"></div>
</div>
</div>
<div class="slider slider-4">
<div class="slider-page">
<div class="slider-main slider-front"></div>
<div class="slider-main slider-bottom"></div>
<div class="slider-main slider-back"></div>
<div class="slider-main slider-top"></div>
<div class="slider-main slider-right"></div>
<div class="slider-main slider-left"></div>
</div>
</div>
</div>
<script>
'use strict'
const baseSize = 200
document.documentElement.style.setProperty('--base-size', baseSize + 'px')
const sliders = [...document.querySelectorAll('.slider')]
const len = sliders - 1
sliders.forEach((slider, idx) => {
const xPos = (idx * baseSize)
const front = slider.querySelector('.slider-front')
const bottom = slider.querySelector('.slider-bottom')
const back = slider.querySelector('.slider-back')
const top = slider.querySelector('.slider-top')
front.style = `background-position: -${xPos}px -100px;`
bottom.style = `background-position: -${xPos}px -100px;`
back.style = `background-position: ${xPos}px 0px;`
top.style = `background-position: -${xPos}px -100px;`
})
const setPos = () => {
let index = 0
const setRotateX = () => {
index++
if (index > 3) {
index = 0
}
sliders.forEach(slider => {
slider.style.transform = `rotateX(${index * 90}deg)`
})
setTimeout(() => {
setRotateX()
}, 3000)
}
setRotateX()
}
setPos()
</script>
斯人若彩虹,遇上方知有
这是利用了 cubic-bezier
贝塞尔曲线的特性实现的动画,彩虹条的颜色是利用了filter: hue-rotate
去将色调转换。
代码如下:
<style>
html,
body,
div {
margin: 0;
padding: 0;
}
html,
body {
background: linear-gradient(to right, #0f2027, #203a43, #2c5364);
width: 100%;
height: 100%;
}
h1 {
text-align: center;
line-height: 3;
font-weight: 700;
-webkit-text-fill-color: transparent;
background-color: hsla(0, 100%, 60%, .8);
-webkit-background-clip: text;
animation: textColorRotate 5s linear infinite;
letter-spacing:2px
}
.rainbow-box {
position: absolute;
top: 100px;
right: 0;
left: 0;
margin: auto;
width: 200px;
height: 200px;
}
.rainbow-arc {
position: absolute;
left: 0;
top: 0;
width: 200px;
height: 100px;
box-sizing: border-box;
overflow: hidden;
transform-origin: 50% 100%;
animation: rainbowMove 3s cubic-bezier(.58,-0.57,.5,1.66) infinite;
}
.rainbow-arc-main {
border: 4px solid transparent;
border-radius: 100%;
box-sizing: border-box;
height: 150px;
left: 0;
margin: 0 auto;
position: absolute;
right: 0;
top: 0;
width: 150px;
}
.rainbow-arc:nth-child(1) {
animation-delay: -50ms;
}
.rainbow-arc:nth-child(2) {
animation-delay: -100ms;
}
.rainbow-arc:nth-child(3) {
animation-delay: -150ms;
}
.rainbow-arc:nth-child(4) {
animation-delay: -200ms;
}
.rainbow-arc:nth-child(5) {
animation-delay: -250ms;
}
.rainbow-arc:nth-child(6) {
animation-delay: -300ms;
}
.rainbow-arc:nth-child(7) {
animation-delay: -350ms;
}
.rainbow-arc:nth-child(1) .rainbow-arc-main {
border-color: hsla(0, 100%, 60%, .8);
height: 200px;
width: 200px;
top: 10px;
}
.rainbow-arc:nth-child(2) .rainbow-arc-main {
border-color: hsla(30, 100%, 60%, .8);
height: 180px;
width: 180px;
top: 20px;
}
.rainbow-arc:nth-child(3) .rainbow-arc-main {
border-color: hsla(60, 100%, 60%, .8);
height: 160px;
width: 160px;
top: 30px;
}
.rainbow-arc:nth-child(4) .rainbow-arc-main {
border-color: hsla(90, 100%, 60%, .8);
height: 140px;
width: 140px;
top: 40px;
}
.rainbow-arc:nth-child(5) .rainbow-arc-main {
border-color: hsla(120, 100%, 60%, .8);
height: 120px;
width: 120px;
top: 50px;
}
.rainbow-arc:nth-child(6) .rainbow-arc-main {
border-color: hsla(150, 100%, 60%, .8);
height: 100px;
width: 100px;
top: 60px;
}
.rainbow-arc:nth-child(7) .rainbow-arc-main {
border-color: hsla(180, 100%, 60%, .8);
height: 80px;
width: 80px;
top: 70px;
}
@keyframes textColorRotate {
from {
filter: hue-rotate(0deg);
}
to {
filter: hue-rotate(360deg);
}
}
@keyframes rainbowMove {
0%, 15% {
transform: rotate(0);
}
100% {
transform: rotate(360deg);
}
}
</style>
<h1><i>斯人若彩虹,遇上方知有</i></h1>
<div class="rainbow-box">
<div class="rainbow-arc">
<div class="rainbow-arc-main"></div>
</div>
<div class="rainbow-arc">
<div class="rainbow-arc-main"></div>
</div>
<div class="rainbow-arc">
<div class="rainbow-arc-main"></div>
</div>
<div class="rainbow-arc">
<div class="rainbow-arc-main"></div>
</div>
<div class="rainbow-arc">
<div class="rainbow-arc-main"></div>
</div>
<div class="rainbow-arc">
<div class="rainbow-arc-main"></div>
</div>
<div class="rainbow-arc">
<div class="rainbow-arc-main"></div>
</div>
</div>
这是在线生成贝塞尔曲线的网站,通过这个网站,你不需要手写,只需要在线调试就可以生成需用的值:cubic-bezier.com
我和我亲爱的祖国,一刻也不能分割
这个效果是为了庆祝祖国母亲70周年生日而画的,这里的五星红旗是通过SVG画的,早前在自己的文章里有提过五星红旗的具体属性。
国旗是五星红旗,旗面为红色,长宽比例为3:2。左上方缀黄色五角星五颗,四颗小星(其外接圆直径为旗高1/10)环拱在一颗大星(其外接圆直径为旗高3/10)的右面,并各有一个角尖正对大星的中心点。
通用尺寸有以下五种:
- 长288厘米,高192厘米;
- 长240厘米,高160厘米;
- 长192厘米,高128厘米;
- 长144厘米,高96厘米;
- 长96厘米,高64厘米。
所以我们有以下的墨线图:
所以按照这个比例我们能画出这样的SVG:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="900" height="600" viewBox="0 0 30 20">
<defs>
<path id="s" d="M0,-1 0.587785,0.809017 -0.951057,-0.309017H0.951057L-0.587785,0.809017z" fill="#ffde00"/>
</defs>
<rect width="30" height="20" fill="#de2910"/>
<use xlink:href="#s" transform="translate(5,5) scale(3)"/>
<use xlink:href="#s" transform="translate(10,2) rotate(23.036243)"/>
<use xlink:href="#s" transform="translate(12,4) rotate(45.869898)"/>
<use xlink:href="#s" transform="translate(12,7) rotate(69.945396)"/>
<use xlink:href="#s" transform="translate(10,9) rotate(20.659808)"/>
</svg>
至于飘扬的动画部分,同样是利用了雪碧图的原理,将图片的每一块区域赋值给dom节点,然后利用transform
进行Y轴的移动。
完整代码如下:
<style>
* {
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
width: 100%;
}
li {
list-style: none;
}
.flag {
position: absolute;
left: 50%;
top: 50%;
animation: wave ease-in-out infinite;
}
.flag > li {
height: 100%;
float: left;
background-image: url("https://fish-pond-1253945200.cos.ap-guangzhou.myqcloud.com/others/chinese/flag.jpg");
background-size: auto 100%;
animation: flag ease-in-out infinite;
}
</style>
<ul id="flag" class="flag"></ul>
<script>
const flag = document.querySelector('#flag')
const image = new Image()
image.src = 'https://fish-pond-1253945200.cos.ap-guangzhou.myqcloud.com/others/chinese/flag.jpg'
const flagWidth = 800
const flagHeight = 640
let imgWidth = ''
let imgHeight = ''
const imgRender = ({
sliceCount = 70,
amplitude = 20,
period = 1.5,
duration = 2,
}) => {
const style = document.createElement('style')
const styleSplinter = []
const sliceCountPerPeriod = Math.floor(sliceCount / period)
const sliceWidth = imgWidth / sliceCount
const formula = sliceCountPerPeriod + 'n+'
const delay = (duration * period / sliceCount)
for (let i = 0; i < sliceCount; ++i) {
if (i < sliceCountPerPeriod) {
styleSplinter.push(`
.flag > li:nth-child(${formula + i}) {
animation-delay: -${delay * (sliceCountPerPeriod - i)}s;
}
`)
}
styleSplinter.push(`
.flag > li:nth-child(${i}) {
background-position: -${i * sliceWidth}px 0;
}
`)
}
styleSplinter.push(`
@keyframes flag {
0% { transform: translate3d(0, ${amplitude}px, 0); }
50% { transform: translate3d(0, ${-amplitude}px, 0); }
100% { transform: translate3d(0, ${amplitude}px, 0); }
}
@keyframes wave {
0% { transform: translate3d(0, ${-amplitude}px, 0); }
50% { transform: translate3d(0, ${amplitude}px, 0); }
100% { transform: translate3d(0, ${-amplitude}px, 0); }
}
.flag {
animation-duration: ${duration}s;
animation-delay: -${delay * sliceCountPerPeriod}s;
}
.flag > li {
animation-duration: ${duration}s;
width: ${imgWidth / sliceCount}px;
}
`)
style.innerHTML = styleSplinter.join('')
flag.innerHTML = new Array(sliceCount + 1).join('<li></li>')
document.documentElement.appendChild(style)
}
image.onload = () => {
imgWidth = image.width
imgHeight = image.height
const ratio = image.width / image.height
if (imgWidth > flagWidth) {
imgWidth = flagWidth
imgHeight = imgWidth / ratio
}
if (imgHeight > flagHeight) {
imgWidth = imgHeight * ratio
imgHeight = flagHeight
}
flag.style.width = imgWidth + 'px'
flag.style.height = imgHeight + 'px'
flag.style.marginLeft = -imgWidth / 2 + 'px'
flag.style.marginTop = -imgHeight / 2 + 'px'
imgRender({
sliceCount: 70,
amplitude: 20,
period: 1.5,
duration: 2,
})
}
</script>
其实CSS还是很有趣的,各位有兴趣也可以多多发掘,多多开脑洞来创作一些有趣的特效。
鱼头我时不时就会上codepen.io/去看别人的创意,从中获取写CSS的灵感,各位对CSS感兴趣,或者希望可以增强CSS水平的都可以进去看看,当然里面不止有CSS,还有各类DEMO,算是可视化版的github了~
如果你喜欢探讨技术,或者对本文有任何的意见或建议,非常欢迎加鱼头微信好友一起探讨,当然,鱼头也非常希望能跟你一起聊生活,聊爱好,谈天说地。 鱼头的微信号是:krisChans95