I am trying to get a wipe up animation to make a circle look like it's filling with water. I've run into two errors, and haven't been able to even tackle the 3rd one:
<img>
tags, but I would like to move this effect to body { background-image: }
and need some direction on how to do this.What I have tried so far:
#banner { width: 300px; height: 300px; position: relative; } #banner div { position: absolute; } #banner div:nth-child(2) { -webkit-animation: wipe 6s; -webkit-animation-delay: 0s; -webkit-animation-direction: up; -webkit-mask-size: 300px 3000px; -webkit-mask-position: 300px 300px; -webkit-mask-image: -webkit-gradient(linear, left bottom, left top, color-stop(0.00, rgba(0, 0, 0, 1)), color-stop(0.25, rgba(0, 0, 0, 1)), color-stop(0.27, rgba(0, 0, 0, 0)), color-stop(0.80, rgba(0, 0, 0, 0)), color-stop(1.00, rgba(0, 0, 0, 0))); } @-webkit-keyframes wipe { 0% { -webkit-mask-position: 0 0; } 100% { -webkit-mask-position: 300px 300px; } }
<div id="banner"> <div> <img src="http://i.imgur.com/vklf6kK.png" /> </div> <div> <img src="http://i.imgur.com/uszeRpk.png" /> </div> </div>
Giving it a default mask position as @anpsmn suggested, doesn't reset it to black anymore.
Here are four different versions to supplement @misterManSam's brilliant answer.
Explanation
If you filled up a circular bowl full of liquid, it would fill faster at the bottom and top than it would in the middle (because there is more area to cover in the wider middle section). So, with that crude explanation in mind, the animation needs to: start fast, slow in the middle, and then finish fast when the bowl narrows again at the top.
To do this we can use a CSS3 easing function: cubic-bezier(.2,.6,.8,.4)
.
Have a look at the example below.
(If you want to tweak the easing here is a great resource: http://cubic-bezier.com/#.2,.6,.8,.4)
Example:
#banner { width: 150px; height: 150px; position: relative; background: #000; border-radius: 50%; overflow: hidden; } #banner::before { content: ''; position: absolute; background: #04ACFF; width: 100%; bottom: 0; animation: wipe 5s cubic-bezier(.2,.6,.8,.4) forwards; } @keyframes wipe { 0% { height: 0; } 100% { height: 100%; } }
<div id="banner"> </div>
Let's take this one step further? What if we wanted to add a wavy surface on the "water" using CSS? We can do this using the amazing SVG. I created a wavy SVG image in Adobe Illustrator and then animated that to travel from left to right on a loop with a separate CSS animation and voila:
Example
#banner { border-radius: 50%; width: 150px; height: 150px; background: #000; overflow: hidden; backface-visibility: hidden; transform: translate3d(0, 0, 0); } #banner .fill { animation-name: fillAction; animation-iteration-count: 1; animation-timing-function: cubic-bezier(.2, .6, .8, .4); animation-duration: 4s; animation-fill-mode: forwards; } #banner #waveShape { animation-name: waveAction; animation-iteration-count: infinite; animation-timing-function: linear; animation-duration: 0.5s; width:300px; height: 150px; fill: #04ACFF; } @keyframes fillAction { 0% { transform: translate(0, 150px); } 100% { transform: translate(0, -5px); } } @keyframes waveAction { 0% { transform: translate(-150px, 0); } 100% { transform: translate(0, 0); } }
<div id="banner"> <div class="fill"> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="300px" height="300px" viewBox="0 0 300 300" enable-background="new 0 0 300 300" xml:space="preserve"> <path fill="#04ACFF" id="waveShape" d="M300,300V2.5c0,0-0.6-0.1-1.1-0.1c0,0-25.5-2.3-40.5-2.4c-15,0-40.6,2.4-40.6,2.4 c-12.3,1.1-30.3,1.8-31.9,1.9c-2-0.1-19.7-0.8-32-1.9c0,0-25.8-2.3-40.8-2.4c-15,0-40.8,2.4-40.8,2.4c-12.3,1.1-30.4,1.8-32,1.9 c-2-0.1-20-0.8-32.2-1.9c0,0-3.1-0.3-8.1-0.7V300H300z"/> </svg> </div> </div>
This example includes a pour line (most bowls fill from the top, not the bottom). The pour line first animates from top to bottom while an animation-delay
property prevents the fill animation from happening until the pour has finished.
#banner { border-radius: 50%; width: 150px; height: 150px; background: #000; overflow: hidden; backface-visibility: hidden; transform: translate3d(0, 0, 0); position: relative; } #banner .fill { transform: translateY(150px); animation-name: fillAction; animation-iteration-count: 1; animation-timing-function: cubic-bezier(.2, .6, .8, .4); animation-duration: 4s; animation-fill-mode: forwards; animation-delay: 0.25s; } #banner .pour { width: 6px; position: absolute; left: 50%; margin-left: -3px; bottom: 0; top: 0; background: #009ae6; animation-name: pourAction; animation-timing-function: linear; animation-duration: 0.25s; } #banner #waveShape { animation-name: waveAction; animation-iteration-count: infinite; animation-timing-function: linear; animation-duration: 0.5s; width: 300px; height: 150px; fill: #04ACFF; } @keyframes pourAction { 0% { transform: translateY(-100%); } 100% { transform: translateY(0); } } @keyframes fillAction { 0% { transform: translateY(150px); } 100% { transform: translateY(-5px); } } @keyframes waveAction { 0% { transform: translate(-150px, 0); } 100% { transform: translate(0, 0); } }
<div id="banner"> <div class="pour"></div> <div class="fill"> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="300px" height="300px" viewBox="0 0 300 300" enable-background="new 0 0 300 300" xml:space="preserve"> <path fill="#04ACFF" id="waveShape" d="M300,300V2.5c0,0-0.6-0.1-1.1-0.1c0,0-25.5-2.3-40.5-2.4c-15,0-40.6,2.4-40.6,2.4 c-12.3,1.1-30.3,1.8-31.9,1.9c-2-0.1-19.7-0.8-32-1.9c0,0-25.8-2.3-40.8-2.4c-15,0-40.8,2.4-40.8,2.4c-12.3,1.1-30.4,1.8-32,1.9 c-2-0.1-20-0.8-32.2-1.9c0,0-3.1-0.3-8.1-0.7V300H300z" /> </svg> </div> </div>
This example adds a few more properties to the CSS to make it look a little more realistic.
.bowl { position: relative; border-radius: 50%; width: 150px; height: 150px; box-shadow: inset 0 -5px 0 0 rgba(0, 0, 0, 0.5), inset 0 -20px 5px 0 rgba(0, 0, 0, 0.2), inset -15px 0 5px 0 rgba(0, 0, 0, 0.1), inset 15px 0 5px 0 rgba(0, 0, 0, 0.1); background: -moz-radial-gradient(center, ellipse cover, transparent 0%, transparent 76%, rgba(0, 0, 0, 0.65) 100%); background: -webkit-radial-gradient(center, ellipse cover, transparent 0%, transparent 76%, rgba(0, 0, 0, 0.65) 100%); background: radial-gradient(ellipse at center, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0) 76%, rgba(0, 0, 0, 0.65) 100%); margin: 20px; } .bowl:before { overflow: hidden; border-radius: 50%; content: ""; box-shadow: inset 0 -5px 0 0 rgba(0, 0, 0, 0.5), inset 0 -20px 5px 0 rgba(0, 0, 0, 0.2), inset -15px 0 5px 0 rgba(0, 0, 0, 0.1), inset 15px 0 5px 0 rgba(0, 0, 0, 0.1); background: -moz-radial-gradient(center, ellipse cover, transparent 0%, transparent 60%, rgba(0, 0, 0, 0.65) 81%, black 100%); background: -webkit-radial-gradient(center, ellipse cover, transparent 0%, transparent 60%, rgba(0, 0, 0, 0.65) 81%, black 100%); background: radial-gradient(ellipse at center, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0) 60%, rgba(0, 0, 0, 0.65) 81%, #000000 100%); position: absolute; width: 150px; height: 150px; z-index: 2; } .bowl:after { content: ""; width: 60px; border-radius: 50%; height: 5px; background: #039be4; box-shadow: inset 0 0 10px 0 #000; position: absolute; left: 50%; margin-left: -30px; bottom: 0; z-index: 2; } .bowl .inner { border-radius: 50%; width: 150px; height: 150px; background: -moz-radial-gradient(center, ellipse cover, transparent 0%, transparent 76%, rgba(0, 0, 0, 0.65) 100%); background: -webkit-radial-gradient(center, ellipse cover, transparent 0%, transparent 76%, rgba(0, 0, 0, 0.65) 100%); background: radial-gradient(ellipse at center, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0) 76%, rgba(0, 0, 0, 0.65) 100%); overflow: hidden; -webkit-backface-visibility: hidden; -webkit-transform: translate3d(0, 0, 0); } .bowl .inner:before { content: ""; width: 20px; height: 20px; background: rgba(255, 255, 255, 0.2); border-radius: 50%; position: absolute; right: 40%; top: 60%; z-index: 2; } .bowl .inner:after { content: ""; width: 20px; height: 40px; background: rgba(255, 255, 255, 0.2); border-radius: 50%; position: absolute; right: 30%; top: 15%; transform: rotate(-20deg); z-index: 2; } .bowl .fill { -webkit-animation-name: fillAction; -webkit-animation-iteration-count: 1; -webkit-animation-timing-function: cubic-bezier(0.2, 0.6, 0.8, 0.4); -webkit-animation-duration: 4s; -webkit-animation-fill-mode: forwards; } .bowl .waveShape { -webkit-animation-name: waveAction; -webkit-animation-iteration-count: infinite; -webkit-animation-timing-function: linear; -webkit-animation-duration: 0.5s; width: 300px; height: 150px; fill: #039be4; } @-webkit-keyframes fillAction { 0% { -webkit-transform: translate(0, 150px); } 100% { -webkit-transform: translate(0, 10px); } } @-webkit-keyframes waveAction { 0% { -webkit-transform: translate(-150px, 0); } 100% { -webkit-transform: translate(0, 0); } } /* For aesthetics only ------------------------------------------*/ body { margin: 0; font-family: Segoe, "Segoe UI", "DejaVu Sans", "Trebuchet MS", Verdana, sans-serif; } h1 { font: 200 1.2em "Segoe UI Light", "DejaVu Sans", "Trebuchet MS", Verdana, sans-serif; font-weight: 200; color: #fff; background: #039be4; padding: 20px; margin: 0; border-bottom: 10px solid #ccc; } h1 strong { font-family: "Segoe UI Black"; font-weight: normal; } .explanation { padding: 20px 40px; float: right; background: #e64a19; -webkit-box-shadow: inset 0 30px 3px 0 rgba(0, 0, 0, 0.5); box-shadow: inset 0 3px 5px 0 rgba(0, 0, 0, 0.2); border-bottom: 10px solid #ccc; max-width: 300px; } .explanation p { color: #fff; font-size: 0.8rem; }
<div class="bowl"> <div class="inner"> <div class="fill"> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="300px" height="300px" viewBox="0 0 300 300" enable-background="new 0 0 300 300" xml:space="preserve"> <path class="waveShape" d="M300,300V2.5c0,0-0.6-0.1-1.1-0.1c0,0-25.5-2.3-40.5-2.4c-15,0-40.6,2.4-40.6,2.4 c-12.3,1.1-30.3,1.8-31.9,1.9c-2-0.1-19.7-0.8-32-1.9c0,0-25.8-2.3-40.8-2.4c-15,0-40.8,2.4-40.8,2.4c-12.3,1.1-30.4,1.8-32,1.9 c-2-0.1-20-0.8-32.2-1.9c0,0-3.1-0.3-8.1-0.7V300H300z" /> </svg> </div> </div> </div>
This can be achieved with a single div and a ::before
pseudo element:
The #banner
is given border-radius: 50%
to create a circle and overflow: hidden
to clip its children inside it
The ::before
pseudo element is animated to 100% height and the animation is paused at 100% using the forwards
value. It begins at the bottom with the use of bottom: 0
The background images would be applied in place of the black and blue backgrounds on #banner
and #banner::before
Compatibility: IE10+ and all modern browsers. The -webkit-
prefixed property is most likely no longer necessary for your keyframe animations. Check the browser compatibility chart over here on caniuse.com
I have added the cubic-bezier(.2,.6,.8,.4)
which is explained in @ChrisSpittles answer. It provides a neat effect!
#banner { width: 300px; height: 300px; position: relative; background: #000; border-radius: 50%; overflow: hidden; } #banner::before { content: ''; position: absolute; background: #04ACFF; width: 100%; bottom: 0; animation: wipe 5s cubic-bezier(.2,.6,.8,.4) forwards; } @keyframes wipe { 0% { height: 0; } 100% { height: 100%; } }
<div id="banner"> </div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With