Skip to content

Instantly share code, notes, and snippets.

@aldoyh
Created October 15, 2025 06:13
Show Gist options
  • Select an option

  • Save aldoyh/8bc774413db38ed1988e3eab5a09c5eb to your computer and use it in GitHub Desktop.

Select an option

Save aldoyh/8bc774413db38ed1988e3eab5a09c5eb to your computer and use it in GitHub Desktop.
404 Error Face
<main>
<svg class="face" viewBox="0 0 320 380" width="320px" height="380px" aria-label="A 404 becomes a face, looks to the sides, and blinks. The 4s slide up, the 0 slides down, and then a mouth appears.">
<g
fill="none"
stroke="currentcolor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="25"
>
<g class="face__eyes" transform="translate(0, 112.5)">
<g transform="translate(15, 0)">
<polyline class="face__eye-lid" points="37,0 0,120 75,120" />
<polyline class="face__pupil" points="55,120 55,155" stroke-dasharray="35 35" />
</g>
<g transform="translate(230, 0)">
<polyline class="face__eye-lid" points="37,0 0,120 75,120" />
<polyline class="face__pupil" points="55,120 55,155" stroke-dasharray="35 35" />
</g>
</g>
<rect class="face__nose" rx="4" ry="4" x="132.5" y="112.5" width="55" height="155" />
<g stroke-dasharray="102 102" transform="translate(65, 334)">
<path class="face__mouth-left" d="M 0 30 C 0 30 40 0 95 0" stroke-dashoffset="-102" />
<path class="face__mouth-right" d="M 95 0 C 150 0 190 30 190 30" stroke-dashoffset="102" />
</g>
</g>
</svg>
</main>
* {
border: 0;
box-sizing: border-box;
margin: 0;
padding: 0;
}
:root {
--hue: 223;
--sat: 10%;
--light: hsl(var(--hue), var(--sat), 95%);
--dark: hsl(var(--hue), var(--sat), 5%);
--trans-dur: 0.3s;
color-scheme: light dark;
font-size: clamp(1rem, 0.95rem + 0.25vw, 1.25rem);
}
body {
background-color: light-dark(var(--light), var(--dark));
color: light-dark(var(--dark), var(--light));
font: 1em / 1.5 sans-serif;
display: grid;
place-items: center;
height: 100vh;
transition:
background-color var(--trans-dur),
color var(--trans-dur);
}
main {
padding: 1.5em 0;
}
.face {
display: block;
width: 12em;
height: auto;
&__eyes,
&__eye-lid,
&__mouth-left,
&__mouth-right,
&__nose,
&__pupil {
animation: eyes 1s 0.3s cubic-bezier(0.65, 0, 0.35, 1) forwards;
}
&__eye-lid,
&__pupil {
animation: {
duration: 4s;
delay: 1.3s;
iteration-count: infinite;
};
}
&__eye-lid {
animation-name: eye-lid;
}
&__mouth-left,
&__mouth-right {
animation-timing-function: cubic-bezier(0.33, 1, 0.68, 1);
}
&__mouth-left {
animation-name: mouth-left;
}
&__mouth-right {
animation-name: mouth-right;
}
&__nose {
animation-name: nose;
}
&__pupil {
animation-name: pupil;
}
}
/* Animations */
@keyframes eye-lid {
from,
40%,
45%,
to {
transform: translateY(0);
}
42.5% {
transform: translateY(17.5px);
}
}
@keyframes eyes {
from {
transform: translateY(112.5px);
}
to {
transform: translateY(15px);
}
}
@keyframes pupil {
from,
37.5%,
40%,
45%,
87.5%,
to {
stroke-dashoffset: 0;
transform: translate(0, 0);
}
12.5%,
25%,
62.5%,
75% {
stroke-dashoffset: 0;
transform: translate(-35px, 0);
}
42.5% {
stroke-dashoffset: 35;
transform: translate(0, 17.5px);
}
}
@keyframes mouth-left {
from,
50% {
stroke-dashoffset: -102;
}
to {
stroke-dashoffset: 0;
}
}
@keyframes mouth-right {
from,
50% {
stroke-dashoffset: 102;
}
to {
stroke-dashoffset: 0;
}
}
@keyframes nose {
from {
transform: translate(0, 0);
}
to {
transform: translate(0, 22.5px);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment