深藏在CSS裡的詩情畫意

陳大魚頭發表於2019-10-16

一聲梧葉一聲秋,一點芭蕉一點愁,三更歸夢三更後。

大概是因為入秋的緣故,最近的感慨比較多。

很多的碎碎念都用都用 HTMLCSS 來記錄在我的codepen codepen.io/krischan77 至上,眼見積累到了一些了,就選出幾個來與大家一同分享。

(免責宣告:有些效果是我在網上看到覺得好,然後臨摹下來的,創意不是原創,但是程式碼是自己手寫的,如果有看到類似的效果,歡迎大家用來作對比。)

文章篇幅有限,因此有些太長的程式碼會進行壓縮,請兩句。

洋溢著青春的活力

深藏在CSS裡的詩情畫意

這是兩個帶有彈性勢能的彈跳盒,實現的主要思路就是利用 @keyframes 來控制 盒子的 scaletranslate ,從而在視覺上達成彈跳的效果。

(關於“洋溢著青春的活力”動效的說明,這個動效出處是第五屆CSS大會上騰訊CDC高階前端開發陳在真老師以“CSS TIME”為主題的演講中的講解示例,主題連結在此:www.yuque.com/cssconf/5th… 當時魚頭我是想模仿下來來著,後來因為覺得關鍵幀除錯麻煩,就直接CV了原始碼,時間一過就忘了這事,當成是原創的了。在這裡對陳在真老師表示萬分抱歉,同時也給讀者們表示萬分抱歉,是我的失誤)

效果地址:codepen.io/krischan77/…

具體程式碼:

<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裡的詩情畫意

這是在很久之前一個網友面試時被問到的問題,當時題目是如何用純CSS實現物體根據滑鼠進入盒子的方向移動,一道挺有意思的題目,當時在群裡各位大佬的討論下,就有了這樣的實現。

實現思路主要是在盒子四個不同的方位定位好子盒子,然後隱藏的同時讓它們稍稍進入父盒子裡一點,那麼再滑鼠划進去時,就能觸發該方位隱藏的子盒子的 hover 事件,利用這個障眼法從而達到題目的效果。

效果地址:codepen.io/krischan77/…

程式碼如下:

<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裡的詩情畫意

這是用純CSS實現的一個評級功能,主要是利用了 label 標籤跟 input 標籤的聯動性,以及 偽類:hover:focus 的操作性實現的。

效果地址:codepen.io/krischan77/…

程式碼如下:

<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>
複製程式碼

客官今天要來點兔子嗎?

深藏在CSS裡的詩情畫意

這是一隻兔子的路徑動畫,實現原理就是利用 animation 來操作 SVG path的 stroke-dashoffset ,從而實現路徑動畫。

效果地址:codepen.io/krischan77/…

程式碼如下:

<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>
複製程式碼

滴水,亦能穿石

深藏在CSS裡的詩情畫意

這個動效主要是利用了animation 來控制不同關鍵幀下的水滴狀態,這裡的滴水動畫要注意的就是水滴下落的形變,以及到地上時引起的漣漪,主要是要儘量貼合物理現象。

效果地址:codepen.io/krischan77/…

程式碼如下:

<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>
複製程式碼

連結在此:codepen.io/krischan77/…

即使故障,也要保持優雅

深藏在CSS裡的詩情畫意

這是因為抖音而走紅的故障風效果,實現原理就是通過animation 來用 clip-path: inset 對元素進行不同位置的切割,從而實現故障風動畫。

效果地址:codepen.io/krischan77/…

程式碼如下:

<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>
複製程式碼

連結在此:codepen.io/krischan77/…

願我如星君如月,夜夜流光相皎潔

深藏在CSS裡的詩情畫意

這是用 display: grid 完成的心型佈局,grid真的是一個非常有用佈局屬性,建議還不熟的親可以花時間去學習學習,這個心型佈局實現的核心就是利用grid的二維性來建立一個 columns 為11,rows 為10的盒子,然後按照心型的形狀去定義子元素的 grid-area,動畫就是常規的顯隱動畫。

效果地址:codepen.io/krischan77/…

順便安利下,這是一個線上生成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>

複製程式碼

轉動的時光,能否倒流

深藏在CSS裡的詩情畫意

這是利用 transformtransition 實現的一個3D輪播圖,就是利用雪碧圖思路將要輪播的背景切割給各個子盒子,然後子盒子進行Z軸變換。

效果地址:codepen.io/krischan77/…

程式碼如下:

<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>
複製程式碼

斯人若彩虹,遇上方知有

深藏在CSS裡的詩情畫意

這是利用了 cubic-bezier 貝塞爾曲線的特性實現的動畫,彩虹條的顏色是利用了filter: hue-rotate去將色調轉換。

效果地址:codepen.io/krischan77/…

程式碼如下:

<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

我和我親愛的祖國,一刻也不能分割

深藏在CSS裡的詩情畫意

效果地址:codepen.io/krischan77/…

這個效果是為了慶祝祖國母親70週年生日而畫的,這裡的五星紅旗是通過SVG畫的,早前在自己的文章裡有提過五星紅旗的具體屬性。

國旗是五星紅旗,旗面為紅色,長寬比例為3:2。左上方綴黃色五角星五顆,四顆小星(其外接圓直徑為旗高1/10)環拱在一顆大星(其外接圓直徑為旗高3/10)的右面,並各有一個角尖正對大星的中心點。

通用尺寸有以下五種:

  1. 長288釐米,高192釐米;
  2. 長240釐米,高160釐米;
  3. 長192釐米,高128釐米;
  4. 長144釐米,高96釐米;
  5. 長96釐米,高64釐米。

所以我們有以下的墨線圖:

深藏在CSS裡的詩情畫意

所以按照這個比例我們能畫出這樣的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 也可以掃碼關注公眾號,訂閱更多精彩內容。

https://fish-pond-1253945200.cos.ap-guangzhou.myqcloud.com/img/base/qrcode-all.png

相關文章