- 作者:陳大魚頭
- 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 也可以掃碼關注公眾號,訂閱更多精彩內容。