Search code examples
javascripthtmlcsscss-transitionsdom-manipulation

Trying to Execute CSS Transitions thru JavaScript Won't Work


CSS transitions aren't working for me when I try to execute them through JavaScript.

let isSearchBarOpen = false;

function toggleSearchBar() {
  if (isSearchBarOpen) {
    searchBar.style.display = "none";
  } else {
    searchBar.style.display = "flex";
    searchBar.classList.add("search-bar-open")
  }
  isSearchBarOpen = !isSearchBarOpen;

  toggleSearchIcon();
}
.search-bar {
  display: none;
  background-color: #000;
  color: #fff;
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  padding: 10px 5px;
  z-index: 1000;
  margin: 0 auto;
  transition: top 2s ease-in;
}

.search-bar-open {
  top: 90px;
}
<div class="search-icon">
  <i class="fas fa-search search-icon-header"></i>
  <img src="images/close-icon.svg" alt="close-icon-search" class="close-icon-search">
</div>
<div class="search-bar" id="search-bar">
  <div class="search-container">
    <form class="search-form">
      <input type="text" placeholder="Search...">
      <button type="submit"><i class="fas fa-search search-icon-action"></i></button>
    </form>
  </div>
</div>

When the search button is clicked, the following things happen (or should happen if I am not wrong):

  1. The function checks if isSearchBarOpen is true or false.
  2. If true —that is, if the search bar is open—, an inline style is added (display:none) hiding the bar.
  3. If it is false — that is, if the search bar is closed — an inline style is added (display:flex) so that it show up. And, in addition, a class is added (.search-bar-open).

From there, if we look at the CSS…

  1. The search bar, when opened (when it shows up), loads the .search-bar-open class and the display:flex inline style. On the one hand, said inline style overrides the display:none CSS property applied through the .search-bar class by specificity.

  2. And, in addition, the .search-bar-open class is added.

  3. Now, I assume that, when the .search-bar-open class is applied, the transition stipulated within .search-bar should occur, that is:

a. I'm in top:0;

b. And in 2 seconds with ease-in

c. I am set top:90px;.

Something I must've misunderstood, since it is not working :-(


Solution

  • If you use JS to make an element visible AND add a class to trigger a transition, it will not work because JS does both those actions at the same time. A transition will trigger if a property is changed on an element, but done like this, the top property is never changed, it was already there when the element was made visible.

    You can add a JS action in between to trigger a browser 'reflow'. That way the browser makes the element visible first, draws that element on the page, and then adds the class to trigger the transition.

    searchBar.style.display = "flex";
    searchBar.offsetWidth;
    searchBar.classList.add("search-bar-open")