一声梧叶一声秋,一点芭蕉一点愁,三更归梦三更后。
大概是因为入秋的缘故,最近的感慨比较多。
很多的碎碎念都用都用 HTML 跟 CSS 来记录在我的codepen https://codepen.io/krischan77 之上,眼见积累到了一些了,就选出几个来与大家一同分享。
(免责声明:有些效果是我在网上看到觉得好,然后临摹下来的,创意不是原创,但是代码是自己手写的,如果有看到类似的效果,欢迎大家用来作对比。)
这是两个带有弹性势能的弹跳盒,实现的主要思路就是利用 @keyframes
来控制 盒子的 scale
跟 translate
,从而在视觉上达成弹跳的效果。
效果地址:https://codepen.io/krischan77/pen/QXLdzP
具体代码:
<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
事件,利用这个障眼法从而达到题目的效果。
效果地址:https://codepen.io/krischan77/pen/RzomRX
代码如下:
<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
的操作性实现的。
效果地址:https://codepen.io/krischan77/pen/NZevBr
代码如下:
<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
,从而实现路径动画。
效果地址:https://codepen.io/krischan77/pen/mdbQqRm
代码如下:
<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
来控制不同关键帧下的水滴状态,这里的滴水动画要注意的就是水滴下落的形变,以及到地上时引起的涟漪,主要是要尽量贴合物理现象。
效果地址:https://codepen.io/krischan77/pen/pXdBWP
代码如下:
<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>
链接在此:https://codepen.io/krischan77/pen/pXdBWP
这是因为抖音而走红的故障风效果,实现原理就是通过 animation
来用 clip-path:inset
对元素进行不同位置的切割,从而实现故障风动画。
效果地址:https://codepen.io/krischan77/pen/QWLRjpN
代码如下:
<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>
链接在此:https://codepen.io/krischan77/pen/QWLRjpN
这是用 display:grid
完成的心型布局, grid
真的是一个非常有用布局属性,建议还不熟的亲可以花时间去学习学习,这个心型布局实现的核心就是利用 grid
的二维性来创建一个 columns 为11,rows 为10的盒子,然后按照心型的形状去定义子元素的 grid-area
,动画就是常规的显隐动画。
效果地址:https://codepen.io/krischan77/pen/wvvWoGy
顺便安利下,这是一个在线生成GRID布局的神器:https://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轴变换。
效果地址:https://codepen.io/krischan77/pen/poooxjP
代码如下:
<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
去将色调转换。
效果地址:https://codepen.io/krischan77/pen/OJJVbxJ
代码如下:
<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>
这是在线生成贝塞尔曲线的网站,通过这个网站,你不需要手写,只需要在线调试就可以生成需用的值:https://cubic-bezier.com
效果地址:https://codepen.io/krischan77/pen/WNeqOeB
这个效果是为了庆祝祖国母亲70周年生日而画的,这里的五星红旗是通过SVG画的,早前在自己的文章里有提过五星红旗的具体属性。
国旗是五星红旗,旗面为红色,长宽比例为3:2。左上方缀黄色五角星五颗,四颗小星(其外接圆直径为旗高1/10)环拱在一颗大星(其外接圆直径为旗高3/10)的右面,并各有一个角尖正对大星的中心点。
通用尺寸有以下五种:
所以我们有以下的墨线图:
所以按照这个比例我们能画出这样的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还是很有趣的,各位有兴趣也可以多多发掘,多多开脑洞来创作一些有趣的特效。
鱼头我时不时就会上https://codepen.io/去看别人的创意,从中获取写CSS的灵感,各位对CSS感兴趣,或者希望可以增强CSS水平的都可以进去看看,当然里面不止有CSS,还有各类DEMO,算是可视化版的github了~
如果你、喜欢探讨技术,或者对本文有任何的意见或建议,你可以扫描下方二维码,关注微信公众号“ 鱼头的Web海洋 ”,随时与鱼头互动。欢迎!衷心希望可以遇见你。