Skip to content

Instantly share code, notes, and snippets.

@tks18
Last active April 25, 2021 00:46
Show Gist options
  • Save tks18/3c3e332527851d0d0b46230a5cc81bd8 to your computer and use it in GitHub Desktop.
Save tks18/3c3e332527851d0d0b46230a5cc81bd8 to your computer and use it in GitHub Desktop.
Pure CSS Heart Animation
<html>
<head>
<title> Pure CSS Heart Animation </title>
<style>
body {
display: flex;
justify-content: center;
margin: 0;
height: 100vh;
background: linear-gradient(135deg, #121721, #000);
font: 1em verdana, sans-serif;
}
.animation-head {
position: absolute;
left: -100vw;
}
.animation-head:checked + label {
color: #e2264d;
filter: none;
will-change: font-size;
-webkit-animation: heart 1s cubic-bezier(0.17, 0.89, 0.32, 1.49);
animation: heart 1s cubic-bezier(0.17, 0.89, 0.32, 1.49);
}
.animation-head:checked + label:before, .animation-head:checked + label:after {
-webkit-animation: inherit;
animation: inherit;
-webkit-animation-timing-function: ease-out;
animation-timing-function: ease-out;
}
.animation-head:checked + label:before {
will-change: transform, border-width, border-color;
-webkit-animation-name: bubble;
animation-name: bubble;
}
.animation-head:checked + label:after {
will-change: opacity, box-shadow;
-webkit-animation-name: sparkles;
animation-name: sparkles;
}
.animation-head:focus + label {
text-shadow: 0 0 3px white, 0 1px 1px white, 0 -1px 1px white, 1px 0 1px white, -1px 0 1px white;
}
.toggle-animation {
align-self: center;
position: relative;
color: #888;
font-size: 2em;
filter: grayscale(1);
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
cursor: pointer;
}
.toggle-animation:before, .toggle-animation:after {
position: absolute;
z-index: -1;
top: 50%;
left: 50%;
border-radius: 50%;
content: '';
}
.toggle-animation:before {
box-sizing: border-box;
margin: -2.25rem;
border: solid 2.25rem #e2264d;
width: 4.5rem;
height: 4.5rem;
transform: scale(0);
}
.toggle-animation:after {
margin: -0.1875rem;
width: 0.375rem;
height: 0.375rem;
box-shadow: 0.32476rem -3rem 0 -0.1875rem #ff8080, -0.32476rem -2.625rem 0 -0.1875rem #ffed80, 2.54798rem -1.61656rem 0 -0.1875rem #ffed80, 1.84982rem -1.89057rem 0 -0.1875rem #a4ff80, 2.85252rem 0.98418rem 0 -0.1875rem #a4ff80, 2.63145rem 0.2675rem 0 -0.1875rem #80ffc8, 1.00905rem 2.84381rem 0 -0.1875rem #80ffc8, 1.43154rem 2.22414rem 0 -0.1875rem #80c8ff, -1.59425rem 2.562rem 0 -0.1875rem #80c8ff, -0.84635rem 2.50595rem 0 -0.1875rem #a480ff, -2.99705rem 0.35095rem 0 -0.1875rem #a480ff, -2.48692rem 0.90073rem 0 -0.1875rem #ff80ed, -2.14301rem -2.12438rem 0 -0.1875rem #ff80ed, -2.25479rem -1.38275rem 0 -0.1875rem #ff8080;
}
@-webkit-keyframes heart {
0%, 17.5% {
font-size: 0;
}
}
@keyframes heart {
0%, 17.5% {
font-size: 0;
}
}
@-webkit-keyframes bubble {
15% {
transform: scale(1);
border-color: #cc8ef5;
border-width: 2.25rem;
}
30%, 100% {
transform: scale(1);
border-color: #cc8ef5;
border-width: 0;
}
}
@keyframes bubble {
15% {
transform: scale(1);
border-color: #cc8ef5;
border-width: 2.25rem;
}
30%, 100% {
transform: scale(1);
border-color: #cc8ef5;
border-width: 0;
}
}
@-webkit-keyframes sparkles {
0%, 20% {
opacity: 0;
}
25% {
opacity: 1;
box-shadow: 0.32476rem -2.4375rem 0 0rem #ff8080, -0.32476rem -2.0625rem 0 0rem #ffed80, 2.1082rem -1.26585rem 0 0rem #ffed80, 1.41004rem -1.53985rem 0 0rem #a4ff80, 2.30412rem 0.85901rem 0 0rem #a4ff80, 2.08305rem 0.14233rem 0 0rem #80ffc8, 0.76499rem 2.33702rem 0 0rem #80ffc8, 1.18748rem 1.71734rem 0 0rem #80c8ff, -1.35019rem 2.0552rem 0 0rem #80c8ff, -0.60229rem 1.99916rem 0 0rem #a480ff, -2.44865rem 0.22578rem 0 0rem #a480ff, -1.93852rem 0.77557rem 0 0rem #ff80ed, -1.70323rem -1.77366rem 0 0rem #ff80ed, -1.81501rem -1.03204rem 0 0rem #ff8080;
}
}
@keyframes sparkles {
0%, 20% {
opacity: 0;
}
25% {
opacity: 1;
box-shadow: 0.32476rem -2.4375rem 0 0rem #ff8080, -0.32476rem -2.0625rem 0 0rem #ffed80, 2.1082rem -1.26585rem 0 0rem #ffed80, 1.41004rem -1.53985rem 0 0rem #a4ff80, 2.30412rem 0.85901rem 0 0rem #a4ff80, 2.08305rem 0.14233rem 0 0rem #80ffc8, 0.76499rem 2.33702rem 0 0rem #80ffc8, 1.18748rem 1.71734rem 0 0rem #80c8ff, -1.35019rem 2.0552rem 0 0rem #80c8ff, -0.60229rem 1.99916rem 0 0rem #a480ff, -2.44865rem 0.22578rem 0 0rem #a480ff, -1.93852rem 0.77557rem 0 0rem #ff80ed, -1.70323rem -1.77366rem 0 0rem #ff80ed, -1.81501rem -1.03204rem 0 0rem #ff8080;
}
}
</style>
</head>
<body>
<input class="animation-head" id="toggle-heart" type="checkbox"/>
<label class="toggle-animation" for="toggle-heart" aria-label="like">😍</label>
</body>
</html>
// @import compass;
$bubble-d: 4.5rem; // bubble diameter
$bubble-r: .5*$bubble-d; // bubble-radius
$sparkle-d: .375rem;
$sparkle-r: .5*$sparkle-d;
@mixin sparkles($k) {
$shadow-list: ();
$n-groups: 7;
$group-base-angle: 360deg/$n-groups;
$group-distr-r: (1 + $k*.25)*$bubble-r;
$n-sparkles: 2;
$sparkle-base-angle: 360deg/$n-sparkles;
$sparkle-off-angle: 60deg; // offset angle from radius
$spread-r: -$k*$sparkle-r;
@for $i from 0 to $n-groups {
$group-curr-angle: $i*$group-base-angle - 90deg;
$xg: $group-distr-r*cos($group-curr-angle);
$yg: $group-distr-r*sin($group-curr-angle);
@for $j from 0 to $n-sparkles {
$sparkle-curr-angle: $group-curr-angle +
$sparkle-off-angle + $j*$sparkle-base-angle;
$xs: $xg + $sparkle-d*cos($sparkle-curr-angle);
$ys: $yg + $sparkle-d*sin($sparkle-curr-angle);
$shadow-list: $shadow-list, $xs $ys 0 $spread-r
hsl(($i + $j)*$group-base-angle, 100%, 75%);
}
}
box-shadow: $shadow-list;
}
@mixin bubble($ext) {
transform: scale(1);
border-color: #cc8ef5;
border-width: $ext;
}
body {
display: flex;
justify-content: center;
margin: 0;
height: 100vh;
background: linear-gradient(135deg,
#121721, #000);
font: 1em verdana, sans-serif;
}
.animation-head {
position: absolute;
left: -100vw;
&:checked + label {
color: #e2264d;
filter: none;
will-change: font-size;
animation: heart 1s cubic-bezier(.17, .89, .32, 1.49);
&:before, &:after {
animation: inherit;
animation-timing-function: ease-out;
}
&:before {
will-change: transform, border-width, border-color;
animation-name: bubble;
}
&:after {
will-change: opacity, box-shadow;
animation-name: sparkles;
}
}
&:focus + label {
text-shadow: 0 0 3px white,
0 1px 1px white, 0 -1px 1px white,
1px 0 1px white, -1px 0 1px white;
}
}
.toggle-animation {
align-self: center;
position: relative;
color: #888;
font-size: 2em;
filter: grayscale(1);
user-select: none;
cursor: pointer;
&:before, &:after {
position: absolute;
z-index: -1;
top: 50%; left: 50%;
border-radius: 50%;
content: '';
}
&:before {
box-sizing: border-box;
margin: -$bubble-r;
border: solid $bubble-r #e2264d;
width: $bubble-d; height: $bubble-d;
transform: scale(0);
}
&:after {
margin: -$sparkle-r;
width: $sparkle-d; height: $sparkle-d;
@include sparkles(1);
}
}
@keyframes heart {
0%, 17.5% { font-size: 0; }
}
@keyframes bubble {
15% { @include bubble($bubble-r); }
30%, 100% { @include bubble(0); }
}
@keyframes sparkles {
0%, 20% { opacity: 0; }
25% {
opacity: 1;
@include sparkles(0);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment