Surprising pause in the menu transition animation

Currently, I am in the process of developing a menu that seems to have some flaws. One issue is that it appears a bit choppy, but the more concerning problem is the half-second delay after clicking an item before it animates.

The concept behind this menu is that inactive menus are positioned off-screen to the right (right: -200px). When you click on any item, all "active" items will shift 20px to the left and activate the target menu.

Overall, the functionality is quite simple, but I am struggling to pinpoint the cause of the delay and choppiness.

$('.rmenu').on('click', '.item', function() {
  var targetid = $(this).data('target-id');
  var targetelement = $('#' + targetid);
  console.log('Clicked ' + targetid);
  if ($(this).data('target-type') === 'menu' && !targetelement.hasClass('active')) { //if target is a submenu and it's not already active
    $('.active').animate({
      'right': '+=20px'
    }); //move all "active" menus to the left a bit (stack behind)
    targetelement.addClass('active').animate({
      'right': '0px'
    }); //make new submenu active
  }
});

$('.rmenu').on('click', '.back', function() {
  var parentid = $(this).parent().data('parent-id');
  $(this).parent().parent().removeClass('active').css('right', '-200px');
  $('.active').animate({
    'right': '-=20px'
  });
})
body {
  background-color: darkgray;
  overflow: hidden;
}
#menu {
  position: absolute;
  bottom: 0;
  right: 0;
  width: 300px;
}
.rmenu {
  position: absolute;
  right: -200px;
  bottom: 0;
  width: 200px;
  transition: .2s;
  border: 1px solid gray;
}
.rmenu.active {
  right: 0;
}
.rmenu div {
  background-color: white;
  border-bottom: 1px solid gray;
}
.rmenu div:last-child {
  border: none;
}
.rmenu .title {
  text-align: center;
  padding: 5px;
  color: gray;
}
.rmenu .item {
  padding: 3px;
  cursor: pointer;
}
.rmenu .back {
  padding-right: 5px;
  cursor: pointer;
}
.rmenu .submenu-indicator {
  float: right;
  padding-right: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="menu">
  <!--main menu-->
  <div id="home" class="rmenu active">
    <div class="title">
      <span>Home</span>
    </div>
    <div data-target-id="items" data-target-type="menu" class="item">
      <span class="label">Items</span><span class="submenu-indicator">></span>
    </div>
    <div class="item">
      <span class="label">Social</span>
    </div>
    <div class="item">
      <span class="label">Settings</span>
    </div>
  </div>

  <!--items menu-->
  <div id="items" class="rmenu" data-parent-id="home">
    <div class="title">
      <span class="back"><</span><span>Items</span>
    </div>
    <div class="item" data-target-id="tables" data-target-type="menu">
      <span class="label">Tables</span><span class="submenu-indicator">></span>
    </div>
    <div class="item">
      <span class="label">Lamps</span>
    </div>
    <div class="item">
      <span class="label">Chairs</span>
    </div>
  </div>

  <!--tables menu-->
  <div id="tables" class="rmenu" data-parent-id="items">
    <div class="title">
      <span class="back"><</span><span>Tables</span>
    </div>
    <div class="item">
      <span class="label">1</span>
    </div>
    <div class="item">
      <span class="label">2</span>
    </div>
    <div class="item">
      <span class="label">3</span>
    </div>
    <div class="item">
      <span class="label">4</span>
    </div>
    <div class="item">
      <span class="label">5</span>
    </div>
    <div class="item">
      <span class="label">6</span>
    </div>
  </div>
</div>

Answer №1

Your CSS transition is conflicting with your jQuery animations. Both are attempting to animate the right attribute simultaneously, causing some erratic movement.

To fix this issue, I adjusted your CSS transition to only apply to elements that are not currently active. Additionally, I added the class .active after initiating the animation, which successfully resolved the problem.

.rmenu:not(.active) {
  transition: .2s;
}
targetelement.animate({
    'right': '0px'
}).addClass("active"); //Moved addClass() after animate()

$('.rmenu').on('click', '.item', function() {
  var targetid = $(this).data('target-id');
  var targetelement = $('#' + targetid);
  console.log('Clicked ' + targetid);
  if ($(this).data('target-type') === 'menu' && !targetelement.hasClass('active')) { 
    $('.active').animate({
      'right': '+=20px'
    }); 
    targetelement.animate({
      'right': '0px'
    }).addClass("active");
  }
});

$('.rmenu').on('click', '.back', function() {
  var parentid = $(this).parent().data('parent-id');
  $(this).parent().parent().removeClass('active').css('right', '-200px');
  $('.active').animate({
    'right': '-=20px'
  });
})
body {
  background-color: darkgray;
  overflow: hidden;
}

#menu {
  position: absolute;
  bottom: 0;
  right: 0;
  width: 300px;
}

.rmenu {
  position: absolute;
  right: -200px;
  bottom: 0;
  width: 200px;
  border: 1px solid gray;
}

.rmenu:not(.active) {
  transition: .2s;
}

.rmenu.active {
  right: 0;
  background-color: blue;
}

.rmenu div {
  background-color: white;
  border-bottom: 1px solid gray;
}

.rmenu div:last-child {
  border: none;
}

.rmenu .title {
  text-align: center;
  padding: 5px;
  color: gray;
}

.rmenu .item {
  padding: 3px;
  cursor: pointer;
}

.rmenu .back {
  padding-right: 5px;
  cursor: pointer;
}

.rmenu .submenu-indicator {
  float: right;
  padding-right: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="menu">
  <!--main menu-->
  <div id="home" class="rmenu active">
    <div class="title">
      <span>Home</span>
    </div>
    <div data-target-id="items" data-target-type="menu" class="item">
      <span class="label">Items</span><span class="submenu-indicator">></span>
    </div>
    <div class="item">
      <span class="label">Social</span>
    </div>
    <div class="item">
      <span class="label">Settings</span>
    </div>
  </div>

  <!--items menu-->
  <div id="items" class="rmenu" data-parent-id="home">
    <div class="title">
      <span class="back"><</span><span>Items</span>
    </div>
    <div class="item" data-target-id="tables" data-target-type="menu">
      <span class="label">Tables</span><span class="submenu-indicator">></span>
    </div>
    <div class="item">
      <span class="label">Lamps</span>
    </div>
    <div class="item">
      <span class="label">Chairs</span>
    </div>
  </div>

  <!--tables menu-->
  <div id="tables" class="rmenu" data-parent-id="items">
    <div class="title">
      <span class="back"><</span><span>Tables</span>
    </div>
    <div class="item">
      <span class="label">1</span>
    </div>
    <div class="item">
      <span class="label">2</span>
    </div>
    <div class="item">
      <span class="label">3</span>
    </div>
    <div class="item">
      <span class="label">4</span>
    </div>
    <div class="item">
      <span class="label">5</span>
    </div>
    <div class="item">
      <span class="label">6</span>
    </div>
  </div>
</div>

Answer №2

I modified this code to eliminate the use of $.animate() completely and avoid mentioning right due to performance concerns. The updated version accomplishes the same functionality purely through CSS, utilizing the transition property on the transform attribute.

function adjustOffset(direction) {
  var offset = 20,
      base = direction ? 0 : (0 - offset);
  $($('.active').get().reverse()).each(function() {
    $(this).css('transform','translateX(' + base + 'px)');
    base = base - offset;
  })
}

$('.item').on('click',function() {
  var $target = $('#'+$(this).attr('data-target-id'));
  adjustOffset();
  $target.toggleClass('active');
});

$('.back').on('click',function() {
  $(this).closest('.rmenu').removeClass('active').css('transform','');
  adjustOffset('back');
})
body {
  background-color: darkgray;
  overflow: hidden;
}
#menu {
  position: absolute;
  bottom: 0;
  right: 0;
  width: 300px;
}
.rmenu {
  position: absolute;
  right: 0;
  transform: translateX(100%);
  bottom: 0;
  width: 200px;
  transition: transform .2s;
  border: 1px solid gray;
}
.rmenu.active {
  transform: translateX(0);
}
.rmenu div {
  background-color: white;
  border-bottom: 1px solid gray;
}
.rmenu div:last-child {
  border: none;
}
.rmenu .title {
  text-align: center;
  padding: 5px;
  color: gray;
}
.rmenu .item {
  padding: 3px;
  cursor: pointer;
}
.rmenu .back {
  padding-right: 5px;
  cursor: pointer;
}
.rmenu .submenu-indicator {
  float: right;
  padding-right: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="menu">
  <!--main menu-->
  <div id="home" class="rmenu active">
    <div class="title">
      <span>Home</span>
    </div>
    <div data-target-id="items" data-target-type="menu" class="item">
      <span class="label">Items</span><span class="submenu-indicator">></span>
    </div>
    <div class="item">
      <span class="label">Social</span>
    </div>
    <div class="item">
      <span class="label">Settings</span>
    </div>
  </div>

  <!--items menu-->
  <div id="items" class="rmenu" data-parent-id="home">
    <div class="title">
      <span class="back">&lt;</span><span>Items</span>
    </div>
    <div class="item" data-target-id="tables" data-target-type="menu">
      <span class="label">Tables</span><span class="submenu-indicator">></span>
    </div>
    <div class="item">
      <span class="label">Lamps</span>
    </div>
    <div class="item">
      <span class="label">Chairs</span>
    </div>
  </div>

  <!--tables menu-->
  <div id="tables" class="rmenu" data-parent-id="items">
    <div class="title">
      <span class="back">&lt;</span><span>Tables</span>
    </div>
    <div class="item">
      <span class="label">1</span>
    </div>
    <div class="item">
      <span class="label">2</span>
    </div>
    <div class="item">
      <span class="label">3</span>
    </div>
    <div class="item">
      <span class="label">4</span>
    </div>
    <div class="item">
      <span class="label">5</span>
    </div>
    <div class="item">
      <span class="label">6</span>
    </div>
  </div>
</div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Obtain a collection of the corresponding keys for a given value from dictionaries

I'm implementing a function that retrieves a list of keys associated with a specific value in the dictionary. Although I am able to print out the first key successfully, I'm facing difficulties in displaying subsequent keys. I understand that I ...

The Ubuntu virtual machine hosted on Google Cloud is experiencing difficulties connecting through Node.js using an external IP address

const express = require('express'); const bodyParser = require('body-parser'); const path = require('path'); const app = express(); app.listen(3000, function(){ console.log('Server is now live on port 3000' ...

Why have the bars been positioned on the left instead of the right, and why does the mobile version require sliding instead of simply accessing the menu through a function?

Hello everyone, I'm currently working on designing a mobile-friendly header menu with the bars positioned on the right side of the screen. The goal is to utilize JavaScript to allow users to click either an 'X' icon or the bars to open the m ...

Exporting a module with Node.js is a crucial aspect of building

Within my custom module, I have successfully set up an export function. module.exports = function(callback) { var request = require("request") var url = "http://sheetsu.com/apis/94dc0db4" request({ url: url, json: true }, ...

Is there a CSS equivalent of column-gap for rows?

After following this guide, I attempted to recreate the photo grid with some spacing between the images. Changing the column-gap property to 3px did add horizontal space, but is there a way to include vertical gaps as well? Any suggestions or solutions wou ...

"Experience the power of React Swiper 6.8.4 as it unveils its slides only during window resizing or when

I'm a beginner in the world of coding and react, and I've encountered an issue with Swiper 6.8.4 in my React app after implementing a FilterMethod. My goal was to create a Slider containing Projects/Images as Slides, allowing users to filter thes ...

Sharing functions between Angular components

Check out my problem statement: https://stackblitz.com/edit/angular-jk8dsj I'm facing two challenges with this assignment: I need to dynamically add elements in the app.component when clicking a button in the key-value.component. I've tried ...

Error: Primefaces ajax status failure (dialog has not been defined)

I incorporated the same code found on primefaces.org, specifically this link: http://www.primefaces.org/showcase/ui/ajaxStatusScript.jsf <p:ajaxStatus onstart="statusDialog.show();" onsuccess="statusDialog.hide();"/> <p:dialog modal="true" ...

Can a shadowed box feature a notch using only CSS?

I am facing a challenge with designing a layout where I am questioning whether it can be achieved using pure CSS or if images are necessary. My goal is to create something similar to the following: In this design, the <body> represents the yellow a ...

How to capture text outside of a HTML tag using Selenium with Python?

I need help extracting the specific text inside a div element that is not enclosed by a label. <div style="color:red;"> <label> Total Amount Due:</label> $0.00 </div> Only interested in retrieving the $0.00 amount from th ...

Tips for retrieving data from a concealed input within a div that is being looped through in Angular.js

Currently, I have a controller that sends data to the UI and uses the ng-repeat directive to map them. My next goal is to bind this data with a hidden input form and then send it to another function in the controller when a click event occurs. Any tips on ...

Trick for adjusting padding on top and bottom for responsive blocks of varying widths

Hello there, I've been working on a project where I need to create a responsive grid of cards, like news articles, that maintain their proportions even when the browser's width changes. To achieve this, I decided to use an aspect-ratio hack by s ...

Type the query into the search bar on the website, hit the submit button, and receive the search results

Is there a way to dynamically pass any query string (from any oracle table, not hardcoded) from a webpage form/field to the database and have the webpage display a table/grid of the results without predefining columns or table names? Current examples I&apo ...

"Enhance Your Website with a WordPress Plugin: The Sticky News Footer

Currently seeking a plugin that can smoothly scroll text, preferably from posts, located at the end of the page in a sticky footer format. I am going for a news-style appearance with clickable links included. In the past, I utilized the Ditty News Ticker ...

Tips for augmenting cell with additional data in react-datepicker

Is it possible to include additional text in a cell using react-datepicker? For example, similar to what is shown in this image: view image here ...

The EJS templating system

I am currently working on a node.js project and I have an ejs template file that utilizes templates for the header and footer. The structure of template.ejs is as follows: <%- include(header) %> main content <%- include(footer) %> <script ...

Next.js is refusing to render an array of HTML elements

Consider this scenario where I have a block of code in TypeScript that attempts to create and display a list of elements. Here is a sample implementation: const MenuList = ():ReactElement => { const router = useRouter(), liElements:any = []; con ...

What is the best way to retrieve information from a data set?

After borrowing some basic HTML, CSS, and JavaScript code from CodePen, I ran into an issue while attempting to convert it to React. The error message says that it cannot read properties of null (specifically 'dataset'). Here is the JavaScript c ...

Dealing with multiple POST requests at once in Node Express JS - Best Practices

I've been working on a Node project with Express to handle incoming GET/POST requests. I have set up routes to manage various types of requests. One specific route, /api/twitter/search, calls a function that uses promises to retrieve Twitter feeds and ...

Issue with Titanium: Unable to scroll within tableview

The tableview is not scrolling as expected. I tested it on a mobile device and the scrolling worked fine, but it doesn't seem to work on tablets. Please assist. CODE var win = Titanium.UI.createWindow({ title : 'Medall app', back ...