<div id="fishbowl" class="fishbowl">
<div class="fishbowl__pool"></div>
<div class="fishbowl__background"></div>
<div class="fishbowl__bottom"></div>
<div class="fishbowl__decoration">
<div class="fishbowl__seaweed fishbowl__seaweed--1"></div>
<div class="fishbowl__seaweed fishbowl__seaweed--2"></div>
<div class="fishbowl__seaweed fishbowl__seaweed--3"></div>
</div>
<div class="fishbowl__water">
<div id="fish" class="fishbowl__fish">
<div class="fishbowl__fish-tail"></div>
</div>
<div class="fishbowl__water-color"></div>
</div>
<div class="fishbowl__top"></div>
<div id="tap" class="fishbowl__tap">
<div class="fishbowl__tap-base"></div>
<div class="fishbowl__tap-handle"></div>
<div class="fishbowl__tap-stream"></div>
<div class="fishbowl__tap-end"></div>
<div class="fishbowl__tap-head"></div>
<div class="fishbowl__tap-text">Click to refill</div>
</div>
</div>
$green: #80c0a1;
$yellow: #F5FCCD;
$brown: #ff7d66;
$black: #000038;
$white: #FFF;
$pink: #eb80b1;
$blue: #419197;
$dark-blue: #12486B;
$orange: orange;
$grey: #919ea3;
$dark-grey: #66777F;
html {
//Scaling drawing to fit on screen (thanks to rems)
font-size: 5vh;
@media screen and (min-height: 400px) {
// Avoiding really big versions of the illustration
font-size: 19px;
}
}
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: $pink;
}
@keyframes swimming {
0%,
100% {
transform: translateX(0);
}
22.5% {
transform: translateX(2.5rem) skewY(-5deg);
}
45% {
transform: translateX(6rem) translateY(-1rem) skewY(5deg);
}
55% {
transform: translateX(5rem) translateY(-0.5rem) scaleX(-1);
}
95% {
transform: translateX(0) scaleX(-1) skewY(10deg);
}
}
@keyframes dead {
0%,
100% {
transform: translateX(2.5rem);
}
22.5% {
transform: translateX(2.5rem) translateY(-1rem) skewY(-5deg);
}
45% {
transform: translateX(2.5rem) skewY(5deg);
}
55% {
transform: translateX(2.5rem) translateY(-1rem) skewY(-5deg);
}
95% {
transform: translateX(2.5rem) skewY(5deg);
}
}
.fishbowl {
$component-class: &;
position: relative;
width: 15rem;
height: 15rem;
&__background {
position: relative;
width: 100%;
height: 100%;
border-radius: 50% 50% 40% 40%;
background: linear-gradient(transparent 10%, $white 150%);
border-bottom: 1px solid $white;
}
&:before {
content: '';
position: absolute;
bottom: 9.5rem;
left: 2rem;
width: 100%;
height: 30%;
border-radius: 50%;
box-shadow: -4rem 10rem 1rem 0 rgba($black, 0.3);
transform: rotate(5deg);
}
&:after {
content: '';
position: absolute;
top: 12.5%;
left: 2.5%;
width: 95%;
height: 85%;
border-radius: 40%;
background: linear-gradient(135deg, transparent 50%, $white 150%);
}
&__bottom {
position: absolute;
bottom: 5%;
left: 17.5%;
width: 65%;
height: 20%;
border-radius: 50%;
background: linear-gradient($yellow, $brown 200%);
}
&__decoration {
position: absolute;
top: 20%;
left: 5%;
width: 90%;
height: 75%;
}
&__seaweed {
position: absolute;
width: 0;
height: 0;
border-left: 0.5rem solid transparent;
border-right: 0.5rem solid transparent;
border-bottom: 5rem solid $green;
&--1 {
bottom: 15%;
right: 20%;
border-bottom: 5rem solid $green;
}
&--2 {
bottom: 10%;
right: 30%;
border-bottom: 8rem solid $green;
}
&--3 {
bottom: 15%;
right: 40%;
border-bottom: 6rem solid $green;
}
}
&__water {
position: absolute;
bottom: 5%;
left: 5%;
width: 90%;
height: 80%;
border-radius: 40% 40% 4.8rem 4.8rem;
transition: height 0.3s ease;
overflow: hidden;
}
&__water-color {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: calc(1% * var(--filling, 90));
background: linear-gradient(transparent -50%, $blue 250%);
border-radius: 20% 20% 4rem 4rem;
transition: height 0.5s linear;
&:after {
content: '';
position: absolute;
top: 0;
left: 5%;
width: 90%;
height: 3rem;
border-radius: 50%;
background: linear-gradient(transparent 0%, $blue 250%);
box-shadow: inset 0 -1px 0 0 rgba($white, 0.5);
}
}
&__top {
position: absolute;
top: 5%;
left: 15%;
width: 70%;
height: 20%;
border-radius: 50%;
box-shadow: 0 2px 2px 3px rgba($white, 0.3);
}
&__fish {
position: absolute;
bottom: 25%;
left: 18%;
width: 2rem;
height: 1rem;
border-radius: 50%;
background: linear-gradient($white -200%, $orange);
box-shadow: 0 2rem 4px -2px rgba($black, 0.3);
transition-property: bottom, transform, box-shadow;
transition-duration: 1s;
transition-timing-function: ease;
animation: swimming;
animation-duration: 5s;
animation-iteration-count: infinite;
animation-fill-mode: forwards;
&:after {
content: '';
position: absolute;
top: 15%;
right: 15%;
width: 0.25rem;
height: 0.25rem;
border-radius: 50%;
background: radial-gradient(circle at 0 0, $white -100%, $dark-blue);
transition: height 0.5s ease;
}
&--dying {
bottom: 10%;
box-shadow: 0 1rem 4px -2px rgba($black, 0.3);
#{$component-class}__fish-tail {
box-shadow: 0 1rem 4px -2px rgba($black, 0.3);
}
}
&--dead {
animation: dead;
animation-duration: 2s;
animation-iteration-count: 2;
animation-fill-mode: forwards;
box-shadow: none;
#{$component-class}__fish-tail {
box-shadow: none;
}
&:after {
height: 0.125rem;
}
}
&--floating {
bottom: max(calc(var(--filling, 0) * 1% - 15%), 10%);
transform: translateX(2.5rem);
animation: none;
box-shadow: none;
&:after {
height: 2px;
}
#{$component-class}__fish-tail {
box-shadow: none;
}
}
}
&__fish-tail {
position: absolute;
top: 0;
left: -0.75rem;
width: 0;
height: 0;
border-top: 0.5rem solid transparent;
border-bottom: 0.5rem solid transparent;
border-left: 0.94rem solid $orange;
box-shadow: 0 2rem 4px -2px rgba($black, 0.3);
transition: box-shadow 1s ease;
}
&__pool {
position: absolute;
right: 0;
bottom: -5%;
width: 50%;
height: 15%;
border-radius: 50%;
background: linear-gradient($white -100%, $blue);
opacity: 0.5;
&:after {
@keyframes wave {
from {
top: 25%;
left: 25%;
width: 50%;
height: 50%;
}
to {
top: 10%;
left: 10%;
width: 80%;
height: 80%;
}
}
content: '';
position: absolute;
top: 25%;
left: 25%;
width: 50%;
height: 50%;
border-right: 2px solid $white;
border-radius: 50%;
animation: wave;
animation-duration: 3s;
animation-iteration-count: infinite;
opacity: 0.5;
}
}
&__tap {
position: absolute;
bottom: 0;
left: -3rem;
width: 12rem;
height: 15.9rem;
cursor: pointer;
&--active {
#{$component-class}__tap-stream {
@keyframes stream {
0% {
height: 0;
}
50% {
top: 2rem;
height: calc(14rem - var(--filling) * 0.1rem);
}
100% {
top: calc(2rem + 14rem - var(--filling) * 0.1rem);
height: 0;
}
}
animation: stream;
animation-duration: 0.5s;
}
#{$component-class}__tap-handle {
@keyframes handle {
from {
transform: rotate(45deg);
}
to {
transform: rotate(405deg);
}
}
animation: handle;
animation-duration: 0.5s;
}
}
}
&__tap-base {
position: absolute;
bottom: 0;
left: 0;
width: 2rem;
height: 14rem;
border-radius: 0 0 1.2rem 1.2rem;
box-shadow: inset -1px -1px 0 0px rgba($white, 0.5);
background: linear-gradient($grey, $dark-grey 150%);
&:before {
content: '';
position: absolute;
z-index: -1;
bottom: 4rem;
right: 15rem;
width: 100%;
height: 100%;
border-radius: 1rem 1rem 0 0;
box-shadow: -4rem 10rem 1rem 0 rgba($black, 0.3);
transform: rotate(-70deg);
}
&:after {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba($white, 0.4) 60%, transparent 200%);
border-radius: 0 0 1.2rem 1.2rem;
}
}
&__tap-handle {
position: absolute;
left: -1rem;
bottom: 6rem;
width: 2rem;
height: 2rem;
border-radius: 0.2rem;
border-top: 1px solid $white;
border-right: 1px solid rgba($white, 0.5);
background: radial-gradient(circle at 0 0, $white -100%, $grey);
transform: rotate(45deg);
&:after {
content: '';
position: absolute;
top: 0.5rem;
left: 0.5rem;
width: 1rem;
height: 1rem;
border-radius: 50%;
background: radial-gradient(circle at 0 0, $white -200%, $blue);
}
}
&__tap-stream {
position: absolute;
top: 2rem;
left: 6.25rem;
width: 1.5rem;
height: 0;
background: linear-gradient($white -100%, $blue);
border-radius: 1rem;
opacity: 0.3;
}
&__tap-head {
position: absolute;
top: 0;
left: 0;
width: 4rem;
height: 0rem;
border-radius: 50% 50% 0 0;
border-top: 2rem solid $grey;
border-left: 2rem solid $grey;
border-right: 2rem solid $grey;
box-shadow: 1px -1px 0 0 $white;
&:before {
content: '';
position: absolute;
z-index: -1;
bottom: 3rem;
right: 23rem;
width: 150%;
height: 200%;
box-shadow: -4rem 10rem 1rem 1rem rgba($black, 0.3);
transform: rotate(2deg) skewX(60deg);
}
&:after {
content: '';
position: absolute;
top: -2rem;
left: -2rem;
width: 8rem;
height: 2rem;
background: linear-gradient(transparent, rgba($white, 0.4) 60%, transparent 200%);
border-radius: 50% 50% 0 50%;
}
}
&__tap-end {
position: absolute;
left: 6rem;
top: 1.5rem;
width: 2rem;
height: 1rem;
border-radius: 50%;
background: linear-gradient($white -70%, $grey);
}
&__tap-text {
position: absolute;
top: 4rem;
left: -6rem;
color: $white;
font-family: 'Arial', sans-serif;
font-size: 0.875rem;
&:after {
content: '';
position: absolute;
bottom: -1rem;
right: -1rem;
width: 2rem;
height: 1px;
background-color: $white;
transform: rotate(45deg);
}
}
@media screen and (max-width: 420px) {
// Centering the whole illustration on mobile
left: 13%;
&__tap-text {
width: 2rem;
top: 1rem;
left: -3.5rem;
}
}
}
View Compiled
let fill = 90;
let intervalId = null;
const fishbowl = document.getElementById('fishbowl');
const fish = document.getElementById('fish');
const tap = document.getElementById('tap');
const emptyingFn = () => setInterval(() => {
fill = fill - 1;
fishbowl.style = `--filling: ${fill}`;
if (fill <= 0) {
clearInterval(intervalId);
} else if (fill < 20) {
fish.classList.add('fishbowl__fish--dead');
} else if (fill < 50) {
fish.classList.add('fishbowl__fish--dying');
} else {
fish.classList.remove('fishbowl__fish--dying');
fish.classList.remove('fishbowl__fish--dead');
}
}, 200);
intervalId = emptyingFn();
tap.addEventListener('click', () => {
tap.classList.add('fishbowl__tap--active');
setTimeout(() => tap.classList.remove('fishbowl__tap--active'), 500);
if (fill <= 0) {
intervalId = emptyingFn();
fish.classList.add('fishbowl__fish--floating');
}
fill = Math.min(fill + 20, 90);
});
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.