Jan 2024
Animated Nav Menu
Anyone else remember when Apple switched their site to be responsive, which was controversial since iPhones were capabale of viewing full-size page content? Here I recreate the other controversy of that launch: the two-line navicon that they still use.
<html>
<head>
<style>
@keyframes flip-top-forward {
0% { transform: none } 50% { transform: var(--translate-top) } 100% { transform: var(--translate-top) var(--rotate-top) } }
@keyframes flip-bottom-forward {
0% { transform: none } 50% { transform: var(--translate-bottom) } 100% { transform: var(--translate-bottom) var(--rotate-bottom) } }
@keyframes flip-top-reverse {
0% { transform: var(--translate-top) var(--rotate-top) } 50% { transform: var(--translate-top) } 100% { transform: none } }
@keyframes flip-bottom-reverse {
0% { transform: var(--translate-bottom) var(--rotate-bottom) } 50% { transform: var(--translate-bottom) } 100% { transform: none } }
:root {
--translate-top: translate(0px,7px); --translate-bottom: translate(0px,-8px); --rotate-top: rotate(-45deg); --rotate-bottom: rotate(45deg) }
body {
background: #f1f1f1; display: flex; align-items: center; justify-content: center }
svg {
cursor: pointer; color: #9c9c9c }
#line-top {
transform-origin: 16px 7px }
#line-bottom {
transform-origin: 16px 22px }
svg.active > #line-top {
animation: 0.2s flip-top-forward ease-in-out;
transform: var(--translate-top) var(--rotate-top) }
svg.active > #line-bottom {
animation: 0.2s flip-bottom-forward ease-in-out;
transform: var(--translate-bottom) var(--rotate-bottom) }
svg.reverse > #line-top {
animation: 0.2s flip-top-reverse ease-in-out;
transform: none }
svg.reverse > #line-bottom {
animation: 0.2s flip-bottom-reverse ease-in-out;
transform: none }
</style>
<script>
class App {
constructor(){
document.addEventListener('DOMContentLoaded',this.handleContentLoaded.bind(this));
}
handleContentLoaded(){
this.svg = document.getElementById('svg');
this.svg.addEventListener('click',this.handleClickSvg.bind(this));
}
handleClickSvg(event){
const is_active = this.svg.classList.contains('active')
this.svg.classList = is_active ? 'reverse' : 'active';
}
}
const app = new App();
</script>
</head>
<body>
<svg id="svg" width="64" viewbox="0 0 32 28">
<rect id="line-top" x="0" y="5" width="32" height="4" rx="1" fill="currentColor" />
<rect id="line-bottom" x="0" y="20" width="32" height="4" rx="1" fill="currentColor" />
</svg>
</body>
</html>
I created the SVG using rectangles, and then setup CSS animations for the transition between states. Binding to the click event, I can toggle the direction of the animation with Javascript by specififying a specific class name.