Trying to Execute CSS Transitions thru JavaScript Won't Work

57 Views Asked by At

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 :-(

3

There are 3 best solutions below

1
Rene van den Berg On BEST ANSWER

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")
1
Junaid Shaikh On

the problem is that transitions does not work for display: none properties, instead of doing display none to flex, just do something to hide search bar without doing display: none;

one possible solution is to give negative top value to remove from visible window like top: -50px (or you can give exact value as the height of your searchbar)

let isSearchBarOpen = false;

    function toggleSearchBar() {
          if (isSearchBarOpen) {
            searchBar.style.top= "-50px";   //here used top instead of display
          } else {
             searchBar.classList.add("search-bar-open")
          }
          isSearchBarOpen = !isSearchBarOpen;
            
          toggleSearchIcon();
      }

.search-bar {
    display: flex;      //here let it to be flex
    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; 
}
1
Swalih T On

The transition not work for display:none. So, instead of transition use animation.

example code:

CSS:

       .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;
            animation: toggleOnAnimation 2s ease-in;
        }

        .search-bar-open {
            top: 90px;
        }

        @keyframes toggleOnAnimation {
            0% {
                top: 0
            }

            100% {
                top: 90px
            }
        }

Javascript:

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

        }

HTML:

    <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"> -->
        <button onclick="toggleSearchBar()">Click</button>
    </div>
    <div class="search-bar" id="search-bar">
        <div class="search-container">
            <form class="search-form">
                <input type="text" placeholder="Search...">
                <button type="submit">
                    Submit
                </button>
            </form>
        </div>
    </div>

Here, I used animation instead of transition. Hope you undertand :)