input(type='checkbox' name='special-mask' value='true' id='special-mask' class='special-mask option')
label(for='special-mask' class='option') ✨ Golden mask
input(type='checkbox' name='talking-mask' value='true' id='talking-mask' class='talking-mask option')
label(for='talking-mask' class='option') 💬 Talking mask
- var emotions = ['neutral','angry','sad','shocked','confused'];
- var emoji = ['😐', '😡', '😞', '😨', '🤔'];
- for (var e = 0; e < emotions.length; e++)
input(type='radio' name='mask-emotions' value='true' id='mask-emotions--'+emotions[e] class='mask-emotions--'+emotions[e]+' option' checked=e===0)
label(for='mask-emotions--'+emotions[e] class='option')
= emoji[e] + ' ' + emotions[e]
.aku-aku.star
.mask-wrapper.star
.feathers
.feather
.feather
.feather
.feather
.mask
.nose
.eye.eye--left
.brow.brow--left
.eye.eye--right
.brow.brow--right
.goatee
.mouth
.teeth
View Compiled
$u: 80vmin; // Base unit
@mixin transition($props) {
will-change: unquote($props);
transition-property: unquote($props);
transition-duration: .35s;
transition-timing-function: ease-in-out;
}
:root {
--lip: .01em;
--brow-offset: .035em;
--mouth-basis: .111em;
--mouth: var(--mouth-basis);
--bg1: #001195;
--bg2: #0c0c39;
--wood: #572f1c;
--feather1: #55428d;
--feather2: #d6b644;
--feather3: #cb8138;
--feather4: #b8346e;
--brows: #c94225;
--eyes: #d6b644;
--eyelids: #4aa759;
--teeth: #e5d2cf;
--goatee: #4aa85a;
--rotate-mask: 0deg;
}
*,
*::before,
*::after {
box-sizing: border-box;
}
html,
body {
height: 100%;
font-size: 16px;
overflow: hidden;
}
body {
display: flex;
justify-content: center;
align-items: center;
margin: 0;
background-image: radial-gradient(circle at center, var(--bg1), var(--bg2));
}
/* Here's where the magic starts */
.aku-aku {
position: relative;
width: .589em;
height: 1em;
font-size: $u;
perspective: 1em;
animation: maskFloat 2s ease-in-out alternate infinite;
transform-style: preserve-3d;
will-change: transform;
div { // Save ourselves some repetition…
position: absolute;
}
}
.mask-wrapper {
left: 0;
top: 0;
width: 100%;
height: 100%;
transform-origin: 43.4% 50%;
transform: rotateY(var(--rotate-mask));
@include transition('transform');
}
.feathers {
left: 0;
top: 0;
width: 100%;
height: .5em;
}
.feather {
bottom: 0;
width: .1417em;
clip-path: polygon(
50% 0,
100% 30%,
50% 100%,
0 32%
);
transform-origin: center bottom;
transform: rotate(var(--feather-angle, 0deg));
animation: feather 2s ease-in-out alternate infinite;
@include transition('background-color');
&:nth-child(1) {
--feather-angle: -30deg;
left: .122em;
height: .375em;
background-color: var(--feather1);
animation-delay: -1.5s;
}
&:nth-child(2) {
--feather-angle: 0deg;
left: .16em;
height: .5em;
background-color: var(--feather2);
animation-delay: -.5s;
}
&:nth-child(3) {
--feather-angle: 23deg;
left: .21em;
height: .41em;
background-color: var(--feather3);
}
&:nth-child(4) {
--feather-angle: 50deg;
left: .278em;
height: .319em;
background-color: var(--feather4);
animation-delay: -1s;
}
}
.mask {
left: .0833em;
top: .433em;
width: .336em;
height: .4027em;
&::before { // In a pseudo-element so the clip doesn't affect the entire mask
content: '';
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: var(--wood);
clip-path: polygon(
0 0,
100% 10%,
90% 95%,
10% 100%
);
@include transition('background-color');
}
}
.nose {
left: .117em;
top: .181em;
width: .106em;
height: .15em;
background-color: var(--feather3);
clip-path: polygon(
50% 0,
100% 71%,
50% 100%,
0 74%
);
@include transition('background-color');
}
.eye {
top: .0917em;
width: .156em;
height: .156em;
&::before { // In a pseudo-element so the animation doesn't affect the eyebrows
content: '';
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: var(--eyes);
clip-path: polygon(0 10%, 100% 10%, 100% 100%, 0 100%); // Clip the top part of the eyes under the eyebrow
transform-origin: 50% 12.5%;
animation: blink 3s ease-in-out alternate infinite;
@include transition('background-color, transform, box-shadow');
}
&--left {
left: -.002em;
&::before {
border-radius: 50% 25% 50% 50%;
box-shadow: inset .0125em -.025em 0 var(--eyelids);
}
}
&--right {
right: -.008em;
&::before {
border-radius: 25% 50% 50% 50%;
box-shadow: inset -.0125em -.025em 0 var(--eyelids);
}
}
}
.brow {
width: 120%;
height: 50%;
background-color: var(--brows);
@include transition('transform, background-color');
&--left {
left: -15%;
top: -8%;
transform-origin: calc(50% + var(--brow-offset)) 125%;
clip-path: polygon(
0 .002em,
calc(100% - .002em) 0,
100% 70%,
.002em 100%
);
}
&--right {
right: -15%;
top: -4%;
transform-origin: calc(50% - var(--brow-offset)) 125%;
clip-path: polygon(
.002em 0,
calc(100% - .002em) .002em,
100% 100%,
0 70%
);
}
}
.mouth {
left: -.008em;
top: .328em;
width: .353em;
height: var(--mouth);
background-color: var(--brows);
clip-path: polygon(
.035em 0,
calc(50% + .001em) .02em,
calc(100% - .037em) 0,
100% 100%,
0 100%
);
@include transition('height, background-color'); // Yeah, terrible thing to do, I know - I don't do this on actualy websites, I promise!
}
.teeth {
left: 0;
right: 0;
top: 0;
bottom: 0;
width: calc(100% - var(--lip) * 9);
height: calc(100% - var(--lip) * 9);
margin: auto;
background-color: var(--teeth);
clip-path: polygon(
var(--lip) 0,
calc(50% + .001em) var(--lip),
calc(100% - var(--lip)) 0,
100% 100%,
0 100%
);
@include transition('background-color');
}
.goatee {
top: .42em;
left: 0;
right: 0;
width: .156em;
height: .111em;
margin: 0 auto;
&::before,
&::after {
content: '';
position: absolute;
top: 0;
border-style: solid;
border-color: var(--goatee) transparent transparent;
@include transition('border-color');
}
&::before {
left: calc(45% - .063em);
border-width: .11em .063em 0 .063em;
filter: brightness(.95);
}
&::after {
left: calc(65% - .047em);
border-width: .092em .047em 0 .047em;
}
}
// Light animations…
@keyframes maskFloat {
from { transform: translateY(-.025em) rotate(-1deg); }
to { transform: translateY(.025em) rotate(1deg); }
}
@keyframes blink {
0% { transform: scaleY(1); }
5% { transform: scaleY(.25); }
10% { transform: scaleY(1); }
}
@keyframes feather {
from { transform: rotate(calc(var(--feather-angle) - 2deg)); }
to { transform: rotate(calc(var(--feather-angle) + 2deg)); }
}
@keyframes talking {
0% { height: var(--mouth); }
10% { height: calc(var(--mouth) * .9); }
20% { height: calc(var(--mouth) * 1.1); }
30% { height: var(--mouth) ; }
40% { height: calc(var(--mouth) * 1.2); }
50% { height: var(--mouth); }
60% { height: calc(var(--mouth) * .8); }
70% { height: calc(var(--mouth) * 1.15); }
80% { height: var(--mouth); }
90% { height: calc(var(--mouth) * .9); }
100% { height: var(--mouth); }
}
@keyframes stars {
from {
opacity: 1;
transform: translate(0, 0);
}
}
// Here are the variations depending on the options checked (default is 'neutral')
.special-mask:checked ~ .aku-aku {
--wood: #92572d;
--feather1: #d97937;
--feather2: #d6b644;
--feather3: #d97937;
--feather4: #d6b644;
--brows: #c74a26;
--eyes: #eaba58;
--eyelids: #4aa85a;
--teeth: #f7c06e;
--goatee: #cb8138;
--rotate-mask: 360deg;
&,
> .star {
&::before,
&::after {
content: '✨';
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
width: 2rem;
height: 2rem;
margin: auto;
font-size: 2rem;
opacity: 0;
animation: stars .75s ease-out infinite forwards;
z-index: -1;
}
}
&::before {
transform: translate(#{$u * -.75}, #{$u * 1.1});
}
&::after {
transform: translate(#{$u * 1.25}, #{$u * -.8});
animation-delay: -.75s;
}
> .star {
&::before {
transform: translate(#{$u * -1.125}, #{$u * -.9});
animation-delay: -.5s;
}
&::after {
transform: translate(#{$u * .75}, #{$u * 1.2});
animation-delay: -.25s;
}
}
}
.talking-mask:checked ~ .aku-aku {
@include transition('--mouth');
.mouth {
animation: talking 2s ease-in-out infinite none;
}
}
.mask-emotions--angry:checked ~ .aku-aku {
--mouth: calc(var(--mouth-basis) * .9);
.brow--left {
transform: rotate(10deg);
}
.brow--right {
transform: rotate(-10deg);
}
}
.mask-emotions--sad:checked ~ .aku-aku {
--mouth: calc(var(--mouth-basis) * 1.1);
.brow--left {
transform: translateX(calc(var(--brow-offset) * .5)) rotate(-10deg);
}
.brow--right {
transform: translateX(calc(var(--brow-offset) * -.5)) rotate(10deg);
}
}
.mask-emotions--shocked:checked ~ .aku-aku {
--mouth: calc(var(--mouth-basis) * 1.5);
.brow--left {
transform: translateY(calc(var(--brow-offset) * -.5)) rotate(-7deg);
}
.brow--right {
transform: translateY(calc(var(--brow-offset) * -.5)) rotate(7deg);
}
}
.mask-emotions--confused:checked ~ .aku-aku {
--mouth: calc(var(--mouth-basis) * 1.05);
.brow--left {
transform: translateY(calc(var(--brow-offset) * -.5)) rotate(-7deg);
}
.brow--right {
transform: translateX(calc(var(--brow-offset) * -.5)) rotate(10deg);
}
}
/* And here's where the magic ends */
input,
label {
position: fixed;
top: .5rem;
color: #fff;
}
input {
left: .5rem;
}
label {
left: 2rem;
text-transform: capitalize;
}
@for $o from 1 through 7 {
.option:nth-of-type(#{$o}) {
$offset: $o - 1;
top: #{$offset * 2rem + .5rem};
}
}
View Compiled
// Inspired by the wonderful masks by Elio Qoshi: https://dribbble.com/shots/4127868-Minimal-Aku-Aku-Illustration
CSS.registerProperty({
'name': '--mouth',
'syntax': '<length>',
'initialValue': '.111em'
});
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.