Меню гамбургер

Дата публикации 02.01.2019

Меню вида гамбургер. Демо: http://demo.umi-cms.spb.su/hamburger/

Отличается от известных мне аналогов тем, что позволяет изменять размеры гамбургера с сохранением пропорций изменением только одним изменением ширины контейнера.

Иконка гамбургера и меню находятся в независимых контейнерах, что позволяет произвольно размещать их на странице.

HTML

	
	

	
	

LESS


/* -- Appearance -- */
.menu-hamburger-icon-wrapper {
    width: 4em;
	left: 1em;
	top: 2em;

	&:before {
		padding-bottom: 64%;
	}	

	.menu-hamburger-icon {		
		span {			
			i {
				background-color: #ececec;
				border-radius: 5px;  
			}		
		}
	}
}



.menu-hamburger {
	min-width: 100px;
	background: transparent;
	top: 5.2em;
	left: 0;

	ul {
		background-color: #cecece;
		padding: 0;

		li {
			padding: 1vh 3em;
			border-bottom: 1px solid #a0a0a0;
			cursor: pointer;			
			letter-spacing: .1em;
			transition: text-shadow .3s;
			opacity: 0.7;
			
			&:last-child {
				border: none;
			}
			
			&.active,
			&:hover {
				text-shadow: 0 0 .3px #2a2a2a, 0 0 .3px #2a2a2a;
				opacity: 1;
			}

			span {
				color: #2a2a2a;
				font-size: 1.4em;
				text-transform: uppercase;				
			}
		}
	}
}


/* -- Layout. Don't edit this rules -- */
.menu-hamburger-icon-wrapper {
    position: absolute;
    height: auto;
	z-index: 101;

	&:before {
		width:100%;
		display: block;
		content: '';
	}	

	.menu-hamburger-icon {
		width: 100%;
		height: 100%;
		position: absolute;
		top:0;
		left: 0;
		
		span {
			position: absolute;	
			left:0;
			width: 100%;
			height: 50%;
			display: flex;
			flex-direction: column;
			justify-content: space-between;
			align-items: center;
			cursor: pointer;
			
			i {
				display: block;
				width: 100%;
				height: 36%; 
				position: relative;  
				transform-origin: 50% 50%;  
			}		
		
			&:first-child {
				top: 0;
				
				i:first-child {
					transition: opacity 0.55s ease;
					will-change: transform;
				}
				
				i:last-child {
					position: relative;
					top: 18%;
					transition: transform 0.5s cubic-bezier(0.77,0.2,0.05,1.0),
								background 0.5s cubic-bezier(0.77,0.2,0.05,1.0),
								opacity 0.55s ease;
				}
			}
			
			&:last-child {
				top: 50%;
				
				i:first-child {
					position: relative;
					top: -18%;
					transition: transform 0.5s cubic-bezier(0.77,0.2,0.05,1.0),
								background 0.5s cubic-bezier(0.77,0.2,0.05,1.0),
								opacity 0.55s ease;
				}
				
				i:last-child {
					transition: opacity 0.55s ease;
				}
			}			
		}		
		
		&.checked span {
			&:first-child {
				i {
					&:first-child {
					  opacity: 0;
					  transform: none;
					}

					&:last-child {
					  transform: rotate(-45deg) translate(0, 0);
					}
				}
			}
			&:last-child {
				i {
					&:first-child {
					  opacity: 1;
					  transform: rotate(45deg) translate(0,0);
					}

					&:last-child {
					  opacity: 0;
					  transform: none;
					}
				}
			}			
		}		
	}
}



.menu-hamburger {
	position: absolute;
	transform-origin: 0% 0%;
	transform: translate(-100%, 0%);	  
	transition: transform 0.5s cubic-bezier(0.77,0.2,0.05,1.0);
	z-index: 100;

	ul {
		width: 100%;	  
		list-style-type: none;
		font-smoothing: antialiased;
		opacity: 1;
	}

	&.checked {
		transform: none;
		
		ul {
			opacity: 1;
		}
	}
}

JS

'use strict';

document.addEventListener('DOMContentLoaded', function(){
	new Hamburger();
});

class Hamburger {
	constructor() {		
		let container = document.querySelector('#menu-hamburger');
		let icon = document.querySelector('#menu-hamburger-icon');
		
		icon.addEventListener('click', (event) => {
			container.classList.toggle('checked');
			icon.classList.toggle('checked');
		});
		
		container.addEventListener('click', (event) => {
			let target = event.target;
			if (target.nodeName == 'SPAN' || target.nodeName == 'LI') {
				container.classList.toggle('checked');
				icon.classList.toggle('checked');
			}
		});		
	}	
}