<!-- beloved hamburger button -->
<button aria-label="Toggle Navigation">
<svg viewBox="-50 -40 100 80" width="50" height="40">
<defs>
<path id="line" fill="none" stroke="currentColor" stroke-width="15" stroke-linecap="round" d="M -40 0 h 80" />
</defs>
<g>
<g class="translate" transform="translate(0 -30)">
<g class="rotate" transform="rotate(-45)">
<use transform="rotate(45)" href="#line" />
</g>
</g>
<g class="rotate" transform="rotate(45)">
<use transform="rotate(-45)" href="#line" />
</g>
<g class="translate" transform="translate(0 30)">
<g class="rotate" transform="rotate(-45)">
<use transform="rotate(45)" href="#line" />
</g>
</g>
</g>
</svg>
</button>
<!-- navigation wrapping text elements within anchor elements -->
<nav>
<svg viewBox="0 0 500 400" width="500" height="400">
<defs>
<path id="path" d="M -150 60 q 50 -20 100 0 t 100 0 100 0 100 0 100 0 100 0 100 0 100 0" fill="none" />
</defs>
<g transform="translate(0 0)">
<a href="#home">
<text>
<textPath text-anchor="middle" href="#path" startOffset="0%">
Home
</textPath>
</text>
</a>
</g>
<g transform="translate(0 100)">
<a href="#about">
<text>
<textPath text-anchor="middle" href="#path" startOffset="100%">
About
</textPath>
</text>
</a>
</g>
<g transform="translate(0 200)">
<a href="#contact">
<text>
<textPath text-anchor="middle" href="#path" startOffset="0%">
Contact
</textPath>
</text>
</a>
</g>
<g transform="translate(0 300)">
<a href="#dance">
<text>
<textPath text-anchor="middle" href="#path" startOffset="100%">
Dance
</textPath>
</text>
</a>
</g>
</svg>
</nav>
@import url("https://fonts.googleapis.com/css?family=Chango&display=swap");
* {
box-sizing: border-box;
padding: 0;
margin: 0;
}
body {
background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 30' opacity='0.2' width='80' height='60'%3E%3Cpath d='M 0 15 q 10 -7 20 0 t 20 0' fill='none' stroke='hsl(0, 0%25, 100%25)' stroke-linecap='round' stroke-width='2' /%3E%3C/svg%3E"), #fb1f34;
color: hsl(0, 0%, 100%);
background-position-x: 50%;
background-size: 50px;
/* center the navigation in the viewport */
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
/* position the hamburger button in the top right corner */
button {
position: absolute;
top: 1rem;
right: 1rem;
width: 4rem;
height: 4rem;
background: none;
border: none;
color: inherit;
padding: 0.5rem;
}
button:focus {
outline-color: currentColor;
}
/* when the button is toggled to .open, update the group elements to toggle between the hamburger and x symbol */
button svg {
width: 100%;
height: auto;
display: block;
filter: drop-shadow(5px 5px hsl(0, 0%, 20%));
}
button .translate {
transition: transform 0.25s ease-in-out;
transition-delay: 0.25s;
}
button .rotate {
transition: transform 0.25s ease-in-out;
transition-delay: 0s;
}
button.open .translate {
transform: translateY(0);
transition-delay: 0s;
}
button.open .rotate {
transform: rotate(0);
transition-delay: 0.25s;
}
/* expand the nav to consider the entire height/width, whichever's smaller */
nav {
width: 100vmin;
visibility: hidden;
}
nav svg {
width: 100%;
height: auto;
display: block;
}
nav svg text {
text-shadow: 0px 0.2rem hsl(0, 0%, 20%);
font-family: "Chango", cursive;
fill: currentColor;
font-size: 2.255rem;
letter-spacing: 0px;
transition-property: letter-spacing, text-shadow;
transition-duration: 0.5s;
transition-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
/* on hover/focus update the style of the text */
nav svg a {
color: inherit;
outline: none;
}
nav svg a:hover text,
nav svg a:focus text {
letter-spacing: 5px;
text-shadow: 0px 0.5rem hsl(0, 0%, 20%);
}
const button = document.querySelector('button');
const nav = document.querySelector('nav');
// toggle a class of open on the button and nav element
button.addEventListener('click', () => {
nav.classList.toggle('open');
button.classList.toggle('open');
const isOpen = nav.classList.contains('open');
// animate the text path to move in/out
anime({
targets: 'textPath',
startOffset: (d, i) => {
if (isOpen) {
return i % 2 === 0 ? '60%' : '40%';
}
return i % 2 === 0 ? '0%' : '100%';
},
duration: 2500,
// slight delay for the opening animation, to follow the hamburger menu
delay: isOpen ? 200 + anime.stagger(50) : anime.stagger(50),
// considering the class on the nav element, toggle its visibility to prevent focus events
begin: () => {
if (nav.classList.contains('open')) {
nav.style.visibility = 'visible';
}
},
complete: () => {
if (!nav.classList.contains('open')) {
nav.style.visibility = 'hidden';
}
},
});
});
This Pen doesn't use any external CSS resources.