Simple JQuery Sliding Effect Gets Out of Sync - javascript

I have this simple JQuery code that will slide the content from one div to the next. However after the browser being open for some time, eventually, it will get off sync and all of them start flying across the screen at the same time, and end up on top of each other. Any ideas what is wrong on my code?
$(function() {
function sp18() {
div = $('#container .box.selected');
$(div).animate({
left: '-50%'
}, 500, function() {
$(div).css('left', '150%').removeClass("selected");
$(div).appendTo('#container');
});
$(div).next().animate({
left: '0'
}, 500).addClass("selected");
setTimeout(sp18, 200);
}
setTimeout(sp18, 100);
});
#container {
letter-spacing: 0.05em;
text-align: center;
width: 100%;
margin-top: 2px;
width: 100%;
height: 38px;
overflow: hidden;
line-height: 38px;
position: relative;
}
#container .box {
position: absolute;
width: 100%;
text-align: center;
left: 150%;
margin-left: 0;
line-height: 38px;
font-size: 13px;
}
#container .box span {
color: #555
}
#container .box.selected {
left: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="container">
<div class="box selected">slide 1</div>
<div class="box">slide 2</div>
<div class="box">slide 3</div>
<div class="box">slide 4</div>
</div>
Occasionally the screen will look like this when they are out of sync:

You may want to add the setTimeout() inside the latest animate complete() callback function. So, this way you wait for the latest animation to finish before calling again the sp18 function, otherwise, if you don't wait an animation to finish before starting a new one, eventually you will get out of sync:
function sp18()
{
let div = $('#container .box.selected');
$(div).animate({left:'-50%'}, 500, function()
{
$(div).css('left', '150%').removeClass("selected");
$(div).appendTo('#container');
});
$(div).next().animate({left:'0'}, 500, function()
{
setTimeout(sp18, 250);
}).addClass("selected");
}
$(document).ready(function()
{
setTimeout(sp18, 1000);
});
#container {
letter-spacing: 0.05em;
text-align: center;
width:100%;
margin-top:2px;
width: 100%;
height: 38px;
overflow: hidden;
line-height:38px;
position: relative;
}
#container .box {
position: absolute;
width: 100%;
text-align: center;
left: 150%;
margin-left: 0;
line-height:38px;
font-size:13px;
}
#container .box span {
color:#555
}
#container .box.selected {
left: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="container">
<div class="box selected">slide 1</div>
<div class="box">slide 2</div>
<div class="box">slide 3</div>
<div class="box">slide 4</div>
</div>

There is an extra }); at the end of your javascript, removing which makes the code work as expected.
Alternatively you can put everything inside $(document).ready() as follows:
$(document).ready(function() {
function sp18() {
div = $("#container .box.selected");
$(div).animate({left: "-50%"}, 500, function() {
$(div).css("left", "150%").removeClass("selected");
$(div).appendTo("#container");
});
$(div).next().animate({left: "0"}, 500).addClass("selected");
setTimeout(sp18, 8000);
}
setTimeout(sp18, 3000);
});
The codepen demo here: https://codepen.io/anon/pen/JVXJBz

Related

How do I get one animation to occur after another when Start button is pressed?

I have the following functions. I want box 3 to move only after box 1 and box 2 have finished moving. Right now, it's moving right away. I assume I would put all the functions under one .click function but I tried a few times and it still does not work.
$(function() {
$("button").click(function() {
$("#box1").animate({
left: $(window).width() - 800
}, {
complete: function() {
$("#box1").hide();
}
});
});
$("button").click(function() {
$("#box2").animate({
left: $(window).width() - 800
}, {
complete: function() { // complete call back
$("#box2").hide(); // can hide or remove this element
},
});
});
$("button").click(function() {
$("#box3").animate({
right: $(window).width() - 200,
top: $(window).height() - 200
});
});
});
#box1,
#box2,
#box3 {
width: 30px;
height: 50px;
position: absolute;
text-align: center;
font-family: Times New Roman;
}
#box1 {
background-color: skyblue;
left: 0px;
top: 50px;
}
#box2 {
background-color: green;
left: 0px;
top: 120px;
}
#box3 {
background-color: black;
left: 100px;
top: 50px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button> Start </button>
<div id="box1">
<p> BOX 1 </p>
</div>
<div id="box2">
<p> BOX 2 </p>
</div>
<div id="box3">
<p> BOX 3 </p>
</div>
If I understand correctly, I simply smashed the first two click handlers together and moved the animation from the third one into the complete callback on #2.
$(function() {
$("button").click(function() {
$("#box1").animate({
left: $(window).width() - 800
}, {
complete: function() {
$("#box1").hide();
}
});
$("#box2").animate({
left: $(window).width() - 800
}, {
complete: function() { // complete call back
$("#box2").hide(); // can hide or remove this element
$("#box3").animate({
right: $(window).width() - 200,
top: $(window).height() - 200
});
}
});
});
});
#box1,
#box2,
#box3 {
width: 30px;
height: 50px;
position: absolute;
text-align: center;
font-family: Times New Roman;
}
#box1 {
background-color: skyblue;
left: 0px;
top: 50px;
}
#box2 {
background-color: green;
left: 0px;
top: 120px;
}
#box3 {
background-color: black;
left: 100px;
top: 50px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button> Start </button>
<div id="box1">
<p> BOX 1 </p>
</div>
<div id="box2">
<p> BOX 2 </p>
</div>
<div id="box3">
<p> BOX 3 </p>
</div>

How to keep user's scrolling place when resizing div

I wanted to do a cool menu effect for a website I'm working on. I'm having a div act as the the section for the main content. When the user opens the menu, the main content div will resize and move out of the way, revealing the menu. However, when I do this with the code I have written, it always loses my scrolling place on the page. Is there any way to keep my place on the page when it shrinks and also when it expands back again? Below is what I have. Thank you in advance!
function shrinkPage() {
var element = document.getElementById("mock-body");
element.classList.toggle("mock-body-on-burger");
var z = document.getElementById("mock-body-container");
z.classList.toggle("mock-body-container-on-burger");
var x = document.getElementById("body");
x.classList.toggle("body-on-burger");
};
body {
margin: 0;
background:#000;
}
.body-on-burger {
max-width: 100%;
overflow-x:hidden;
}
.mock-body-container{
height:100vh;
}
.mock-body-container-on-burger {
height:100vh;
transform: scale(0.4) translate(130%);
overflow: hidden;
}
.mock-body-size-change{
overflow: scroll;
}
.mock-body {
position:relative;
background: #fff;
margin-left: 50px;
}
.container {
position: fixed;
height:50px;
width:50px;
cursor: pointer;
}
.container #icon {
width: 16px;
height: 8px;
position: relative;
margin: 0px auto 0;
top: 40%;
}
.container #icon .bars {
height: 1px;
background: #fff;
}
.myDiv {
height:500px;
}
.one {
background:red;
}
.two {
background:green;
}
.three {
background:blue;
}
<body id="body">
<div class="menu-activator" onclick="shrinkPage()">
<div class="container usd">
<div id="icon">
<div class="bars first"></div>
</div>
</div>
</div>
<div id="mock-body-container" class="mock-body-container">
<div id="mock-body" class="mock-body">
<div class="myDiv one"></div>
<div class="myDiv two"></div>
<div class="myDiv three"></div>
</div>
</div>
</body>
Please take a look at the snippet below. Notice how the overflow property is used.
You have to scroll mock-body-container to keep its scrolling position.
You're scrolling body instead, so when you scale mock-body-container there is nothing to scroll in body and you loose the scrolling position.
function shrinkPage() {
var element = document.getElementById("mock-body");
element.classList.toggle("mock-body-on-burger");
var z = document.getElementById("mock-body-container");
z.classList.toggle("mock-body-container-on-burger");
var x = document.getElementById("body");
x.classList.toggle("body-on-burger");
};
body {
margin: 0;
background:#000;
}
.body-on-burger {
max-width: 100%;
overflow-x:hidden;
}
.mock-body-container{
height:100vh;
overflow:auto;
}
.mock-body-container-on-burger {
height:100vh;
transform: scale(0.4) translate(130%);
}
.mock-body-size-change{
overflow: scroll;
}
.mock-body {
position:relative;
background: #fff;
margin-left: 50px;
}
.container {
position: fixed;
height:50px;
width:50px;
cursor: pointer;
}
.container #icon {
width: 16px;
height: 8px;
position: relative;
margin: 0px auto 0;
top: 40%;
}
.container #icon .bars {
height: 1px;
background: #fff;
}
.myDiv {
height:500px;
}
.one {
background:red;
}
.two {
background:green;
}
.three {
background:blue;
}
<body id="body">
<div class="menu-activator" onclick="shrinkPage()">
<div class="container usd">
<div id="icon">
<div class="bars first"></div>
</div>
</div>
</div>
<div id="mock-body-container" class="mock-body-container">
<div id="mock-body" class="mock-body">
<div class="myDiv one"></div>
<div class="myDiv two"></div>
<div class="myDiv three"></div>
</div>
</div>
</body>
Once you know the element that was in focus it should be relatively easy. If you need to find which element was last in focus, you can do that with a scroll function. If you need this as well let me know and I will update my answer.
If you know that #mock-body is the last element in focus, just scroll back to it after the resize.
In this example I've used jQuery as it makes this interaction easier, but this can be done (albeit more verbosely) with vanilla JS as well.
$('html, body').animate({
scrollTop: $('#mock-body').offset().top
}, 0); // If you want the animation to be smoother you can increase 0 to a higher number
A simple way to do it is to remember the position of the document scroll and reapply it when you getting back to "normal" view:
let savedScroll;
function shrinkPage() {
let _s = (el) => document.querySelector(el),
s_ = (d) => !d.classList.contains('body-on-burger'),
x = _s('#body'),
element = _s('#mock-body'),
z = _s('#mock-body-container');
if (s_(x)) {
savedScroll = document.documentElement.scrollTop;
}
element.classList.toggle("mock-body-on-burger");
z.classList.toggle("mock-body-container-on-burger");
x.classList.toggle("body-on-burger");
if (s_(x)) {
document.documentElement.scrollTop = savedScroll;
}
};
Check it out:
let savedScroll;
function shrinkPage() {
let _s = (el) => document.querySelector(el),
s_ = (d) => !d.classList.contains('body-on-burger'),
x = _s('#body'),
element = _s('#mock-body'),
z = _s('#mock-body-container');
if (s_(x)) {
savedScroll = document.documentElement.scrollTop;
}
element.classList.toggle("mock-body-on-burger");
z.classList.toggle("mock-body-container-on-burger");
x.classList.toggle("body-on-burger");
if (s_(x)) {
document.documentElement.scrollTop = savedScroll;
}
};
body {
margin: 0;
background: #000;
}
.body-on-burger {
max-width: 100%;
overflow-x: hidden;
}
.mock-body-container {
height: 100vh;
}
.mock-body-container-on-burger {
height: 100vh;
transform: scale(0.4) translate(130%);
overflow: hidden;
}
.mock-body-size-change {
overflow: scroll;
}
.mock-body {
position: relative;
background: #fff;
margin-left: 50px;
}
.container {
position: fixed;
height: 50px;
width: 50px;
cursor: pointer;
}
.container #icon {
width: 16px;
height: 8px;
position: relative;
margin: 0px auto 0;
top: 40%;
}
.container #icon .bars {
height: 1px;
background: #fff;
}
.myDiv {
height: 500px;
}
.one {
background: red;
}
.two {
background: green;
}
.three {
background: blue;
}
<body id="body">
<div class="menu-activator" onclick="shrinkPage()">
<div class="container usd">
<div id="icon">
<div class="bars first"></div>
</div>
</div>
</div>
<div id="mock-body-container" class="mock-body-container">
<div id="mock-body" class="mock-body">
<div class="myDiv one"></div>
<div class="myDiv two"></div>
<div class="myDiv three"></div>
</div>
</div>
</body>
Legend: _s(el) returns first match of el and s_(d) checks if d has class body-on-burger.
The simple way to do this is to determine the change in height during the resize, and scroll that much.
const heightChange = newHeight - initialHeight;
scrollableDiv.scrollTop = scrollableDiv.scrollTop - heightChange;
In my case I am using a resize method I wrote, so I do this work inside of a window.addEventListener("mousemove", handleResize); when I know the div in actively being resized by the user.
This will still work fine with native html resizable elements, you just need to figure out how/when to listen for resize/drag events accordingly.

Jquery animate() effect doesn't function well

When hover on the first and second element, some element will animate to the left, it works well if hovered with a normal speed, but will crashed if hovered too fast for some times
(the text won't show or the text won't move back to its original place when mouseoff, checkout the figures below).
Any suggestions would be appreciated.
1.text won't show
2.text won't move back to its original place
$(document).ready(function() {
var flag = false;
$(".tab-ico").hover(function() {
var f = $(this);
f.data('timeout', window.setTimeout(function() {
f.find(".tab-text").stop(true, true).animate({
left: "-=64"
}, 300, function() {
flag = true;
});
}, 300));
}, function() {
clearTimeout($(this).data("timeout"));
if (flag === true) {
$(this).find(".tab-text").stop(true, true).animate({
left: "+=64"
}, 300, function() {
flag = false;
});
}
});
});
.pfm-toolbar-wrap {
height: 100%;
position: fixed;
right: 0;
top: 0;
width: 35px;
z-index: 9990;
}
.pfm-tbar-tab-Spike {
position: relative;
width: 35px;
}
.pfm-toolbar-tabs {
border-right: 5px solid #7a6e6e;
height: 100%;
}
.p-tab div.tab-ico {
background: #7a6e6e;
}
.tab-text {
border-radius: 3px;
color: #fff;
height: 32px;
left: 0px;
line-height: 32px;
position: absolute;
text-align: center;
width: 70px;
padding-right: 5px;
z-index: -1;
background: #7a6e6e;
}
.tab-text a {
color: #fff;
display: block;
}
.p-tab {
left: 0;
margin-top: -100px;
position: absolute;
top: 50%;
width: 35px;
z-index: 9;
text-align: center;
}
.p-tab div.tab-ico:hover {
background: #e20531;
cursor: pointer;
}
.p-tab div.tab-ico:hover .tab-text {
background: #e20531;
}
.tab-ico {
width:35px;
height:35px;
margin-bottom:5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="pfm-toolbar-wrap">
<div class="pfm-toolbar-tabs">
<div class="p-tab">
<div class="pfm-tbar-tab-Spike m_b15">
<div class="tab-ico cart"> <i class="cbl-icon"></i> <em class="tab-text"> text</em>
</div>
</div>
<div class="pfm-tbar-tab-group m_b15">
<div class="tab-ico "> <i class="cbl-icon"></i>
<em class="tab-text"> text2</em>
</div>
</div>
</div>
</div>
</div>
you can use css transition-delay property as follows:
transition-delay: 1s; /* delays for 1 second */
-webkit-transition-delay: 1s; /* for Safari & Chrome */
Find more info here.
I suggest that you use CSS transition, here are two links that will help you make that with less code and using CSS transition
https://css-tricks.com/almanac/properties/t/transition/
https://blog.alexmaccaw.com/css-transitions

CSS3 or JAVASCRIPT for hover

I would like to put in evidence a picture (and blur all the rest) when I am over a link. Here my Html:
<body>
<div id="back">
<div id="one"></div>
<div id="two"></div>
</div>
<div id="menu">
one</div>
two</div>
</div>
</body>
and CSS:
#Back{
position: absolue;
background-image: url(images/fond.png);
width: 960px;
height: 600px;
margin: 0 auto;
}
#one{
background-image: url(images/formation.png);
width: 960px;
height: 600px;
z-index:1;
}
#two{
background-image: url(images/experiences.png);
width: 960px;
height: 600px;
z-index:2;
margin-top:-600px;
}
The problem i tried in css with this:
#link1:hover #one{
display:none;
}
And in javascript with this script:
function over(id){
if(document.getElementById(id)){
var objet = document.getElementById(id);
objet.style.display = "none";
}
}
Both doesn t work. I m not super good with the javascript. Thank so much for your help!!!
HTML:
<div id="menu">
link1
link2
</div>
<div class="div0" id="zero">
<div class="div1" id="one"></div>
<div class="div2" id="two"></div>
</div>
CSS:
.div0 {
position: absolute;
top: 30px;
left: 0px;
background-image: url(http://www.sanbarcomputing.com/images/js.jpg);
background-size: 400px 400px;
width: 400px;
height: 400px;
transition: 1s;
}
.div1 {
position: absolute;
top: 30px;
left: 0px;
background-image: url(http://www.sanbarcomputing.com/images/html5-logo.png);
background-size: 200px 200px;
width: 200px;
height: 200px;
transition: 1s;
}
.div2 {
position: absolute;
top: 30px;
left: 200px;
background-image: url(http://www.sanbarcomputing.com/images/class-header-css3.jpg);
background-size: 200px 200px;
width: 200px;
height: 200px;
transition: 1s;
}
JavaScript:
(function () {
var zeroEl = document.getElementById('zero'),
oneEl = document.getElementById('one'),
twoEl = document.getElementById('two'),
link1El = document.getElementById('link1'),
link2El = document.getElementById('link2');
function mouseover (elem) {
elem.style.opacity = '.2';
zeroEl.style.opacity = '.2';
}
function mouseout (elem) {
elem.style.opacity = '1';
zeroEl.style.opacity = '1';
}
document.addEventListener('DOMContentLoaded', function () {
link1El.addEventListener('mouseover', function () {
mouseover(oneEl); }, false);
link2El.addEventListener('mouseover', function () {
mouseover(twoEl); }, false);
link1El.addEventListener('mouseout', function() {
mouseout(oneEl); }, false);
link2El.addEventListener('mouseout', function () {
mouseout(twoEl); }, false);
}, false);
})();
jsfiddle
I could not get the CSS hover solution to work, for whatever reason.
NOTE: This solution uses modern JavaScript techniques that may not be compatible with legacy browsers
EDIT: Updated to use Pavlo's opacity solution, fixed css errors, changed image alignments, made images independent divs
First, assign a class to each link:
<div id="menu">
one</div>
two</div>
</div>
Then, if your css hover does not work, try using jQuery to do the hovering:
$('.link').hover(function() {
//handle mouse enter
}, function() {
//handle mouse leave
});
Refer: http://api.jquery.com/hover/

When you hover the .container it changes the color of both. But I just want to change it of the container where the mouse is on

I prepared this:
http://jsfiddle.net/hXpWh/2/
When you hover the .container it changes the color of both. But I just want to change it of the container where the mouse is on.
Here is the js code:
moped = "";
$(".container").mouseenter(function () {
$(".content").css('background', function () {
moped = $(this).css('background');
return "green";
});}).mouseleave(function () {
$(".content").css('background', function () {
return moped;
});
});
html:
<div class="container">
<div class="content"></div>
<div class="caption">
<p>This is the caption of .container</p>
</div>
</div>
<div class="container2">
<div class="content"></div>
<div class="caption">
<p>This is the caption of .container2</p>
</div>
</div>
css:
.container {
position: absolute;
top: 0;
left: 0;
display: block;
z-index: 800;
width: 250px;
height: 250px;
padding: 0;
margin: 0;
}
.container2 {
position: absolute;
top: 0;
left: 255px;
display: block;
z-index: 800;
width: 250px;
height: 250px;
padding: 0;
margin: 0;
}
.content {
display: block;
background: red;
position: absolute;
z-index: 900;
top: 0;
left: 0;
width: 250px;
height: 250px;
}
.caption {
display: block;
background: none;
position: absolute;
z-index: 1000;
top: 0;
left: 0;
width: 250px;
height: 250px;
}
.caption p {
position: relative;
bottom: 10px;
left: 10px;
}
The other answers show what's wrong in the jQuery code, but another fix is to just using CSS for this.
Give the outer elements a common class, then:
.cont {
background:red;
}
.cont:hover .content {
background: green;
}
DEMO: http://jsfiddle.net/hXpWh/4/
But with respect to the jQuery code, not only do you need to find the nested .content, but also, there's no need for the variable. Just set the background to "" in the mouseleave.
$(".container").mouseenter(function () {
$(this).find(".content").css('background', "green");
}).mouseleave(function () {
$(this).find(".content").css('background', "");
});
Change $(".content") to $(this).find(".content") in the .mouseenter function, and it will only change the one that you hover over. You could change it to $(".content", this), but as per epascarello in the comments, it is not as efficient.
Well , you could either move the css background attribute or do this:
moped = "";
$(".container").mouseenter(function () {
$(this).children(".content").css('background', function () {
moped = $(this).css('background-color');
return "green";
});
}).mouseleave(function () {
$(this).children(".content").css('background', function () {
return moped;
});
});
My advice is do it with the script and refactor it , use .hover() and name the mouseenter and mouseout functions separately.
Good luck, mate.

Categories

Resources