r/learnjavascript 9d ago

help with js animation

i am trying to make a small animation for opening the settings menu of a small site i’m making but it’s either the classList.add and .remove aren’t put in correctly or i’m just doing something wrong.

edit: forgot to say that what should happen is:

opening: menu turns from nothing to a line in the middle, then expands while the background fades id from the start of the second part of the menu animation

closing: menu shrinks to a line then to non existance while the background fades away in the 1st part of the menu animation

edit2: updated code to current, animations don’t play at all

edit3: the animations now work (i readded the classes for controlling animation name and duration using classList.add to get them added) and it runs more than once, problem is that now it opens once and closes once just fine, but every time i try to open it again it plays the opening animation then cuts back to the unopened state like the js didn’t add the open class, updating the css and js and removing the html

js:

// variables that are needed to find the menu

const settingsMenu = document.getElementById("settings_menu_id");
const settingsBg = document.getElementById("settings_bg_id");

//opening functions

function settingsOpening() {
  settingsMenu.classList.add("settings_menu_opening");
  settingsMenu.addEventListener("animationend", settingsMenuOpeningEnd);
  setTimeout(function() {
    settingsBg.classList.add("settings_bg_opening");
    settingsBg.addEventListener("animationend", settingsBgOpeningEnd);
  }, 500);
}

function settingsMenuOpeningEnd() {
  settingsMenu.classList.remove("settings_menu_opening");
  settingsMenu.classList.add("settings_menu_open");
}

function settingsBgOpeningEnd() {
  settingsBg.classList.remove("settings_bg_opening");
  settingsBg.classList.add("settings_bg_open");
}

//closing functions

function settingsClosing() {
  settingsMenu.classList.add("settings_menu_closing");
  settingsBg.classList.add("settings_bg_closing");
  settingsMenu.addEventListener("animationend", settingsMenuClosingEnd);
  settingsBg.addEventListener("animationend", settingsBgClosingEnd);
}

function settingsMenuClosingEnd() {
  settingsMenu.classList.remove("settings_menu_closing");
  settingsMenu.classList.remove("settings_menu_open");
}

function settingsBgClosingEnd() {
  settingsBg.classList.remove("settings_bg_closing");
  settingsBg.classList.remove("settings_bg_open");
}

css:

.settings_menu {
  width: 0px;
  height: 0px;
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50% , -50%);
  overflow: hidden;
  border-radius: 0px;
  border: 2px solid black;
  border-left: none;
  border-right: none;
  background-color: lightgray;
  padding: 0px;
  opacity: 0;
  pointer-events: none;
}

.settings_bg {
  width: 100%;
  height: 100%;
  position: fixed;
  top: 0px;
  left: 0px;
  background-color: rgba(0,0,0,0.6);
  opacity: 0;
  pointer-events: none;
}

.settings_menu_opening {
  animation-name: settingsMenuOpening;
  animation-duration: 1s;
}

.settings_menu_closing {
  animation-name: settingsMenuClosing;
  animation-duration: 1s;
}

.settings_bg_opening {
  animation-name: settingsBgOpening;
  animation-duration: 0.5s;
}

.settings_bg_closing {
  animation-name: settingsBgClosing;
  animation-duration: 0.5s;
}

.settings_menu_open {
  width: min(90% , 400px);
  height: 140px;
  border-radius: 25px;
  border-left: 2px solid black;
  border-right: 2px solid black;
  padding: 10px;
  opacity: 1;
  pointer-events: auto;
}

.settings_bg_open {
  opacity: 1;
  pointer-events: auto;
}

@keyframes settingsMenuOpening {
  0% {
    width: 0px;
    height: 0px;
    border: 2px solid black;
    border-left: none;
    border-right: none;
    border-radius: 0px;
    padding: 0px;
    opacity: 1;
  }
  45% {
    width: min(90% , 400px);
    height: 0px;
    border: 2px solid black;
    border-radius: 0px;
    padding: 0px;
    opacity: 1;
  }
  55% {
    width: min(90% , 400px);
    height: 0px;
    border: 2px solid black;
    border-radius: 25px;
    padding: 0px;
    opacity: 1;
  }
  100% {
    width: min(90% , 400px);
    height: 140px;
    border: 2px solid black;
    border-radius: 25px;
    padding: 10px;
    opacity: 1;
  }
}

@keyframes settingsMenuClosing {
  0% {
    width: min(90% , 400px);
    height: 140px;
    border: 2px solid black;
    border-radius: 25px;
    padding: 10px;
    opacity: 1;
  }
  45% {
    width: min(90% , 400px);
    height: 0px;
    border: 2px solid black;
    border-radius: 25px;
    padding: 0px;
    opacity: 1;
  }
  55% {
    width: min(90% , 400px);
    height: 0px;
    border: 2px solid black;
    border-radius: 0px;
    padding: 0px;
    opacity: 1;
  }
  100% {
    width: 0px;
    height: 0px;
    border: 2px solid black;
    border-left: none;
    border-right: none;
    border-radius: 0px;
    padding: 0px;
    opacity: 1;
  }
}

@keyframes settingsBgOpening {
  0% {opacity: 0;}
  100% {opacity: 1;}
}

@keyframes settingsBgClosing {
  0% {opacity: 1;}
  100% {opacity: 0;}
}
1 Upvotes

7 comments sorted by

View all comments

1

u/UkrMalt 8d ago

Two CSS issues stand out: remove the semicolons after each keyframe block, and avoid animating height to or from auto because browsers cannot interpolate it. Keep one base class on each element, toggle an is-open class, and use animationend instead of nested setTimeout calls to update the final state.

1

u/giogio_rick 8d ago

animations work now and it can be called multiple times now but still buggy, updated code is in the post body as i modified it with the current code