I want to show loading progress bar till the page load. If the internet might be slow and page take more to load, the progress bar show till the page fully load.
I attempted to add code, but because internet speeds vary, it is inaccurate. Could you please help me with this? I want to add a progress bar that starts at 0% while the page is loading and goes up to 100% after the page is completely loaded, dependent on the page loading speed.
$(window).on('load', function() {
$('#preloader').fadeOut(500);
$('body').removeClass('pre_loader');
});
var width = 100,
perfData = window.performance.timing, // The PerformanceTiming interface represents timing-related performance information for the given page.
EstimatedTime = -(perfData.loadEventEnd - perfData.navigationStart),
time = parseInt((EstimatedTime / 1000) % 60) * 100;
// Loadbar Animation
$(".loadbar").animate({
width: width + "%"
}, time);
// Percentage Increment Animation
function animateValue(id, start, end, duration) {
var range = end - start,
current = start,
increment = end > start ? 1 : -1,
stepTime = Math.abs(Math.floor(duration / range)),
obj = $(id);
var timer = setInterval(function() {
current += increment;
$(obj).text(current + "%");
//obj.innerHTML = current;
if (current == end) {
clearInterval(timer);
}
}, stepTime);
}
// Fading Out Loadbar on Finised
setTimeout(function() {
$('.preloader-wrap').fadeOut(100);
}, time);
<div class="preloader-wrap">
<div class="loader">
<div class="trackbar">
<div class="loadbar">
</div>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
Sound like CSS (only) animation would be an option to consider. Inline your progress bar and it's <style> first thing as the page loads. Then remove then and make the body visible again on page load event. You can cheat time if you use some easing function that will never finish.
If you need numbers in your progress bar, then there is an options for that; even by a variable in modern browsers https://css-tricks.com/animating-number-counters/
For example (need to play with the percent values a bit):
<!-- almost first thing on page -->
<style>
.container {
width: 400px;
height: 50px;
position: relative;
border: 1px solid black;
}
.progress {
background: blue;
float: left;
color: white;
width: 100%;
height: 50px;
line-height: 50px;
animation-name: slideInFromLeft;
animation-duration: 30s;
animation-timing-function: cubic-bezier(0, .9, .9, .999);
text-align: center;
}
.percent::before {
content: counter(count);
animation-name: counter;
animation-duration: 30s;
animation-timing-function: cubic-bezier(0, .9, .9, .999);
counter-reset: count 0;
}
#keyframes slideInFromLeft {
0% {
width: 0%;
}
99% {
width: 99%;
}
}
#keyframes counter {
0% {
counter-increment: count 0;
}
10% {
counter-increment: count 50;
}
20% {
counter-increment: count 60;
}
30% {
counter-increment: count 70;
}
40% {
counter-increment: count 80;
}
50% {
counter-increment: count 90;
}
60% {
counter-increment: count 95;
}
70% {
counter-increment: count 98;
}
80% {
counter-increment: count 99;
}
90% {
counter-increment: count 90;
}
100% {
counter-increment: count 100;
}
}
</style>
<div class="container">
<div class="progress">
<span class="percent">%</span>
</div>
</div>
Related
I'm attempting to mimic the following widget with HTML/CSS/JavaScript:
https://gyazo.com/76bee875d35b571bd08edbe73ead12cb
The way that I have it set up is the following:
I have a bar with a background color that has a gradient from red to green which is static.
I then have two blinders that is supposed to represent the negative space to give the illusion that the colored bars are animating (in reality, the blinders are simply sliding away)
I did it this way because I figured it might be easier instead of trying to animate the bar going in both directions, but now I'm not so sure lol. One requirement that I'm trying to keep is that the animation only deals with transform or opacity to take advantage of optimizations the browser can do (as described here: https://hacks.mozilla.org/2016/08/animating-like-you-just-dont-care-with-element-animate/)
The example has a few buttons to help test various things. The "Random positive" works great, and is exactly what I want. I haven't quite hooked up the negative yet tho because I'm not sure how to approach the problem of transitioning from positive to negative and vice-versa.
Ideally, when going from a positive to a negative, the right blinder will finish at the middle, and the left blinder will pick up the animation and finish off where it needs to go.
So for example, if the values is initially set to 40%, and the then set to -30%, the right blinder should animate transform: translateX(40%) -> transform: translateX(0%) and then the left blinder should animate from transform: translateX(0%) -> transform: translateX(-30%) to expose the red.
Also, the easing should be seamless.
I'm not sure if this is possible with the setup (specifically keeping the easing seamless, since the easing would be per-element, I think, and can't "carry over" to another element?)
Looking for guidance on how I can salvage this to produce the expected results, or if there's a better way to deal with this.
Note: I'm using jquery simply for ease with click events and whatnot, but this will eventually be in an application that's not jquery aware.
Here's my current attempt: https://codepen.io/blitzmann/pen/vYLrqEW
let currentPercentageState = 0;
function animate(percentage) {
var animation = [{
transform: `translateX(${currentPercentageState}%)`,
easing: "ease-out"
},
{
transform: `translateX(${percentage}%)`
}
];
var timing = {
fill: "forwards",
duration: 1000
};
$(".blind.right")[0].animate(animation, timing);
// save the new value so that the next iteration has a proper from keyframe
currentPercentageState = percentage;
}
$(document).ready(function() {
$(".apply").click(function() {
animate($("#amount").val());
});
$(".reset").click(function() {
animate(0);
});
$(".random").click(function() {
var val = (Math.random() * 2 - 1) * 100;
$("#amount").val(val);
animate(val);
});
$(".randomPos").click(function() {
var val = Math.random() * 100;
$("#amount").val(val);
animate(val);
});
$(".randomNeg").click(function() {
var val = Math.random() * -100;
$("#amount").val(val);
animate(val);
});
$(".toggleBlinds").click(function() {
$(".blind").toggle();
});
$(".toggleLeft").click(function() {
$(".blind.left").toggle();
});
$(".toggleRight").click(function() {
$(".blind.right").toggle();
});
});
$(document).ready(function() {});
.wrapper {
margin: 10px;
height: 10px;
width: 800px;
background: linear-gradient(to right, red 50%, green 50%);
border: 1px solid black;
box-sizing: border-box;
position: relative;
overflow: hidden;
}
.blind {
height: 100%;
position: absolute;
top: 0;
background-color: rgb(51, 51, 51);
min-width: 50%;
}
.blind.right {
left: 50%;
border-left: 1px solid white;
transform-origin: left top;
}
.blind.left {
border-right: 1px solid white;
transform-origin: left top;
}
<div class="wrapper">
<div class='blind right'></div>
<div class='blind left'></div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.0/jquery.min.js" type="text/javascript"></script>
<input id="amount" type="number" placeholder="Enter percentage..." value='40' />
<button class="apply">Apply</button>
<button class="random">Random</button>
<button class="randomPos">Random Positive</button>
<button class="randomNeg">Random Negative</button>
<button class="toggleBlinds">Toggle Blinds</button>
<button class="toggleLeft">Toggle L Blind</button>
<button class="toggleRight">Toggle R Blind</button>
<button class="reset" href="#">Reset</button>
I've modified your code. Have a look at the code.
let currentPercentageState = 0;
function animate(percentage) {
var animation = [{
transform: `translateX(${currentPercentageState}%)`,
easing: "ease-out"
},
{
transform: `translateX(${percentage}%)`
}
];
var timing = {
fill: "forwards",
duration: 1000
};
if (percentage < 0) {
$(".blind.right")[0].animate(
[{
transform: `translateX(0%)`,
easing: "ease-out"
},
{
transform: `translateX(0%)`
}
], timing);
$(".blind.left")[0].animate(animation, timing);
} else {
$(".blind.left")[0].animate(
[{
transform: `translateX(0%)`,
easing: "ease-out"
},
{
transform: `translateX(0%)`
}
], timing);
$(".blind.right")[0].animate(animation, timing);
}
// save the new value so that the next iteration has a proper from keyframe
//currentPercentageState = percentage;
}
$(document).ready(function() {
$(".apply").click(function() {
animate($("#amount").val());
});
$(".reset").click(function() {
animate(0);
});
$(".random").click(function() {
var val = (Math.random() * 2 - 1) * 100;
$("#amount").val(val);
animate(val);
});
$(".randomPos").click(function() {
var val = Math.random() * 100;
$("#amount").val(val);
animate(val);
});
$(".randomNeg").click(function() {
var val = Math.random() * -100;
$("#amount").val(val);
animate(val);
});
$(".toggleBlinds").click(function() {
$(".blind").toggle();
});
$(".toggleLeft").click(function() {
$(".blind.left").toggle();
});
$(".toggleRight").click(function() {
$(".blind.right").toggle();
});
});
$(document).ready(function() {});
.wrapper {
margin: 10px;
height: 10px;
width: 800px;
background: linear-gradient(to right, red 50%, green 50%);
border: 1px solid black;
box-sizing: border-box;
position: relative;
overflow: hidden;
}
.blind {
height: 100%;
position: absolute;
top: 0;
background-color: rgb(51, 51, 51);
min-width: 50%;
}
.blind.right {
left: 50%;
border-left: 1px solid white;
transform-origin: left top;
}
.blind.left {
border-right: 1px solid white;
transform-origin: left top;
}
<div class="wrapper">
<div class='blind right'></div>
<div class='blind left'></div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.0/jquery.min.js" type="text/javascript"></script>
<input id="amount" type="number" placeholder="Enter percentage..." value='40' />
<button class="apply">Apply</button>
<button class="random">Random</button>
<button class="randomPos">Random Positive</button>
<button class="randomNeg">Random Negative</button>
<button class="toggleBlinds">Toggle Blinds</button>
<button class="toggleLeft">Toggle L Blind</button>
<button class="toggleRight">Toggle R Blind</button>
<button class="reset" href="#">Reset</button>
You need to animate the things in two steps. The first step is to reset the previous state to initial state(which should be set to 0) and in the second step, you need to run the other animation which will actually move it to the destination state.
In order to achive this you can do,
let currentPercentageState = 0;
const animationTiming = 300;
function animate(percentage) {
let defaultTranformVal = [{
transform: `translateX(${currentPercentageState}%)`,
easing: "ease-out"
}, {transform: `translateX(0%)`}];
var animation = [{
transform: `translateX(0%)`,
easing: "ease-out"
},{
transform: `translateX(${percentage}%)`,
easing: "ease-out"
}];
var timing = {
fill: "forwards",
duration: animationTiming
};
if (percentage < 0) {
if(currentPercentageState > 0) {
$(".blind.right")[0].animate(defaultTranformVal, timing);
setTimeout(() => {
$(".blind.left")[0].animate(animation, timing);
}, animationTiming);
} else {
$(".blind.left")[0].animate(animation, timing);
}
}
if(percentage > 0) {
if(currentPercentageState < 0) {
$(".blind.left")[0].animate(defaultTranformVal, timing);
setTimeout(() => {
$(".blind.right")[0].animate(animation, timing);
}, animationTiming);
} else {
$(".blind.right")[0].animate(animation, timing);
}
}
// save the new value so that the next iteration has a proper from keyframe
currentPercentageState = percentage;
}
Here, you will see we have two transformations. The first one defaultTranformVal will move the currentPercentageState to zero and then the other one which will move from 0 to percentage.
You need to handle a couple of conditions here. The first one is if you are running it the first time(means there is no currentPercentageState), you don't need to run defaultTranformVal. If you have currentPercentageState then you need to run defaultTranformVal and then run the second animation.
Note:- You also need to clear the timeout in order to prevent the memory leak. This can be handle by storing the setTimout return value and then when next time it's running clear the previous one with the help of clearTimeout.
Here is the updated codepen example:-
https://codepen.io/gauravsoni119/pen/yLeZBmb?editors=0011
EDIT: I actually did manage to solve this!
let easing = "cubic-bezier(0.5, 1, 0.89, 1)";
let duration = 1000;
let easeReversal = y => 1 - Math.sqrt((y-1)/-1)
https://codepen.io/blitzmann/pen/WNrBWpG
I gave it my own cubic-bezier function of which I know the reversal for. The post below and my explanation was based on an easing function using sin() which isn't easily reversible. Not only that, but the built in easing function for ease-out doesn't match the sin() one that I had a reference for (I'm not really sure what the build in one is based on). But I realized I could give it my own function that I knew the reversal for, and boom, works like a charm!
This has been a very informative experience for me, I'm glad that I've got a solution that works. I still think I'll dip my toes in the other ideas that I had to see which pans out better in the long term.
Historical post:
So, after a few nights of banging my head around on this, I've come to the conclusion that this either isn't possible the way I was thinking about doing it, or if it is possible then the solution is so contrived that it's probably not worth it and I'd be better off developing a new solution (of which I've thought of one or tow things that I'd like to try).
Please see this jsfiddle for my final "solution" and a post-mortem
https://jsfiddle.net/blitzmann/zc80p1n4/
let currentPercentageState = 0;
let easing = "linear";
let duration = 1000;
function animate(percentage) {
percentage = parseFloat(percentage);
// determine if we've crossed the 0 threshold, which would force us to do something else here
let threshold = currentPercentageState / percentage < 0;
console.log("Crosses 0: " + threshold);
if (!threshold && percentage != 0) {
// determine which blind we're animating
let blind = percentage < 0 ? "left" : "right";
$(`.blind.${blind}`)[0].animate(
[
{
transform: `translateX(${currentPercentageState}%)`,
easing: easing
},
{
transform: `translateX(${percentage}%)`
}
],
{
fill: "forwards",
duration: duration
}
);
} else {
// this happens when we cross the 0 boundry
// we'll have to create two animations - one for moving the currently offset blind back to 0, and then another to move the second blind
let firstBlind = percentage < 0 ? "right" : "left";
let secondBlind = percentage < 0 ? "left" : "right";
// get total travel distance
let delta = currentPercentageState - percentage;
// find the percentage of that travel that the first blind is responsible for
let firstTravel = currentPercentageState / delta;
let secondTravel = 1 - firstTravel;
console.log("delta; total values to travel: ", delta);
console.log(
"firstTravel; percentage of the total travel that should be done by the first blind: ",
firstTravel
);
console.log(
"secondTravel; percentage of the total travel that should be done by the second blind: ",
secondTravel
);
// animate the first blind.
$(`.blind.${firstBlind}`)[0].animate(
[
{
transform: `translateX(${currentPercentageState}%)`,
easing: easing
},
{
// we go towards the target value instead of 0 since we'll cut the animation short
transform: `translateX(${percentage}%)`
}
],
{
fill: "forwards",
duration: duration,
// cut the animation short, this should run the animation to this x value of the easing function
iterations: firstTravel
}
);
// animate the second blind
$(`.blind.${secondBlind}`)[0].animate(
[
{
transform: `translateX(${currentPercentageState}%)`,
easing: easing
},
{
transform: `translateX(${percentage}%)`
}
],
{
fill: "forwards",
duration: duration,
// start the iteration where the first should have left off. This should put up where the easing function left off
iterationStart: firstTravel,
// we only need to carry this aniamtion the rest of the way
iterations: 1-firstTravel,
// delay this animation until the first "meets" it
delay: duration * firstTravel
}
);
}
// save the new value so that the next iteration has a proper from keyframe
currentPercentageState = percentage;
}
// the following are just binding set ups for the buttons
$(document).ready(function () {
$(".apply").click(function () {
animate($("#amount").val());
});
$(".reset").click(function () {
animate(0);
});
$(".random").click(function () {
var val = (Math.random() * 2 - 1) * 100;
$("#amount").val(val);
animate(val);
});
$(".randomPos").click(function () {
var val = Math.random() * 100;
$("#amount").val(val);
animate(val);
});
$(".randomNeg").click(function () {
var val = Math.random() * -100;
$("#amount").val(val);
animate(val);
});
$(".flipSign").click(function () {
animate(currentPercentageState * -1);
});
$(".toggleBlinds").click(function () {
$(".blind").toggle();
});
$(".toggleLeft").click(function () {
$(".blind.left").toggle();
});
$(".toggleRight").click(function () {
$(".blind.right").toggle();
});
});
animate(50);
//setTimeout(()=>animate(-100), 1050)
$(function () {
// Build "dynamic" rulers by adding items
$(".ruler[data-items]").each(function () {
var ruler = $(this).empty(),
len = Number(ruler.attr("data-items")) || 0,
item = $(document.createElement("li")),
i;
for (i = -11; i < len - 11; i++) {
ruler.append(item.clone().text(i + 1));
}
});
// Change the spacing programatically
function changeRulerSpacing(spacing) {
$(".ruler")
.css("padding-right", spacing)
.find("li")
.css("padding-left", spacing);
}
changeRulerSpacing("30px");
});
.wrapper {
margin: 10px auto 2px;
height: 10px;
width: 600px;
background: linear-gradient(to right, red 50%, green 50%);
border: 1px solid black;
box-sizing: border-box;
position: relative;
overflow: hidden;
}
.blind {
height: 100%;
position: absolute;
top: 0;
background-color: rgb(51, 51, 51);
min-width: 50%;
}
.blind.right {
left: 50%;
border-left: 1px solid white;
transform-origin: left top;
}
.blind.left {
border-right: 1px solid white;
transform-origin: left top;
}
#buttons {
text-align: center;
}
/* Ruler crap */
.ruler-container {
text-align: center;
}
.ruler, .ruler li {
margin: 0;
padding: 0;
list-style: none;
display: inline-block;
}
/* IE6-7 Fix */
.ruler, .ruler li {
*display: inline;
}
.ruler {
display:inline-block;
margin: 0 auto;https://jsfiddle.net/user/login/
background: lightYellow;
box-shadow: 0 -1px 1em hsl(60, 60%, 84%) inset;
border-radius: 2px;
border: 1px solid #ccc;
color: #ccc;
height: 3em;
padding-right: 1cm;
white-space: nowrap;
margin-left: 1px;
}
.ruler li {
padding-left: 1cm;
width: 2em;
margin: .64em -1em -.64em;
text-align: center;
position: relative;
text-shadow: 1px 1px hsl(60, 60%, 84%);
}
.ruler li:before {
content: '';
position: absolute;
border-left: 1px solid #ccc;
height: .64em;
top: -.64em;
right: 1em;
}
<div class="wrapper">
<div class='blind right'></div>
<div class='blind left'></div>
</div>
<div class="ruler-container">
<ul class="ruler" data-items="21"></ul>
</div>
<div id="buttons">
<input id="amount" type="number" placeholder="Enter percentage..." value='-80' />
<button class="apply">Apply</button>
<button class="random">Random</button>
<button class="randomPos">Random Positive</button>
<button class="randomNeg">Random Negative</button>
<button class="flipSign">Flip Sign</button>
<button class="toggleBlinds">Toggle Blinds</button>
<button class="toggleLeft">Toggle L Blind</button>
<button class="toggleRight">Toggle R Blind</button>
<button class="reset" href="#">Reset</button>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.0/jquery.min.js" type="text/javascript"></script>
<hr />
<p><strong>A note</strong> on the attempt made here:</p>
<p>
I was trying to animate a percentage bar that has both positive and negative values. But I set a challenge as well: I wanted to achieve this via animations utilizing only the compositor - which means animating opacity or transform <strong>only</strong> (no color, width, height, position, etc). The ideas presented here were based on the concept of blinds. I have a static element with a background gradient of red to green, then I have two elements that "blind" the user to the background. These blinds, being a simple element, simply slide into and out of place.
</p>
<p>The problem that I ran into was timing the two animations correctly when they switched signage. It's currently working (very well) for linear animation, but as soon as you introduce an easing function it gets wonky. The reason for this is due to the value that I'm using to set the first animation length (iteration, not duration), as well as the second animations start to pick up where the first left off. The value that I was using is the percentage of the total travel distance that each of the blinds will have to do.</p>
<p>So, for example, if you have a value of 50, and go to -80, that's a total travel distance of 130. The first blind travels <code>50 / 130 = ~0.3846</code> of the total distance, and the second blind will travel <code>1 - ~0.3846 = ~0.6154</code> of the total distance.</p>
<p>But, these are not the correct values for the <em>duration</em> of the animation. Instead, these are the percentages of the easing values (the y-axis). To get the duration for these, I would have to find the x value (given the known y value). eg, for an ease-out animation for a value going from 50 to -80, the animation crosses our 0 at ~0.03846, and we would have to solve for x given <code>0.03846 = sin((x * PI) / 2)</code>.</p>
<p>With the help of Wolfram Alpha, I was able to find a few test values this got me much closer to the actual animation, but the blinds always stopped slightly off the mark. I eventually chalked this up to one of two reasons: the fact that the valuess are always going to be approximate and the browser is never going to be 100% accurate, or / and 2) the browser is using a slightly different easing function than I was using for reference. Regardless, being so constrained by the fact that this "animation" relies on two different aniamtions lining up perfectly, I decided to leave this version be and go in a different direction.</p>
<p>
If anyone finds an actual solution to this, please post an answer here: https://stackoverflow.com/questions/62866844/how-to-animate-a-progress-bar-with-negatives-using-element-animate
</p>
Thanks to those that attempted this admittedly tricky problem
I created a page where the background colors of a div change every so often. I want to make it so that when the mouse is over(or hovers) the color changer pauses where it is, as long as the mouse hovers there. And when the mouse no longer hovers the div, the colors continue to change where it left off. The closest examples I ran into on this website used JQuery solutions. I am not looking for a JQuery solution. I am looking for a javascript solution. I appreciate any and all of your responses. Thank You!
var dammit = document.getElementById("muck");
var colorChange = document.getElementById("color-changer");
var colors = ["red", "blue", "green", "pink"];
var counter = 0;
function changer() {
if (counter >= colors.length) {
counter = 0;
};
colorChange.style.background = colors[counter];
counter++;
};
var myTimer = setInterval(changer, 3000);
body {
background: #FDCA40;
margin: 0;
padding: 0;
-webkit-transition: background 0.9s;
-moz-transition: background 0.9s;
transition: background 0.9s;
}
div#muck {
width: 100%;
height: 100vh;
}
<body id="color-changer">
<div id="muck"></div>
</body>
There is no way to pause a timer, but you can just stop the currently running one and then start a new one.
(FYI: All browsers that are within 5 years old at least support CSS transitions. No need to vendor prefix that.)
var source = document.getElementById("muck");
var colorChange = document.getElementById("color-changer");
var colors = ["red", "blue", "green", "pink"];
var counter = 0;
function changer(){
if (counter >= colors.length){
counter = 0;
};
colorChange.style.background = colors[counter];
counter++;
};
var myTimer = setInterval(changer, 1000);
// Stop the current timer when mouseover
source.addEventListener("mouseover", function(){ clearInterval(myTimer)});
// Start a new timer when mouse out
source.addEventListener("mouseout", function(){ myTimer = setInterval(changer, 1000);});
body{
background: #FDCA40;
margin: 0;
padding: 0;
transition: background 0.9s;
}
div#muck{
width: 100%;
height: 100vh;
}
<body id="color-changer">
<div id="muck"></div>
</body>
You can do this purely in CSS but you need to use animation. I also added some CSS variables so the animation is easier to change.
body {
background: #FDCA40;
margin: 0;
padding: 0;
}
/* Safari 4.0 - 8.0 */
#-webkit-keyframes example {
from {background-color: red;}
to {background-color: yellow;}
}
#keyframes example {
0% {background-color: red;}
20% {background-color: blue;}
40% {background-color: green;}
80% {background-color: pink;}
100% {background-color: red;}
}
div#muck {
--animation-transition-speed: 0.9s;
--number-of-colors: 4;
width: 100%;
height: 100vh;
-webkit-animation-name: example;
-webkit-animation-duration: calc(var(--animation-transition-speed) * var(--number-of-colors));
animation-name: example;
animation-duration: calc(var(--animation-transition-speed) * var(--number-of-colors));
animation-iteration-count: infinite;
}
div#muck:hover {
animation-play-state: paused;
}
<body id="color-changer">
<div id="muck"></div>
</body>
While this doesnt really pouse the interval it mimics what you need very closely..
You can use a flag.. something like this:
var output = document.getElementById('id')
var isPaused = false;
var counter = 0;
window.setInterval(function() {
if(!isPaused) {
counter++;
if (counter >= colors.length) {
counter = 0;
};
colorChange.style.background = colors[counter];
}
}, 1000);
document.getElementById('muck').addEventListener('mouseenter', function(e) {
isPaused = true;
});
document.getElementById('muck').addEvenetListener('mouseleave', function(e) {
isPaused = false;
});
from Javascript - Pausing setInterval()
I found a pen online to create image carousel, problem is I can't get it display 3 items inside a container.
I have tried removing the opacity for the carousel photo but then it messes up the display for the full container.
Here is link to my fiddle:
!(function(d) {
// Variables to target our base class, get carousel items, count how many carousel items there are, set the slide to 0 (which is the number that tells us the frame we're on), and set motion to true which disables interactivity.
var itemClassName = "carousel__photo";
items = d.getElementsByClassName(itemClassName),
totalItems = items.length,
slide = 0,
moving = false;
// To initialise the carousel we'll want to update the DOM with our own classes
function setInitialClasses() {
// Target the last, initial, and next items and give them the relevant class.
// This assumes there are three or more items.
items[totalItems - 1].classList.add("prev");
items[0].classList.add("active");
items[1].classList.add("next");
}
// Set click events to navigation buttons
function setEventListeners() {
var next = d.getElementsByClassName('carousel__button--next')[0],
prev = d.getElementsByClassName('carousel__button--prev')[0];
next.addEventListener('click', moveNext);
prev.addEventListener('click', movePrev);
}
// Disable interaction by setting 'moving' to true for the same duration as our transition (0.5s = 500ms)
function disableInteraction() {
moving = true;
setTimeout(function() {
moving = false
}, 500);
}
function moveCarouselTo(slide) {
// Check if carousel is moving, if not, allow interaction
if (!moving) {
// temporarily disable interactivity
disableInteraction();
// Preemptively set variables for the current next and previous slide, as well as the potential next or previous slide.
var newPrevious = slide - 1,
newNext = slide + 1,
oldPrevious = slide - 2,
oldNext = slide + 2;
// Test if carousel has more than three items
if ((totalItems - 1) > 3) {
// Checks if the new potential slide is out of bounds and sets slide numbers
if (newPrevious <= 0) {
oldPrevious = (totalItems - 1);
} else if (newNext >= (totalItems - 1)) {
oldNext = 0;
}
// Check if current slide is at the beginning or end and sets slide numbers
if (slide === 0) {
newPrevious = (totalItems - 1);
oldPrevious = (totalItems - 2);
oldNext = (slide + 1);
} else if (slide === (totalItems - 1)) {
newPrevious = (slide - 1);
newNext = 0;
oldNext = 1;
}
// Now we've worked out where we are and where we're going, by adding and removing classes, we'll be triggering the carousel's transitions.
// Based on the current slide, reset to default classes.
items[oldPrevious].className = itemClassName;
items[oldNext].className = itemClassName;
// Add the new classes
items[newPrevious].className = itemClassName + " prev";
items[slide].className = itemClassName + " active";
items[newNext].className = itemClassName + " next";
}
}
}
// Next navigation handler
function moveNext() {
// Check if moving
if (!moving) {
// If it's the last slide, reset to 0, else +1
if (slide === (totalItems - 1)) {
slide = 0;
} else {
slide++;
}
// Move carousel to updated slide
moveCarouselTo(slide);
}
}
// Previous navigation handler
function movePrev() {
// Check if moving
if (!moving) {
// If it's the first slide, set as the last slide, else -1
if (slide === 0) {
slide = (totalItems - 1);
} else {
slide--;
}
// Move carousel to updated slide
moveCarouselTo(slide);
}
}
// Initialise carousel
function initCarousel() {
setInitialClasses();
setEventListeners();
// Set moving to false now that the carousel is ready
moving = false;
}
// make it rain
initCarousel();
}(document));
/* Parent wrapper to carousel. Width can be changed as needed. */
.carousel-wrapper {
overflow: hidden;
width: 90%;
margin: auto;
}
.carousel-custom-section {
width: 100%;
display: flex;
}
.carousel-single-item {
width: 33%;
display: flex;
}
.carousel-single-item-row {
display: flex;
width: 33%;
flex-direction: row;
}
.carousel-wrapper * {
box-sizing: border-box;
}
.carousel {
-webkit-transform-style: preserve-3d;
-moz-transform-style: preserve-3d;
transform-style: preserve-3d;
}
.carousel__photo {
opacity: 0;
position: absolute;
top: 0;
width: 100%;
margin: auto;
padding: 1rem 4rem;
z-index: 100;
/* transition: transform .5s, opacity .5s, z-index .5s; */
}
.carousel__photo.initial,
.carousel__photo.active {
opacity: 1;
position: relative;
z-index: 900;
}
.carousel__photo.prev,
.carousel__photo.next {
z-index: 800;
}
/* Style navigation buttons to sit in the middle, either side of the carousel. */
.carousel__button--prev,
.carousel__button--next {
position: absolute;
top: 50%;
width: 3rem;
height: 3rem;
background-color: #FFF;
transform: translateY(-50%);
border-radius: 50%;
cursor: pointer;
z-index: 1001;
}
.carousel__button--prev {
left: 0;
}
.carousel__button--next {
right: 0;
}
/* Use pseudo elements to insert arrows inside of navigation buttons */
.carousel__button--prev::after,
.carousel__button--next::after {
content: " ";
position: absolute;
width: 10px;
height: 10px;
top: 50%;
left: 54%;
border-right: 2px solid black;
border-bottom: 2px solid black;
transform: translate(-50%, -50%) rotate(135deg);
}
.carousel__button--next::after {
left: 47%;
transform: translate(-50%, -50%) rotate(-45deg);
}
<div class="carousel-wrapper">
<div class="carousel">
<div class="carousel-custom-section">
<div class="carousel-single-item">
<img class="carousel__photo initial" src="https://via.placeholder.com/150/0000FF/808080?text=one">
</div>
<div class="carousel-single-item">
<img class="carousel__photo" src="https://via.placeholder.com/150/FF0000/808080?text=two">
</div>
<div class="carousel-single-item">
<img class="carousel__photo" src="https://via.placeholder.com/150/00FF00/808080?text=three">
</div>
</div>
<div class="carousel-custom-section">
<div class="carousel-single-item">
<img class="carousel__photo" src="https://via.placeholder.com/150/FF0000/808080?text=four">
</div>
<div class="carousel-single-item">
<img class="carousel__photo" src="https://via.placeholder.com/150/00FF00/808080?text=five">
</div>
<div class="carousel-single-item">
<img class="carousel__photo" src="https://via.placeholder.com/150/00FF00/808080?text=six">
</div>
</div>
<div class="carousel__button--next"></div>
<div class="carousel__button--prev"></div>
</div>
</div>
Can somebody please point me in right direction what I am doing wrong?
I implemented a infinite loop animation using setInterval. I now like to change the implementation to requestAnimationFrame() so that I will have performance which I am after. For some reasons, requestAnimationFrame() does not call the function supplied to it.
My code looks like this;
var index = 0;
var $btn = $('.btn');
function btnBlinkRun() {
if (index < 2) {
index = index + 1;
} else {
index = 0;
}
$('#ani--scaleinout').removeAttr('id');
$($btn[index]).attr('id', 'ani--scaleinout');
window.requestAnimationFrame(btnBlinkRun);
}
btnBlinkRun();
.btn{
width: 30px;
height: 30px;
background: blue;
border-radius: 100%;
margin-bottom: 10px;
}
#ani--scaleinout {
animation: zoominout 1s ease-in;
}
#keyframes zoominout {
50% {
transform: scale(1.4);
}
100% {
transform: scale(1);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<div class="btn" id="ani--scaleinout"></div>
<div class="btn"></div>
<div class="btn"></div>
</div>
It looks like what's going on is you are firing requestAnimationFrame multiple times per second. Your css animation has a duration of 1s. But you are removing the attribute every x ms.
It is triggering, it's just happening so fast you can't see it. To demonstrate change your call to window.requestAnimationFrame to use a setTimeout and you'll notice the animation:
setTimeout(function() {
window.requestAnimationFrame(btnBlinkRun);
}, 1000);
Not saying this is a preferred solution, but explaining why this is happening.
It executes alright. But it does not do what you want it to, i presume.
Animation frame fires on every single rending frame (e.g. 60fps) and not on CSS animation keyframes.
The animationend event is your friend here.
var index = 0;
var buttons = document.querySelectorAll('.btn');
function btnBlinkRun() {
if (index < 2) {
index = index + 1;
} else {
index = 0;
}
const element = document.querySelector('#ani--scaleinout');
element.id = null;
buttons[index].id = 'ani--scaleinout';
buttons[index].addEventListener("animationend", btnBlinkRun, { once: true });
}
btnBlinkRun();
.btn{
width: 30px;
height: 30px;
background: blue;
border-radius: 100%;
margin-bottom: 10px;
}
#ani--scaleinout {
animation: zoominout 1s ease-in;
}
#keyframes zoominout {
50% {
transform: scale(1.4);
}
100% {
transform: scale(1);
}
}
<div>
<div class="btn" id="ani--scaleinout"></div>
<div class="btn"></div>
<div class="btn"></div>
</div>
I have been trying using jquery animate to do a running text. But I can't seems to get it run in an endless loop. It always runs one time only..
/* js: */
$(document).ready(function(){
function scroll() {
$('.scroll').animate({
right: $(document).width()
}, 8000, scroll);
}
scroll();
});
/* css: */
.scroll {
position: absolute;
right: -200px;
width: 200px;
}
<!-- html: -->
<div class="scroll">This text be scrollin'!</div>
This is the demo:
https://jsfiddle.net/y9hvr9fa/1/
Do you guys know how to fix it?
So this is what I did:
Precalculate $(document).width() as if a horizontal scroll appears, the width will change in the next iteration
Remove the width you have set for scroll so that the width is only as long as the content - and you would have to give white-space:nowrap to keep the text in a line.
In the animate use the width of the scroll text using $('.scroll').outerWidth()
See demo below and update fiddle here
$(document).ready(function() {
// initialize
var $width = $(document).width();
var $scrollWidth = $('.scroll').outerWidth();
$('.scroll').css({'right': -$scrollWidth + 'px'});
// animate
function scroll() {
$('.scroll').animate({
right: $width
}, 8000, 'linear', function() {
$('.scroll').css({'right': -$scrollWidth + 'px'});
scroll();
});
}
scroll();
});
body {
overflow: hidden;
}
.scroll {
position: absolute;
white-space: nowrap;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="scroll">This text be scrollin'!</div>
Let me know your feedback on this, thanks!
CSS Alternative:
Alternatively you could use a CSS transition like in this CodePen:
https://codepen.io/jamesbarnett/pen/kfmKa
More advanced:
$(document).ready(function(){
var scroller = $('#scroller'); // scroller $(Element)
var scrollerWidth = scroller.width(); // get its width
var scrollerXPos = window.innerWidth; // init position from window width
var speed = 1.5;
scroller.css('left', scrollerXPos); // set initial position
function moveLeft() {
if(scrollerXPos <= 0 - scrollerWidth) scrollerXPos = window.innerWidth;
scrollerXPos -= speed;
scroller.css('left', scrollerXPos);
window.requestAnimationFrame(moveLeft);
}
window.requestAnimationFrame(moveLeft);
});
.scroll {
display: block;
position: absolute;
overflow: visible;
white-space: nowrap;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="scroller" class="scroll">This text be scrollin'!</div>
Dirty solution (my original answer):
In this example this would be a quick fix:
The text is running to the left without ever stopping. Here you will tell the text to always start at that position. (After the time has run up - meaning not necessarily just when it has left the screen)
$(document).ready(function(){
function scroll() {
$('.scroll').css('right', '-200px').animate({
right: $(document).width()
}, 8000, scroll);
}
scroll();
});
I have been trying using jquery animate to do a running text.
You know that the <marquee> HTML element works, right?
Which means you don't need CSS, Javascript or jQuery.
Pure HTML Solution:
<marquee>This text be scrollin'!</marquee>
The <marquee> element includes a large number of optional declarative attributes which control the behaviour of the scrolling text:
behavior
bgcolor
direction
height
hspace
loop
scrollamount
scrolldelay
truespeed
vspace
width
Further Reading:
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/marquee
Note 1:
The resource above correctly notes that:
This feature is no longer recommended. Though some browsers might
still support it, it may have already been removed from the relevant
web standards, may be in the process of being dropped, or may only be
kept for compatibility purposes.
Note 2
The same resource also recommends:
see the compatibility table at the bottom of this page to guide your decision
And... a cursory look at that compatibility table shows that the <marquee> element is as browser-compatible as the most established, most browser-compatible elements which exist today.
I hope it is useful :)
function start() {
new mq('latest-news');
mqRotate(mqr);
}
window.onload = start;
function objWidth(obj) {
if (obj.offsetWidth) return obj.offsetWidth;
if (obj.clip) return obj.clip.width;
return 0;
}
var mqr = [];
function mq(id) {
this.mqo = document.getElementById(id);
var wid = objWidth(this.mqo.getElementsByTagName("span")[0]) + 5;
var fulwid = objWidth(this.mqo);
var txt = this.mqo.getElementsByTagName("span")[0].innerHTML;
this.mqo.innerHTML = "";
var heit = this.mqo.style.height;
this.mqo.onmouseout = function () {
mqRotate(mqr);
};
this.mqo.onmouseover = function () {
clearTimeout(mqr[0].TO);
};
this.mqo.ary = [];
var maxw = Math.ceil(fulwid / wid) + 1;
for (var i = 0; i < maxw; i++) {
this.mqo.ary[i] = document.createElement("div");
this.mqo.ary[i].innerHTML = txt;
this.mqo.ary[i].style.position = "absolute";
this.mqo.ary[i].style.left = wid * i + "px";
this.mqo.ary[i].style.width = wid + "px";
this.mqo.ary[i].style.height = heit;
this.mqo.appendChild(this.mqo.ary[i]);
}
mqr.push(this.mqo);
}
function mqRotate(mqr) {
if (!mqr) return;
for (var j = mqr.length - 1; j > -1; j--) {
maxa = mqr[j].ary.length;
for (var i = 0; i < maxa; i++) {
var x = mqr[j].ary[i].style;
x.left = parseInt(x.left, 10) - 1 + "px";
}
var y = mqr[j].ary[0].style;
if (parseInt(y.left, 10) + parseInt(y.width, 10) < 0) {
var z = mqr[j].ary.shift();
z.style.left = parseInt(z.style.left) + parseInt(z.style.width) * maxa + "px";
mqr[j].ary.push(z);
}
}
mqr[0].TO = setTimeout("mqRotate(mqr)", 20);
}
.marquee {
position: relative;
overflow: hidden;
text-align: center;
margin: 0 auto;
width: 100%;
height: 30px;
display: flex;
align-items: center;
white-space: nowrap;
}
#latest-news {
line-height: 32px;
a {
color: #555555;
font-size: 13px;
font-weight: 300;
&:hover {
color: #000000;
}
}
span {
font-size: 18px;
position: relative;
top: 4px;
color: #999999;
}
}
<div id="latest-news" class="marquee">
<span style="white-space:nowrap;">
<span> •</span>
one Lorem ipsum dolor sit amet
<span> •</span>
two In publishing and graphic design
<span> •</span>
three Lorem ipsum is a placeholder text commonly
</span>
</div>
How is this?
.scroll {
height: 50px;
overflow: hidden;
position: relative;
}
.scroll p{
position: absolute;
width: 100%;
height: 100%;
margin: 0;
line-height: 50px;
text-align: center;
-moz-transform:translateX(100%);
-webkit-transform:translateX(100%);
transform:translateX(100%);
-moz-animation: scroll 8s linear infinite;
-webkit-animation: scroll 8s linear infinite;
animation: scroll 8s linear infinite;
}
#-moz-keyframes scroll {
0% { -moz-transform: translateX(100%); }
100% { -moz-transform: translateX(-100%); }
}
#-webkit-keyframes scroll {
0% { -webkit-transform: translateX(100%); }
100% { -webkit-transform: translateX(-100%); }
}
#keyframes scroll {
0% {
-moz-transform: translateX(100%);
-webkit-transform: translateX(100%);
transform: translateX(100%);
}
100% {
-moz-transform: translateX(-100%);
-webkit-transform: translateX(-100%);
transform: translateX(-100%);
}
}
<div class="scroll"><p>This text be scrollin'!</p></div>