Как идеально ровно нарисовать меню бургер в процентах
изучаю css с нуля и хочу вывести формулу чтобы всегда бургер преобразовывался в крестик, пытаюсь играть translateY, но получается если чуть изменить он уже не преобразуется в крестик при нажатие, как можно задать данные параметр чтобы всегда образовывался идеально ровный крестик? сейчас он немножко кривой 
.hamb__field.active .bar:nth-child(1) {
transform: translateY(12px) rotate(45deg);
}
.hamb__field.active .bar:nth-child(3) {
transform: translateY(-12px) rotate(-45deg);
}
const hamb = document.querySelector("#hamb");
const popup = document.querySelector("#popup");
const menu = document.querySelector("#menu").cloneNode(1);
const body = document.body;
hamb.addEventListener("click", hambHandler);
function hambHandler(e) {
e.preventDefault();
popup.classList.toggle("open");
hamb.classList.toggle("active");
body.classList.toggle("noscroll");
renderPopup();
}
function renderPopup() {
popup.appendChild(menu);
}
.container {
width: 100%;
max-width: 1000px;
margin: 0 auto;
height: 100%;
padding: 0 15px;
}
.navbar {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 75px;
background: #7a52b3;
}
/* меню бургер */
.hamb {
display: none;
}
/* расположение обьектов в меню бургер */
.popup {
display: none;
}
.menu {
display: flex;
}
.navbar__wrap .menu > li > a {
align-items: center;
padding: 0 20px;
color: rgba(255, 255, 255, 0.7);
}
@media (max-width: 1000px) {
.navbar__wrap .menu {
display: none;
}
.hamb {
display: flex;
align-items: center;
}
.hamb__field {
padding: 10px 20px;
cursor: pointer;
}
.bar {
display: block;
width: 30px;
height: 4px;
margin: 6px auto;
background-color: #fff;
transition: 0.2s;
}
.popup {
position: fixed;
top: 75px;
left: -100%;
width: 100%;
height: 100%;
background-color: #fff;
z-index: 100;
display: flex;
transition: 0.3s;
}
.popup.open {
left: 0;
}
/* контент в меню бургере */
.popup .menu {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: start;
padding: 50px 0;
overflow: auto;
}
/* контент в меню бургере */
.popup .menu > li > a {
width: 100%;
display: flex;
justify-content: center;
padding: 20px 0;
font-size: 20px;
font-weight: bold;
color: #3f3f3f;
}
.hamb__field.active .bar:nth-child(2) {
opacity: 0;
}
.hamb__field.active .bar:nth-child(1) {
transform: translateY(12px) rotate(45deg);
}
.hamb__field.active .bar:nth-child(3) {
transform: translateY(-12px) rotate(-45deg);
}
body.noscroll {
overflow: hidden;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="style.css" />
<title>Adaptive header for site</title>
</head>
<body>
<nav class="navbar">
<div class="container">
<div class="navbar__wrap">
<div class="hamb">
<div class="hamb__field" id="hamb">
<span class="bar"></span>
<span class="bar"></span>
<span class="bar"></span>
</div>
</div>
<ul class="menu" id="menu">
<li><a href="#">Home</a></li>
<li><a href="#">Benefits</a></li>
<li><a href="#">Prices</a></li>
<li><a href="#">Blog</a></li>
<li><a href="#">About us</a></li>
<li><a href="#">Contact</a></li>
</ul>
</div>
</div>
</nav>
<div class="popup" id="popup"></div>
<script src="script.js"></script>
</body>
</html>
Ответы (2 шт):
В процентах на все случаи жизни не подскажу, но подскажу как сделать в вашем случае.
И так у нас есть 3 полоски, при нажатии мы скрываем тот что по середине и поворачиваем 1-ый и 3-ий на 45 и -45 градусов соответственно. Теперь всё что нам надо это совместить центры полосок, после поворота, но это тоже самое что совместить центры и без поворота, т.е. наложить их друг на друга, потому что поворот происходит относительно центра полосок. А чтобы их совместить нам нужно знать расстояние между полосками (margin) и высоту полосок (height). Обе переменные нам известны - это 6px и 4px соответственно. значит нам надо первую сместить на сумму height + margin, а вторую на -(height + margin). Ниже пример как я это релизовал:
const hamb = document.querySelector("#hamb");
const popup = document.querySelector("#popup");
const menu = document.querySelector("#menu").cloneNode(1);
const body = document.body;
hamb.addEventListener("click", hambHandler);
function hambHandler(e) {
e.preventDefault();
popup.classList.toggle("open");
hamb.classList.toggle("active");
body.classList.toggle("noscroll");
renderPopup();
}
function renderPopup() {
popup.appendChild(menu);
}
:root {
--menu-line-vertical-margin: 6px;
--menu-line-height: 4px;
--offsetY: calc(var(--menu-line-vertical-margin) + var(--menu-line-height));
}
.container {
width: 100%;
max-width: 1000px;
margin: 0 auto;
height: 100%;
padding: 0 15px;
}
.navbar {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 75px;
background: #7a52b3;
}
/* меню бургер */
.hamb {
display: none;
}
/* расположение обьектов в меню бургер */
.popup {
display: none;
}
.menu {
display: flex;
}
.navbar__wrap .menu>li>a {
align-items: center;
padding: 0 20px;
color: rgba(255, 255, 255, 0.7);
}
@media (max-width: 1000px) {
.navbar__wrap .menu {
display: none;
}
.hamb {
display: flex;
align-items: center;
}
.hamb__field {
padding: 10px 20px;
cursor: pointer;
}
.bar {
display: block;
width: 30px;
height: var(--menu-line-height);
margin: var(--menu-line-vertical-margin) auto;
background-color: #fff;
transition: 0.2s;
}
.popup {
position: fixed;
top: 75px;
left: -100%;
width: 100%;
height: 100%;
background-color: #fff;
z-index: 100;
display: flex;
transition: 0.3s;
}
.popup.open {
left: 0;
}
/* контент в меню бургере */
.popup .menu {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: start;
padding: 50px 0;
overflow: auto;
}
/* контент в меню бургере */
.popup .menu>li>a {
width: 100%;
display: flex;
justify-content: center;
padding: 20px 0;
font-size: 20px;
font-weight: bold;
color: #3f3f3f;
}
.hamb__field.active .bar:nth-child(2) {
opacity: 0;
}
.hamb__field.active .bar:nth-child(1) {
transform: translate(0, var(--offsetY)) rotate(45deg);
}
.hamb__field.active .bar:nth-child(3) {
transform: translate(0, calc(-1 * var(--offsetY))) rotate(-45deg);
}
body.noscroll {
overflow: hidden;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="style.css" />
<title>Adaptive header for site</title>
</head>
<body>
<nav class="navbar">
<div class="container">
<div class="navbar__wrap">
<div class="hamb">
<div class="hamb__field" id="hamb">
<span class="bar"></span>
<span class="bar"></span>
<span class="bar"></span>
</div>
</div>
<ul class="menu" id="menu">
<li><a href="#">Home</a></li>
<li><a href="#">Benefits</a></li>
<li><a href="#">Prices</a></li>
<li><a href="#">Blog</a></li>
<li><a href="#">About us</a></li>
<li><a href="#">Contact</a></li>
</ul>
</div>
</div>
</nav>
<div class="popup" id="popup"></div>
<script src="script.js"></script>
</body>
</html>
В процентах тоже можно. Для этого нужно бары обернуть в еще один div и добавить overflow: hidden в обёртку, чтобы отступы (margins) не схлопывались:
let humbs = document.querySelectorAll('.humb');
[...humbs].map(el => el.addEventListener('click', function(e) {
this.classList.toggle('active');
}));
.humb {
padding: 5px;
background: #7a52b3;
overflow: hidden;
margin-bottom: 1em;
}
.bar-wrap {
transition: 0.2s;
overflow: hidden;
}
.bar {
display: block;
width: 30px;
height: 4px;
margin: 3px auto;
background-color: #fff;
}
.v2 {
width: 70px;
height: 10px;
margin: 8px auto;
}
.active .bar-wrap:nth-child(1) {
transform: translate(0, 100%) rotate(45deg);
}
.active .bar-wrap:nth-child(3) {
transform: translate(0, -100%) rotate(-45deg);
}
.active .bar-wrap:nth-child(2) {
opacity: 0;
}
<div class="humb">
<div class="bar-wrap"><span class="bar"></span></div>
<div class="bar-wrap"><span class="bar"></span></div>
<div class="bar-wrap"><span class="bar"></span></div>
</div>
<div class="humb">
<div class="bar-wrap"><span class="bar v2"></span></div>
<div class="bar-wrap"><span class="bar v2"></span></div>
<div class="bar-wrap"><span class="bar v2"></span></div>
</div>