Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly animate a bar gliding?

I have two buttons, when a user clicks on them it gets underlined. However, I'd like the .underline to be animated/glide horizontally to the button that is being clicked on.

Demo: https://jsfiddle.net/ds1wr736/11/

As of right now, the .underline just appears and disapears when a button is clicked. How can I animate this to smoothly glide (x values changing) to the selected button without hacks and JQuery?

function switchTab(tab) {
  if (tab === 1) {
    document.getElementById("tab2").classList.add("underline");
    document.getElementById("tab1").classList.remove("underline");
  }
  else if (tab === 2) {
    document.getElementById("tab1").classList.add("underline");
    document.getElementById("tab2").classList.remove("underline");
  }
}
.bar {
  background-color: gray;
  padding: 20px;
}

.underline {
  border-bottom: 5px solid red;
}

button {
  width: 100px;
  height: 50px;
  background-color: white;
}

button:focus {
  outline: none;
}
<div class="bar">
  <button id='tab1' class="underline" onclick='switchTab(2)'>Tab 1</button>
  <button id='tab2' onclick='switchTab(1)'>Tab 2</button>
</div>
like image 239
javanumero Avatar asked Mar 19 '18 18:03

javanumero


2 Answers

Rather than animating a border I've created an additional element that reacts to the the click events. This allows us to track the position of the "underline" and scale and animate it between buttons when clicked.

This can be modified to accept hover events instead using mouseover instead of click.

let buttons = document.querySelectorAll('button');

buttons.forEach(button => {
  button.addEventListener('mouseover', hoverboard); // Hover event
  //button.addEventListener('click', hoverboard);
});

function hoverboard(e) {

  const board = document.querySelector('.hoverboard');
  // - 1 due to the border of the button
  let width = this.offsetWidth - 1;
  const firstChild = document.querySelector('.bar button:first-child');
  const lastChild = document.querySelector('.bar button:last-child');
  // - 19 due to padding being 20px on the left and removing 1 for the button's border
  let left = this.offsetLeft - 19;

  board.style.cssText = 'transform: translateX(' + left + 'px); width: ' + width + 'px;';

}
.bar {
  position: relative;
  background-color: gray;
  padding: 20px;
}

.underline {
  border-bottom: 5px solid red;
}

button {
  width: 100px;
  height: 50px;
  background-color: white;
}

button:focus {
  outline: none;
}

.hoverboard {
  position: absolute;
  width: 100px;
  height: 3px;
  background: red;
  transition: transform .25s ease, width .25s ease;
}
<div class="bar">
  <button id='tab1'>Tab 1</button>
  <button id='tab2' style="width: 65px;">Tab 2</button>
  <button>Tab 3</button>
  <div class="hoverboard"></div>
</div>
like image 135
Wild Beard Avatar answered Oct 22 '22 01:10

Wild Beard


Here ya go. Only the edited classes are here:

.underline:after {
  border-bottom: 5px solid red;
  animation-name: slideIn;
  animation-duration: 1s;
  width: 100%;
  content: '';
  position: absolute;
  bottom: 0;
  left: 0;
}

@keyframes slideIn {
    from {width: 0;}
    to {width: 100%;}
}

button{
  position: relative;
  width: 100px;
  height: 50px;
  background-color: white;
}

What I did is that I used the abstract after element on the buttons and positioned it absolute to it's relative button. And used css animation.

like image 20
Georgios Dimitriadis Avatar answered Oct 22 '22 01:10

Georgios Dimitriadis