Related
I am trying to change the style of an element while some javascript is running in the background, to indicate that the page is 'busy' or 'loading'. I've been attempting to do this by toggling a class on at the start of the JS script with jQuery's .toggleClass(), and toggling it off at the end, with some suitable CSS styling attached to the class.
Although the class is toggled immediately, the CSS styling attached to it doesn't apply until after the JS has finished executing, however. So if the class is toggled both on and off, the user does not see any change in style.
I've included a simple example below. How can I force the change in CSS styling to apply immediately, before the rest of the JS code executes?
$(function() {
$('#box').click(function() {
// Toggle class 'red' on.
$(this).toggleClass('red');
// Do something that takes time.
for (i = 0; i < 10000; i++) {
console.log(i);
}
// Toggle class 'red' off.
$(this).toggleClass('red');
});
});
.wrapper {
margin: 15px;
text-align: center;
color: #000;
}
#box {
margin: 15px 0;
width: 100px;
height: 100px;
line-height: 100px;
cursor: pointer;
background: #ccc;
border: solid 3px #ccc;
-webkit-transition: all .3s linear 0s;
transition: all .3s linear 0s;
}
#box.red {
background: #f43059;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wrapper">
<div id="box">Click me.</div>
</div>
The problem is that your "something that takes time" is synchronous and blocking - while it's operating, browser repainting will be disabled.
One option would be to listen to a transitionend event, to ensure that the animation to red completes before the resource-intensive operation runs.
So that the removal of .red animates properly too, you could set a setTimeout right after the heavy operations finish. Note that your code will a bit be clearer if you use addClass and removeClass instead of toggleClass:
$('#box').click(function() {
$(this).one('transitionend', () => {
// Do something that takes time.
for (i = 0; i < 1000; i++) {
console.log(i);
}
// Toggle class 'red' off.
setTimeout(() => {
$(this).removeClass('red');
});
});
$(this).addClass('red');
});
.wrapper {
margin: 15px;
text-align: center;
color: #000;
}
#box {
margin: 15px 0;
width: 100px;
height: 100px;
line-height: 100px;
cursor: pointer;
background: #ccc;
border: solid 3px #ccc;
-webkit-transition: all .3s linear 0s;
transition: all .3s linear 0s;
}
#box.red {
background: #f43059;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wrapper">
<div id="box">Click me.</div>
</div>
First of all, you can find a simplified demo of my code in this JSFiddle and also below the question. I found that my problem happens the way I describe it in Google Chrome, so if you plan to try and fix the bug, please use that browser. I apologize if the code is not very well simplified; please consider that this is a snippet from a bigger project.
I'm working on a webapp that uses JQuery and GreenSock's TweenLite for animations.
This app consists on some menus that control everything, that are transitioned between using the bodyChange() function. This function has two parameters:
nextOrPrev, that runs one animation or another based on the value
provided ("next" or "prev"). Only the "next" animation is done yet, but that is not important for now. The "prev" animation, not yet used, just emits an alert("prev").
bodyFunction. The function provided will fill the body with the elements necessary for that menu, and the wrap them in a #bodyWrap.
In the demo I provide you with there are only two menus: The first one, mainMenu, with only a #playButton. When you click it, the bodyChange() function is called with the following parameters: ("next", playSettingsBody), playSettings being the second menu.
This is the problem: when you click the playButton, the button goes up a on the screen and then executes the TweenLite animation. I can't see, however, why does the button "jump up", instead of staying in the same place and execute the animation. This is probably due to a small mistake. What is it?
Thanks for any help.
mainMenuBody();
function mainMenuBody() {
$("body").append(
//BUTTONS
"<div id='playButton' class='mainButton'><div class='buttonText mainButtonText text'>PLAY</div></div>"
);
//WRAP
$("body").wrapInner("<div id='bodyWrap'></div>");
//BINDS
$("#playButton").bind("click", function() {
bodyChange("next", playSettingsBody);
});
}
function bodyChange(nextOrPrev, bodyFunction) {
switch (nextOrPrev) {
case "next":
//ANIMATION AND BODY CHANGE
TweenLite.to($("#bodyWrap"), .4, {
ease: Power2.easeIn,
transform: "rotateY(90deg)",
onComplete: function(){
$("body").empty();
//NEW STUFF
bodyFunction();
TweenLite.from($("#bodyWrap"), .4, {
ease: Power2.easeOut,
transform: "rotateY(90deg)"
});
}
});
//END OF ANIMATION AND BODY CHANGE
break;
case "prev":
alert("prev");
}
}
function playSettingsBody() {
$("body").append(
"<p class='text' id='CYTText'>This is the second menu!</p>"
);
}
body{
background-image: url("../resources/pics/Vignette2.png");
background-repeat: no-repeat;
background-position: center center;
background-attachment: fixed;
background-color: #02BFC1;
overflow:hidden;
margin: 0;
}
.text {
color: #FFFFFF;
font-family:Bebas Neue;
-webkit-user-select: none;
cursor: default;
text-shadow: 3px 3px 2px rgba(0,0,0,0.2);
}
.mainButton {
-webkit-transform:scale(1);
width: 200px;
height: 200px;
border: 10px solid #F1F2F0;
text-align:center;
background-color: #F37C2B;
/*background:#5F4A21;*/
display: table;
position: absolute;
margin: auto;
top: 150px;
bottom: 0;
-webkit-transition: all 0.5s ease;
cursor: pointer;
box-shadow: 0px 0px 30px rgba(0,0,0,0.4);
}
.mainButtonText {
position: relative;
display:table-cell;
vertical-align:middle;
-webkit-transform:scale(1);
font-size: 90px;
text-shadow: 4px 4px 2px rgba(0,0,0,0.2);
-webkit-transition: all 0.5s ease;
}
<script src="https://code.jquery.com/jquery-3.1.0.min.js" integrity="sha256-cCueBR6CsyA4/9szpPfrX3s49M9vUU5BgtiJj06wt/s=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.19.0/TweenMax.min.js"></script>
This problem is caused in your .mainButton class. Your code looks a little like this.
.mainButton {
position: absolute;
top: 150px;
bottom: 0;
//rest
}
By removing the line bottom: 0; your JSFiddle now works as expected. However, if you remove the line top: 150px; instead and leave in the bottom: 0 the problem still occurs. Unfortunately, I cannot provide an explanation for this. It might be worth posting a question on the GSAP forums inquiring about why this occurs works when positioning using bottom but not when using top
Edit
Since you need bottom: 0 and I wasn't able to fix your code I wrote an example which works using Timeline, a GSAP plugin. You can see this JSFiddle or the code example below.
var tl = new TimelineMax();
tl.pause();
tl.fromTo($("#click"), 1, {rotationY: 0, ease: Power2.easeOut}, {rotationY: 90, transformOrigin:"right", ease: Power2.easeOut})
.set($("#click2"), {css:{display: "table"}}, "-=0.6")
.fromTo($("#click2"), 1, {rotationY: -90, ease: Power2.easeOut}, {rotationY: 0, transformOrigin:"left", ease: Power2.easeOut}, "-=0.6");
$("#click").click(function() {
tl.play();
});
$("#click2").click(function() {
tl.reverse();
});
* {
margin: 0;
padding: 0;
}
body {
background-image: url("../resources/pics/Vignette2.png");
background-repeat: no-repeat;
background-position: center center;
background-attachment: fixed;
background-color: #02BFC1;
overflow: hidden;
}
div.one, div.two {
position: absolute;
bottom: 0;
height: 200px;
width: 200px;
background: #F37C2B;
text-align: center;
display: table;
cursor: pointer;
border: 10px solid #F1F2F0;
}
div.one .text, div.two .text {
position: relative;
display: table-cell;
vertical-align: middle;
color: #FFFFFF;
font-family: Bebas Neue;
font-size: 90px;
}
div.two {
display: none;
border-color: transparent;
background: none;
}
div.two .text {
font-size: 40px;
}
<script src="https://code.jquery.com/jquery-3.1.0.min.js" integrity="sha256-cCueBR6CsyA4/9szpPfrX3s49M9vUU5BgtiJj06wt/s=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.19.0/TweenMax.min.js"></script>
<div id="click" class="one">
<div class="text">
Play
</div>
</div>
<div id="click2" class="two">
<div class="text">
Second Menu
</div>
</div>
when I click on the main circle the surrounding 5 circles will get minimized completely( to 100% hide), but those are not minimizing completely. There is a small circle over the main circle after minimizing. How to completely minimize (hide) the tiny circle on top of the main circle after toggle close.
I have tried jQuery hide but it was hiding entire element,
Below is the jQuery code,
var nbOptions = 8;
var angleStart = -360;
// jquery rotate animation
function rotate(li,d) {
$({d:angleStart}).animate({d:d}, {
step: function(now) {
$(li)
.css({ transform: 'rotate('+now+'deg)' })
.find('label')
.css({ transform: 'rotate('+(-now)+'deg)' });
}, duration: 0
});
}
// show / hide the options
function toggleOptions(s) {
$(s).toggleClass('open');
var li = $(s).find('li');
var deg = $(s).hasClass('half') ? 180/(li.length-1) : 360/li.length;
for(var i=0; i<li.length; i++) {
var d = $(s).hasClass('half') ? (i*deg)-90 : i*deg;
$(s).hasClass('open') ? rotate(li[i],d) : rotate(li[i],angleStart);
}
}
$('.selector button').click(function(e) {
toggleOptions($(this).parent());
});
setTimeout(function() { toggleOptions('.selector'); }, 100);
http://jsfiddle.net/adzFe/2574/
You do need to remove the border and padding inside .selector.open li input + label but you can toggle on and off with another class.
.open1 {
padding: 6px;
border:1px solid #999;
}
Add this JS:
function toggleOptions(s) {
$(s).toggleClass('open');
var li = $(s).find('li');
li.find("label").toggleClass("open1"); // NEW
...
}
Fiddle: http://jsfiddle.net/adzFe/2576/
I agree, the mini circle is caused by extra padding at wrong class, I have moved the padding to the selector.open. Now it is not showing any mini circle.
.selector li input + label {
position: absolute;
left: 50%;
bottom: 120%;
width: 0;
height: 0;
margin-left: 0;
background: #fff;
border-radius: 50%;
text-align: center;
overflow: hidden;
cursor: pointer;
background:#eee;
transition: all 0.8s ease-in-out, color 0.1s, background 0.1s;
}
.selector li input + label img {
border-radius:50%;
}
.selector.open li input + label {
width: 90px;
height: 90px;
margin-left: -40px;
padding:6px;
border:1px solid #999;
box-shadow: 0 3px 3px rgba(0, 0, 0, 0.1);
}
.selector.open li input + label:hover {
border:1px solid #fff;
padding:6px;
background:#fff;
}
.mainimage{
width:100%;
height:100%;
border-radius:50%;
}
Working code
http://jsfiddle.net/adzFe/2577/
Looks like the problem is in your CSS .selector li input + label rule. You still have some padding and border width in this rule which is giving the circles some size. Change those 2 values to 0 and they should completely hide:
.selector li input + label {
position: absolute;
left: 50%;
bottom: 120%;
width: 0;
height: 0;
margin-left: 0;
background: #fff;
border-radius: 50%;
text-align: center;
overflow: hidden;
cursor: pointer;
border:0 solid #999; /* previously 1px */
padding:0; /* previously 6px */
background:#eee;
transition: all 0.8s ease-in-out, color 0.1s, background 0.1s;
}
Update:
Since the padding and border are needed, you can adjust your ruleset to have these values while the menu circles have the open class and remove them when the class is not present
http://jsfiddle.net/avt0fvk4/
The website I am building has 4 large background images that take up the entire height and width of the user's browser. They are implemented as CSS background divs. The problem is, when scrolling on larger screen sizes, it is very laggy and choppy. Scrolling between these images is done automatically via JavaScript when the user presses a button, so this is part of the core functionality of my website and I must find a way to prevent lag.
So far, I have tried preloading the images via JS and converting the images from PNG to JPEG (increase compression and decrease quality) server-side. Neither of these worked.
The minimum height of the image can be 630 pixels. How can I prevent lag while scrolling between sections?
Here's my code:
CSS:
body { height: 100%; margin: 0px; font-family: HelveticaNeue, Helvetica, Arial, sans-serif; }
.area { height: 630px; border: 0px solid red; background: repeat-x; margin-bottom: 0px; }
a { text-decoration: none; }
h1, h2, h3, h4, h5, h6 { font-family: Av, Helvetica, Arial, sans-serif; color: #292E37; font-weight: lighter; }
#top { position: fixed; width: 100%; height: 10%; background: #292E37; box-shadow: inset 0px -1px 5px #000; z-index: 1000; }
#navigation { float: right; height: 100%; }
#bottom { width: 100%; position: fixed; bottom: 0px; padding: 10px; background: #292E37; box-shadow: inset 0px 1px 5px #000; text-shadow: 0px 1px 0px #000; color: #fff; }
#sceneSelection { top: 20%; position: fixed; padding: 10px; }
#info { margin-top: 50px; margin-bottom: 50px; }
.box { margin-top: 50px; padding: 75px; background: #292E37; box-shadow: inset 0px 1px 5px #000; text-shadow: 0px 1px 0px #000; color: #fff; }
.nav { position: relative; top: 38%; height: 100%; margin-right: 35px; display: inline-block; color: #fff; text-shadow: 0px 1px #000; }
.nav:hover { color: #EA5555; }
.nimage { float: left; width: 16px; height: 16px; position: relative; top: 5%; left: -20%; }
.home { background: url(site_images/icons/nav/home.png); }
.pricing { background: url(site_images/icons/nav/pricing.png); }
.features { background: url(site_images/icons/nav/features.png); }
.blog { background: url(site_images/icons/nav/blog.png); }
.contact { background: url(site_images/icons/nav/contact.png); }
.about { background: url(site_images/icons/nav/us.png); }
.logo { font-size: 2em; text-shadow: 0px 1px #000; padding-top: 10px; padding-left: 15px; color: #EA5555; font-family: Av, Helvetica, Arial, sans-serif; }
.red { color: #EA5555; }
.white { color: #fff; text-shadow: 0px 1px 0px #000; font-weight: bold; }
.dark { color: #202020; }
.center { text-align: center; }
.left { text-align: left; }
.right { text-align: right; }
.larger { font-size: 1.25em; }
.buttoni { -webkit-border-radius: 2px; -moz-border-radius: 0px; border-radius: 4px; background: #ddd; display: block; color: #ccc; font-size: 14pt; height: 50px; text-align: right; margin: 10px; cursor: pointer; color: #505050; }
.buttoni:hover { background: #EA5555; color: #fff; }
.btext { padding: 15px; position: relative; top: 25%; }
.groundi { background: url(ground_button.png); }
.skyi { background: url(sky_button.png); }
.stratospherei { background: url(stratosphere_button.png); }
.spacei { background: url(space_button.png); }
.image { height: 50px; width: 50px; float: left; border-top-left-radius: 5px; border-bottom-left-radius: 5px; }
li { color: #EA5555; }
li span { color: #505050; }
HTML:
<div class="space area" id="a4">
</div>
<div class="stratosphere area" id="a3">
</div>
<div class="sky area" id="a2">
</div>
<div class="ground area" id="a1">
</div>
JavaScript:
function scroll_to(id, speed, margin) {
$('html, body').animate({
scrollTop: $('#' + id).offset().top - margin
}, speed);
}
function match_height() {
var heights = [11, 630, 693, 756, 819, 882, 945, 1008, 1071, 1134, 1197, 1260, 1323, 1386, 1449, 1512, 1575, 1638, 1701, 1764, 1827, 1890, 1953, 2016, 2079, 2142, 2205, 2268, 2331, 2394, 2457, 2520];
var browsery = $(window).height();
var i = 0;
while(browsery > heights[i]) {
i++;
}
var h = heights[i];
$(".area").css("height", h + "px");
$(".area").css("width", "100%");
$(".ground").css("background", "url(scenes/ground/" + h + ".png)");
$(".sky").css("background", "url(scenes/sky/" + h + ".png)");
$(".stratosphere").css("background", "url(scenes/stratosphere/" + h + ".png)");
$(".space").css("background", "url(scenes/space/" + h + ".png)");
}
match_height();
var pos = 0;
$(".buttoni").click(function() {
var id = $(this).attr("id");
if(pos != id) {
scroll_to("a" + id, 2000, 0);
}
pos = id;
});
OP,
For browsers that support 3d transforms, e.g.: -webkit-transform, you could try the following:
your.div { -webkit-transform: translate3d(0,0,1px); }
Might not look like much, but doing the above causes the div in question to be hardware-accelerated.
Should you run into any flickering issues—they've been known to turn up in some cases—the following should sort you out:
your.div {
-webkit-transform: translate3d(0,0,1px);
-webkit-backface-visibility: hidden;
}
Via David Walsh - http://davidwalsh.name/translate3d
The use of translate3d pushes CSS animations into hardware acceleration. Even if you're looking to do a basic 2d translation, use translate3d for more power! If your animation is still flickering after switching to the transform above, you can use a few little-known CSS properties to try to fix the problem
Hope that helps.
As per my understanding, the issue and the solution drafted in the OP is two-fold:
initially, within the match_height() function, the OP author retrieves the images that best fits the screen height, so that upon completed animation the user sees one full background image.
after initial load, the user can navigate up and down the sections (with their respective background images) with the help of some buttons that trigger the scroll_to() function and its contained animation. Here is where the actual problem resides.
My efforts and the resulting fiddle focus on the scroll_to() function and the associated animation. I applied the following measures that, in conjunction, result in a (as per my subjective observation) 'smoother' scolling experience:
the original animation happened against 'html' and 'body', I'm reducing the jQuery selector to one selector only. In order to be able to use jQuery 1.9 (where jQuery.browser is deprecated) I'm using feature detection to get the 'right' selector:
function getScrollerSelector() {
var $body = $("<body/>");
$body.scrollTop(1);
return $body.scrollTop() == 1 ? "body" : "html";
}
In order to reduce the browser's processing load, I'm applying a logic that, per CSS, sets the background image of invisible sections to none during scrolling:
.scrolldown.scrollto-a2 #a1,
.scrolldown.scrollto-a3 #a1, .scrolldown.scrollto-a3 #a2,
.scrolldown.scrollfrom-a3 #a4,
.scrolldown.scrollfrom-a2 #a4, .scrolldown.scrollfrom-a2 #a3,
.scrollup.scrollto-a3 #a4,
.scrollup.scrollto-a2 #a4, .scrollup.scrollto-a2 #a3,
.scrollup.scrollfrom-a2 #a1,
.scrollup.scrollfrom-a3 #a1, .scrollup.scrollfrom-a3 #a2
{ background: none; }
I played around with linear easing, but that did not necessarily improve anything
All in all, scrolling doesn't seem choppy to me any more, but please take into account that this is also dependent on the client computers processing power.
Here's the scroll_to() function:
function scroll_to(id, speed, margin) {
var currentScrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
var scrollTop = $('#' + id).offset().top - margin;
var direction = scrollTop > currentScrollTop ? "down" : "up";
$("body").addClass("scroll"+direction + " scrollto-"+id + " scrollfrom-"+getScrollFrom(direction));
$( scrollerSelector ).animate({
scrollTop: scrollTop
}, {
//easing: 'linear',
duration: speed,
complete: function() {
$("body").removeClass("scrollup scrolldown scrollto-a1 scrollto-a2 scrollto-a3 scrollto-a4 scrollfrom-a1 scrollfrom-a2 scrollfrom-a3 scrollfrom-a4");
}
}
);
}
This is the link to jsfiddle
Since you are Scaling up the image, you can tell the Browser how to handle the rendering of image.
During the animation / scrolling, you can tell browser to Optimize on Speed and on completion of Animation / scrolling, Optimize on Quality.
Here is the CSS Property you can use on img: 'image-rendering' with values as optimizeSpeed / optimizeQuality.
https://developer.mozilla.org/en-US/docs/CSS/image-rendering
One thing you could do to images is smush it using http://www.smushit.com/ysmush.it/
this reduces the size of the image without loosing quality removing all unwanted meta data.
Testing locally it seems like your code should work ok, I have firefox 15 and chrome and don't see any lagging
What if you try this for the scroll to method?
function scroll_to(id, speed, margin) {
$('html, body').animate({
scrollTop: $('#' + id)
}, speed);
}
I had a similar problem with a website I was working on. In the end the problem seemed to be because of the large dimensions of the image that the computer/browser had to compute and render on screen.
My recommendation would be to try and reduce the amount of image that needs to be shown and scrolled on screen if possible.
Most modern browsers now support hardware (graphics card) rendering instead of the traditional (usually slower) software based (CPU) rendering. Hardware based rendering should in theory reduce that lag you're experiencing. However if your PC only has base or average graphics rendering capabilities, you're not going to have much success regardless. I personally had no success with either in Chrome, FireFox or IE until I gave in and removed the images.
As you can see
I want to somehow remove the dotted lines after the button has been clicked.Any ideas how ?
Thanks
GUYS : This is the current status of my CSS ansd HTML but still no USE:
.myButton input {
position:absolute;
display:block;
top: 5%;
left:87%;
height: 44px;
border:none;
cursor:pointer;
width: 43px;
font: bold 13px sans-serif;;
color:#333;
background: url("hover.png") 0 0 no-repeat;
text-decoration: none;
}
.myButton input:hover {
background-position: 0 -44px;
color: #049;
outline: 0;
}
.myButton input:active {
background-position: 0 -88px;
color:#fff;
outline: 0;
}
input:active, input:focus {
outline: 0;
}
<div class="myButton">
<input type="submit" value="">
</div>
Nothing seems to be happening !!
You have to style the <a> like:
a {outline: none}
use the below code
a:active
{
outline: none;
}
try for other browsers also
a:focus
{
-moz-outline-style: none;
}
a:focus { outline:none }
Possible with pure HTML as well:
...
And with JavaScript you can do that on all links:
window.onload = function WindowLoad(evt) {
//hide focus:
var arrLinks = document.getElementsByTagName("a");
for (var i = 0; i < arrLinks.length; i++) {
arrLinks[i].hideFocus = "true";
}
Despite my comment on your question,
You should keep them for
accessibility.
You can find your CSS-trick here for this
(Anyway, you should keep them.)
#myElement { outline: 0; }
Try this on your element, i dont now if is an image, div, button, link. But it works
If you want to keep the outline on active and on focus, but hide it on clicking a link, you can add in css:
A.No-Outline {outline-style:none;}
and use script:
$('A').hover(function() {
$(this).addClass('No-Outline');
},function() {
$(this).removeClass('No-Outline');
});
you must be hover befor clicking, so it does the job.