第一次看到 CSS 動畫,覺得為之驚豔,這樣做動畫比用 jquery 自己刻快多了,效果又好,然後就因為工作在忙的關係,又停止了學習的腳步。
首先先來一個簡單的範例 :
這裡比較特別的是 cubic-bezier 可以利用這個網頁來計算
cubic-bezier,
四個參數其實是貝滋曲線的兩個控制點座標,
起點和終點為 0,0 和 1,1 , 套在 svg 上就是 <path d="M 0 0 C 參數1 參數2 參數3 參數4 1 1"/>
<style>
.a05301
{
position:absolute;
width:1em;
height:1em;
background-color:#f00;
animation-name:a05301_a1; /* 名稱 */
animation-duration:3000ms; /* 動畫時間 */
animation-delay:0ms; /* 延遲 */
animation-iteration-count:infinite;
/*
播放次數
infinite 代表無限次播放
*/
animation-timing-function:ease;
/*
預設 ease
linear, ease-in, ease-out, ease-in-out
step-start, step-end, steps(int,start/end),
cubic-bezier(n,n,n,n)
*/
animation-direction:alternate;
/*
播放方向
normal 預設
reverse 反向
alternate 來回
alternate-reverse 反向來回
*/
animation-fill-mode:none;
/*
播放後
none 回到前面
backwards 回到前面
forwards 停在後面
both 前面或後面
*/
animation-play-state:paused;
/*
running 播放中
paused 暫停
*/
}
.a05301_d1
{
animation-timing-function:ease;
}
.a05301_d2
{
animation-timing-function:linear;
}
.a05301_d3
{
animation-timing-function:ease-in;
}
.a05301_d4
{
animation-timing-function:ease-out;
}
.a05301_d5
{
animation-timing-function:ease-in-out;
}
.a05301_d6
{
animation-timing-function:cubic-bezier(0.6, -0.6, 0.1, 1.6);
}
.a05301_d7
{
animation-timing-function:steps(3,start);
}
@keyframes a05301_a1
{
0%
{
left:8em;
}
2%
{
left:8em;
}
50%
{
left:50%;
}
100%
{
left:95%;
}
}
#a05301_id1 input:checked ~ .a05301
{
animation-play-state:running;
}
</style>
<div id="a05301_id1" style="line-height:1em">
<label for="a05301_id2">播放</label>
<input id="a05301_id2" type="checkbox" checked=""><br><br>
<div class="a05301 a05301_d1"></div> ease <hr>
<div class="a05301 a05301_d2"></div> linear <hr>
<div class="a05301 a05301_d3"></div> ease-in <hr>
<div class="a05301 a05301_d4"></div> ease-out <hr>
<div class="a05301 a05301_d5"></div> ease-in-out <hr>
<div class="a05301 a05301_d6"></div> cubic-bezier<hr>
<div class="a05301 a05301_d7"></div> steps <hr>
</div>
<br>
ease
linear
ease-in
ease-out
ease-in-out
cubic-bezier
steps
Event
CSS 的屬性 animation-name 被修改後,動畫會重新開始,如果只給同一個名字是沒有用的,所以這裡的解決方法是先設 animation-name="" 然後設個 timeout 後再修改為要播放的動畫名稱
Ani2 的按鈕是利用新增 CSS 來取代本來的腳本,在 chrome 和 firefox 上,取代後會立即生效,但是在 safari 和 iphone/ipad 上卻會等動畫結束重新開始後才會套用新的腳本, Ani3 是取代後直接呼叫套用的 function 讓動畫重新開始。
animationstart 開始播放
animationend 播放結束
animationiteration 動畫開始重複
animationcancel 取消
<style>
.a05302
{
position:absolute;
width:1em;
height:1em;
background-color:#f00;
animation-name:"";
animation-duration:3000ms;
animation-iteration-count:2;
animation-timing-function:ease;
animation-direction:normal;
animation-fill-mode:both;
animation-play-state:paused;
}
@keyframes a05302_a1
{
0%
{
left:10%;
}
50%
{
left:50%;
}
100%
{
left:90%;
}
}
@keyframes a05302_a2
{
0%
{
left:10%;
}
50%
{
transform:translate(0,3em);
left:50%;
}
100%
{
left:90%;
}
}
#a05302_play:checked ~ .a05302
{
animation-play-state:running;
}
#a05302_div button
{
font-size:1em;height:1.7em;
}
</style>
<style id="a05302_newcss">
</style>
<div id="a05302_div">
播放 <input id="a05302_play" type="checkbox" checked=""><br>
<div id="a05302_id1" class="a05302"></div>
<br><br><br>
<button id="a05302_change">Change</button>
<button id="a05302_restart">Restart</button>
<button id="a05302_ani2">Ani2</button>
<button id="a05302_ani3">Ani3</button>
<br>
<br>
<div id="a05302_id2" style="border:1px solid #000;padding:1em;"></div>
</div>
<script>
(function()
{
let o = $("#a05302_id1");
let txt = $("#a05302_id2");
let n=0;
let a=["a05302_a1","a05302_a2"];
let an=0;
o.css("animation-name",a[an]);
function setani(o,name)
{
o.css("animation-name","");
setTimeout(function()
{
o.css("animation-name",name);
},10);
}
o.on("animationstart",function()
{
if (++n>=2) {txt.html("");n=0;}
txt.html(txt.html()+"開始.");
});
o.on("animationend",function()
{
txt.html(txt.html()+"結束.");
setani(o,a[an]);
});
o.on("animationiteration",function()
{
txt.html(txt.html()+"重複.");
});
o.on("animationcancel",function()
{
txt.html(txt.html()+"取消.");
});
$("#a05302_change").on("click",function()
{
an=(an+1)&1;
setani(o,a[an]);
});
$("#a05302_restart").on("click",function()
{
setani(o,a[an]);
});
$("#a05302_ani2").on("click",function()
{
let cc = document.getElementById('a05302_newcss').sheet;
try{cc.deleteRule(0);}catch(e){}
cc.insertRule("@keyframes a05302_a2{"
+"0%{left:10%;}50%{"
+"transform:translate(0,3em);"
+"left:50%;}100%{left:90%;}}", 0);
});
$("#a05302_ani3").on("click",function()
{
let cc = document.getElementById('a05302_newcss').sheet;
try{cc.deleteRule(0);}catch(e){}
cc.insertRule("@keyframes a05302_a2{"
+"0%{left:10%;}50%{"
+"transform:translate(0,-3em);"
+"left:50%;}100%{left:90%;}}", 0);
setTimeout(function(){setani(o,a[an])},10);
});
})();
</script>
利用 CSS 動畫來實做一個指針時鐘,幾乎不需要寫程式,
<style>
.a05303
{
position:absolute;
width:8em;
height:8em;
animation-name:a05303_a1;
animation-iteration-count:infinite;
animation-timing-function:linear;
animation-direction:normal;
animation-play-state:running;
}
.a05303_h
{
animation-duration:12000ms;
}
.a05303_m
{
animation-duration:1000ms;
}
@keyframes a05303_a1
{
0%
{
transform:rotate(0deg);
}
100%
{
transform:rotate(360deg);
}
}
.a05303_d1
{
position:absolute;
left:calc( 50% - 2px );
top:10%;
width:4px;
height:40%;
background-color:#0000ff;
}
.a05303_d2
{
position:absolute;
left:calc( 50% - 2px );
top:20%;
width:4px;
height:30%;
background-color:#ff0000;
}
.a05303_circle
{
border:1px solid #000;
width:8em;
height:8em;
border-radius:4em;
}
</style>
<div class="a05303 a05303_m">
<div class="a05303_d1"></div>
</div>
<div class="a05303 a05303_h">
<div class="a05303_d2"></div>
</div>
<div class="a05303_circle"></div>
搭配 clip-path 可以設計多邊形變形的動畫
<style>
.a05304_bk
{
position:relative;
width:13em;
height:13em;
background:#fff;
}
.a05304_path
{
position:absolute;
width:13em;
height:13em;
background:#ffee88;
animation-name:a05303;
animation-iteration-count:1;
animation-timing-function:ease;
animation-direction:normal;
animation-play-state:running;
animation-duration:2000ms;
animation-fill-mode:both;
}
.a05304_ball
{
position:absolute;
left:12em;
top:6em;
width:1em;
height:1em;
border-radius:0.5em;
background:#f00;
animation:a05304_a 3000ms 0s 1 linear running;
/*
animation:a05304_a 3000ms 0s infinite linear running;
*/
}
@keyframes a05304_a
{
0%{left:12.00em;top:6.00em;}
33%{left:3.00em;top:11.20em;}
66%{left:3.00em;top:0.80em;}
100%{left:12.00em;top:6.00em;}
}
@keyframes a05304_a1
{
0%
{clip-path:polygon(96% 50% ,27% 90% ,27% 10% ,96% 50% ,96% 50% ,96% 50% ,96% 50% ,96% 50% )
}
100%
{clip-path:polygon(96% 50% ,50% 96% ,4% 50% ,50% 4% ,96% 50% ,96% 50% ,96% 50% ,96% 50% )}
}
#a05304 button
{
font-size:1em;
}
</style>
<style id="a05304_css"></style>
<div id="a05304">
<div class="a05304_bk">
<div class="a05304_path"></div>
<div class="a05304_ball"></div>
</div><br>
<button class="a05304_b" nn="3">三角形</button>
<button class="a05304_b" nn="4">四邊形</button>
<button class="a05304_b" nn="5">五邊形</button>
<button class="a05304_b" nn="6">六邊形</button>
<button class="a05304_b" nn="7">七邊形</button>
</div>
<script>
$(function()
{
function cn(n)
{
let i;
let j=100/n;
let d=3.1415926*2/n;
let hh="@keyframes a05304_b{";
let pp="polygon(";
let x,y;
for (i=0;i<=n;i++)
{
x=(6+6*Math.cos(i*d));
y=(6+6*Math.sin(i*d));
hh+=(i*j)+"%{left:"+x+"em;top:"+y+"em;}";
pp+=((x+0.5)*100/13).toFixed(0)+"% "
+((y+0.5)*100/13).toFixed(0)+"% ,";
}
for (;i<=7;i++)
{
pp+=((x+0.5)*100/13).toFixed(0)+"% "
+((y+0.5)*100/13).toFixed(0)+"% ,";
}
hh+="}";
pp=pp.substr(0,pp.length-1)+")";
return [hh,pp];
}
function setani(o,name)
{
o.css("animation-name","");
setTimeout(function()
{
o.css("animation-name",name);
},10);
}
let bakn=3;
let bakpath="";
function setn(n)
{
let css=document.getElementById("a05304_css").sheet;
try{css.deleteRule(0);}catch(e){}
try{css.deleteRule(0);}catch(e){}
let r=cn(n);
let r1=cn(bakn);
css.insertRule(r[0]);
css.insertRule("@keyframes a05304_a1{"
+"0%{"
+"clip-path:"+r1[1]+";transform:rotate(0deg);"
+"-webkit-clip-path:"+r1[1]
+"}"
+"100%{"
+"clip-path:"+r[1]+";transform:rotate(360deg);"
+"-webkit-clip-path:"+r[1]
+"}}");
setani($(".a05304_path"),"a05304_a1");
bakn=n;
bakpath=r[1];
}
$(".a05304_path").on("animationend",function()
{
$(".a05304_path").css("clip-path",bakpath);
$(".a05304_path").css("-webkit-clip-path",bakpath);
});
$(".a05304_ball").on("animationend",function()
{
setani($(".a05304_ball"),"a05304_b");
});
$(".a05304_b").on("click",(e)=>
{
setn( parseInt($(e.target).attr("nn")) );
});
setn(3);
});
</script>