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

Editing DOM elements within Angular JS using Greasemonkey extension

I have been developing a Greasemonkey script to enhance the performance of a vendor's angularJS tool by automating certain processes. One major obstacle I am encountering is that the element I need to interact with is not yet loaded in the DOM when m ...

What are the benefits of implementing a hexadecimal strategy in javascript?

I have a somewhat unusual question that has been puzzling me. I've noticed some interesting choices in naming variables in JavaScript, seemingly using what appears to be "a hexadecimal approach". For example, I see variables named like _0x2f8b, _0xcb6 ...

Ways to Ensure a Property of an Object Remains Synced with Another

I'm dealing with the following Object structure: { a: "123" b: "$a" } In this setup, b should always be equal to the value of a. Any suggestions on how I can achieve this using JavaScript? ...

I'm looking for a way to dynamically update Laravel pagination records based on the selected option value for the number of items per page using Laravel and

I am working on creating a custom filter system using a select option menu and pagination with AJAX. The select option allows users to choose between displaying 10, 15, 20, or 25 products per page while updating the Laravel default pagination dynamically ...

Surprising automatic scrolling upon pressing the keydown button in Bootstrap

My webpage appears normal with the Bootstrap framework, but whenever I press the down key, the screen scrolls down and displays unexpected white space due to reaching the end of the background-image sized at 1798px * 1080px. Please refer to the image: He ...

IE presenting problems with JQuery content loaded via Ajax

I operate a website that showcases various products, each with a corresponding link to a fancybox displaying detailed information about the product (detailed.php file). <a class="fancy fancy'.$_GET['type'].'" href="detail.php?id=&ap ...

The Google Maps API is not providing any data in response to my jQuery JSONP request

Similar Topic: Unpacking Google Geo API (Reverse Geocoding) using jQuery $(window).load(function() { var purl = "http://maps.googleapis.com/maps/api/geocode/json?latlng=32.759294499999996,-97.32799089999999&sensor=false"; $.getJSON(purl,f ...

Guide on accessing nested objects in EJS templates

I'm attempting to extract the "info" portion from the JSON data provided below. In my code snippet, I'm using the <%= person['person_details']%> to access that specific section of the JSON. However, it only returns [Object Obje ...

CSS: Set the left position to 250px with the added feature of hiding any overflow

I am currently working on a sidebar that can be shown or hidden using JavaScript with CSS animations. To achieve this effect, I need to position the content div (#main) using left: 250px;. #main { left: 250px; position: relative; overflow: hidden; } ...

downsides of scrolling text functionality

Sure, it may seem evil. But what makes it so? Is it because all browsers support it? Which aspx asp.net controls are restricted in this tag? What are the reasons for avoiding this tag? ...

Obtain image from an external server using AJAX

Our team is currently working on retrieving images from external servers that are cross-origin. While JSONP may not be effective in this case, we are exploring the use of plain AJAX GET requests. One potential workaround involves using iframes to manipulat ...

Navigating across various iFrames with the help of XPath and C#

Trying to extract a data element from a table that is nested within two iframes. These frames are displayed like this: <iframe id="appContent" frameborder="0" name="appContentFrame" src="/controller.aspx" style="height: 0px; width: 1319px;"> ...

Converting Dynamo DB stream data into Json format

I need to convert the DDB stream message into a standard JSON format. To achieve this, I am using unmarshalleddata = aws.DynamoDB.Converter.unmarshall(result.NewImage); where result.NewImage is { carrier: { S: 'SPRING' }, partnerTransacti ...

Click here to start your Django download now

I am looking for a way to monitor the number of times a file has been downloaded. Here is my plan: 1) Instead of using <a href="{{ file.url }}" download>...</a>, I propose redirecting the user to a download view with a link like <a href="do ...

Utilize Aframe to easily view and upload local gltf files

I've been working on a project to create a user-friendly panel for loading and viewing gltf models in real-time in A-frame. Here is the current workflow I am following: Using the input tag to load files from local storage. Using v-on-change to assi ...

The MarkCompactCollector was unsuccessful in promoting the young object due to a failed allocation process

After successfully cloning a Git repository that houses a Vue project using the command git clone, I proceeded to run npm install in order to install all necessary dependencies, resulting in the creation of the node_modules folder. However, upon executing ...

When trying to connect to the MongoDB database using Node.js and Express, the content

Currently immersing myself in the world of MongoDB for Node.js Here is my app.js: var express = require('express'), app = express(), engines = require('consolidate'), MongoClient = require('mongodb').MongoClient, as ...

Positioning of the dropdown in Material UI AutoComplete menus

Is there a way to turn off autocomplete auto position? I would like the autocomplete options to always appear at the bottom. Check out this link for more information! ...

Creating a three-dimensional shape using a transparent image in Three.js

Hey there! I'm currently working on creating a 3D model that features the upper and lower sides as transparent images, while the other sides are a solid color (yellow in this case). var texture = new THREE.TextureLoader().load( 'img.png' ); ...

What is the best way to add clickable links to 3D objects and meshes with ThREE?

My goal is to create a simple box that can act as a link when clicked. This seemingly straightforward task has proven difficult for me, so I would greatly appreciate any assistance. Despite my efforts to troubleshoot and research online, I have not been ...