CSSとJavascriptだけのBubbleアニメ

2020年10月21日

テクノロジー プログラミング

eyecatch cssアニメは奥が深いことを、改めて理解した、ユゲタです。 とある会社のwebサイトを作った時に、水の中のイメージで泡が上っていく動画ファイルを背景に貼り付けたのが非常に印象良くできたので、 それをもっと軽くできないかと考えて、cssのみでBubbleアニメに挑戦してみました。 ただし、素のcssだけだと、ランダム座標や、いろいろなパラメータの繰り返し処理など、限界があったので、javascriptと連動することも許容しましたが、ライブラリなどは一切使っていないので、ブラックボックス無しの状態にすることができました。

ソースコード

<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <title>Bubble</title> <link rel="stylesheet" href="bubble.css"> <script src="bubble.js"></script> </head> <body> <div class="bubble-area"></div> </body> </html>   html,body{ width:100%; height:100%; padding:0; margin:0; } .bubble-area{ background: linear-gradient(to bottom, #6ca4e4 0%, #0c2b84 100%); width:100%; height:100%; position:relative; overflow:hidden; } .bubble-move{ position:absolute; width:50px; height:50px; transition-delay : 0s; transition-duration : 10s; transition-property : top; transition-timing-function : linear; } .bubble-move[data-mode="1"]{ transition-timing-function : linear; } .bubble-move[data-mode="2"]{ transition-timing-function : ease; } .bubble-move[data-mode="3"]{ transition-timing-function : ease-in-out; } .bubble-shake{ position:absolute; width:100%; height:100%; border:1px solid rgba(255,255,255,0.5); border-radius:50%; box-shadow: 0px 0px 15px 0px rgba(255, 255, 255, 0.6) inset; animation-delay : 0s; animation-timing-function: ease; animation-iteration-count: infinite; animation-direction : normal; } .bubble-shake[data-shake="1"]{ animation-name : shake-1; animation-duration : 2.0s; } .bubble-shake[data-shake="2"]{ animation-name : shake-2; animation-duration : 2.5s; } .bubble-shake[data-shake="3"]{ animation-name : shake-3; animation-duration : 3.0s; } .bubble-shake[data-shake="4"]{ animation-name : shake-4; animation-duration : 3.5s; } .bubble-shake:after { content: ""; display: block; width: 20%; height: 20%; border-radius: 100%; background: rgba(255, 255, 255, 0.8); position: absolute; right: 15%; top: 15%; filter: blur(2px); transform: rotateZ(45deg) scaleY(0.8); } @keyframes shake { 0% {transform : translateX( 10px)} 50% {transform : translateX(-10px)} 100% {transform : translateX( 10px)} } @keyframes shake-1 { 0% {transform : translateX( 10px)} 50% {transform : translateX(-10px)} 100% {transform : translateX( 10px)} } @keyframes shake-2 { 0% {transform : translateX(-15px)} 50% {transform : translateX( 15px)} 100% {transform : translateX(-15px)} } @keyframes shake-3 { 0% {transform : translateX( 20px)} 50% {transform : translateX(-20px)} 100% {transform : translateX( 20px)} } @keyframes shake-4 { 0% {transform : translateX(-25px)} 50% {transform : translateX( 25px)} 100% {transform : translateX(-25px)} } (function(){ var MAIN = function(){ this.area = document.querySelector(".bubble-area"); if(!this.area){return;} this.borns(); }; MAIN.prototype.borns = function(){ var num = this.get_rand(20,40); for(var i=0; i<num; i++){ this.set_item(); } }; MAIN.prototype.set_item = function(){ if(!this.area){return;} var item = document.createElement("div"); var shake = document.createElement("div"); shake.className = "bubble-shake"; var shake_num = this.get_rand(1,4); shake.setAttribute("data-shake" , shake_num); item.appendChild(shake); var pos = this.get_random_pos(); item.className = "bubble-move"; var move_num = this.get_rand(1,3); shake.setAttribute("data-move" , move_num); var id = (+new Date()); item.setAttribute("data-id" , id); item.style.setProperty("top" , pos.top +"px"); item.style.setProperty("left" , pos.left+"px"); var scale = this.get_scale(0.3,1.0); item.style.setProperty("transform" , "scale("+scale+")"); var duration = scale * 10000 /2; item.style.setProperty("transition-duration" , duration +"ms" , "important"); item.ontransitionend = (function(e){ var elm = e.target; elm.parentNode.removeChild(elm); this.set_item(); }).bind(this); this.area.appendChild(item); var rand_time = this.get_rand(0,10000); setTimeout((function(item){ item.style.setProperty("top" , "-60px" , ""); }).bind(this , item) , rand_time); }; MAIN.prototype.get_random_pos = function(){ return { top : this.area.offsetHeight, left : Math.floor(Math.random() * this.area.offsetWidth) }; }; MAIN.prototype.get_scale = function(min , max){ return Math.floor((Math.random() * (max - min) + min)*100) / 100; }; MAIN.prototype.get_rand = function(min , max){ return Math.floor((Math.random() * (max - min) + min)); }; window.addEventListener("load",function(){new MAIN()}); })()

解説

基本的にhtmlには、"bubble-area"というクラス名がついた器の中に、泡を発生させる仕様で、bubble.cssとbubble.jsを事前に読み込んでおく事を前提に設計しています。 cssでの重な内容は、泡1個分のcssを作っているんですが、左右の揺れと、上に移動する処理を別々に行うために、"bubble-move"と"bubble-shake"という2つのdivを自動で作るようにしています。 それをjavascriptで、画面(器)の底辺にx座標をランダムで配置して、タイミングをずらして、画面上部に座標移動すると、cssのトランジション処理で、泡が上に移動していくようにしています。 一番上まで到達した泡は、transitionendイベントを受け取って、自然に消えるようにセットしてみました。 泡が次から次へと生まれてきた時に、エレメントが残った状態では、そのページの処理速度が重くなるだろうと考えて、泡の最大個数を最初に表示して、その後は1個消えたら1個追加するという仕様にしています。 こうすることで、非常に軽い状態を保つことが可能になります。

プレビュー

See the Pen Bubble by YugetaKoji (@geta1972) on CodePen.

今の所の課題

bubble-areaのサイズに応じて、スピード変更をするような値付与を考えると、どんな大きさでも安定したアニメになるので、その点は考慮してみたいですね。 あと、カーソルでクリックしたら、泡が弾けて消えるような機能などをつけると、ホームページで使った時にかなり面白い印象が与えられます。 やってみても、見てみても面白いcssアニメでした。

人気の投稿

このブログを検索

ごあいさつ

このWebサイトは、独自思考で我が道を行くユゲタの少し尖った思考のTechブログです。 毎日興味がどんどん切り替わるので、テーマはマルチになっています。 もしかしたらアイデアに困っている人の助けになるかもしれません。

ブログ アーカイブ