Tom
Tom

Reputation: 4033

HTML Hamburger - how to form proper X

I'm trying to build an animated hamburger using css. To do so I use three different span and animate on click - nothing special.

But somehow the transform-origin whatsoever is messed up, hence I can't form a proper X. How can I do so?

let active = false;

const handleNav = () => {
  const hamburger = document.querySelector(".hamburger");
  if (!active) {
    hamburger.classList.add("is-active");
  } else {
    hamburger.classList.remove("is-active");
  }
  
  active = !active;
}
.hamburger {
  width: 25px;
  cursor: pointer;
}

span {
    display: block;
    width: 100%;
    height: 2px;
    background-color: black;
    margin-bottom: 4px;
    transform-origin: 0 50%;
    transition: all 0.3s;
}

span:last-child {
  margin-bottom: 0;
}

.is-active span:first-child {
  transform: rotate(45deg);
}

.is-active span:nth-child(2) {
  width: 0;
}

.is-active span:last-child {
  transform: rotate(-45deg);
}
<div class="hamburger" onclick="handleNav()">
    <span></span>
    <span></span>
    <span></span>
</div>

Upvotes: 1

Views: 99

Answers (3)

upender
upender

Reputation: 180

One way is to hide the hamburger and display close icon.

Other way is to calculate the width required to make a perfect close icon and set width when active. Here width is around 17. See the below code.

let active = false;

const handleNav = () => {
  const hamburger = document.querySelector(".hamburger");
  if (!active) {
    hamburger.classList.add("is-active");
  } else {
    hamburger.classList.remove("is-active");
  }
  
  active = !active;
}
.hamburger {
  width: 25px;
  cursor: pointer;
}

span {
    display: block;
    width: 100%;
    height: 2px;
    background-color: black;
    margin-bottom: 4px;
    transform-origin: 0 50%;
    transition: all 0.3s;
}

span:last-child {
  margin-bottom: 0;
}

.is-active span:first-child {
  transform: rotate(45deg);
  width: 17px
}

.is-active span:nth-child(2) {
  width: 0;
}

.is-active span:last-child {
  transform: rotate(-45deg);
  width: 17px
}
<div class="hamburger" onclick="handleNav()">
    <span></span>
    <span></span>
    <span></span>
</div>

Upvotes: 2

Ankit Beniwal
Ankit Beniwal

Reputation: 529

If you can make minor changes in design then change height and margin-bottom of span.

span{
    height: 3px;
    margin-bottom: 6px;
}

or slightly translate first and last bar:

.is-active span:first-child {
  transform: rotate(45deg) translate(0,-3px);
}

.is-active span:last-child {
  transform: rotate(-45deg) translate(0,3px);
}

Upvotes: 0

ROOT
ROOT

Reputation: 11622

As mentioned in the comment, you have to change transform-origin for the <span>s to the right value, here is a snippet:

let active = false;

const handleNav = () => {
  const hamburger = document.querySelector(".hamburger");
  if (!active) {
    hamburger.classList.add("is-active");
  } else {
    hamburger.classList.remove("is-active");
  }
  
  active = !active;
}
.hamburger {
  width: 25px;
  cursor: pointer;
}

span {
    display: block;
    width: 100%;
    height: 2px;
    background-color: black;
    margin-bottom: 4px;
    transform-origin: 17%;
    transition: all 0.3s;
}

span:last-child {
  margin-bottom: 0;
}

.is-active span:first-child {
  transform: rotate(45deg);
}

.is-active span:nth-child(2) {
  width: 0;
}

.is-active span:last-child {
  transform: rotate(-45deg);
}
<div class="hamburger" onclick="handleNav()">
    <span></span>
    <span></span>
    <span></span>
</div>

Upvotes: 0

Related Questions