Crossfading Background Images - javascript

I am trying to crossfade and cycle through a series of 5 images which is a full screen background image.
I am applying the following css class to body.
body {
display: table;
margin:0px;
height:100%;
background-image:url('images/image1.jpg') ;
background-size: 1500px auto;
-webkit-font-smoothing: subpixel-antialiased !important;
}
I would like to replace background-image with the next image in sequence i.e. images/image2.jpg, images/image3.jpg, every 8 seconds, with the prior image fading out and the new image fading in, and being able to control the speed of fading.
I was wondering what the best way is to go about doing this. I tried using Jquery Cycle but it didn't fit my needs since this is a full-screen background image.
This link was the most helpful so far.
http://css3.bradshawenterprises.com/cfimg/#cfimg1

images = ["https://upload.wikimedia.org/wikipedia/commons/thumb/f/ff/Solid_blue.svg/225px-Solid_blue.svg.png",
"https://i.kinja-img.com/gawker-media/image/upload/s--XkYSDzxz--/c_scale,fl_progressive,q_80,w_800/hflvykipmc5g22mc3m0m.jpg",
"https://vignette2.wikia.nocookie.net/symbolism/images/4/43/Orange.png/revision/latest?cb=20140818120046",
"https://vignette4.wikia.nocookie.net/joke-battles/images/0/0e/Green.jpg/revision/latest?cb=20170111231844"];
// These are just placeholder images, replace the URLs with anything you desire.
bgNum = 0;
setInterval(changeBackground,5000); // Change to the number of milliseconds desired between frame changes
changeBackground();
function changeBackground() {
c = document.getElementById('bgContainer');
c.removeChild(c.childNodes[0]);
bg2 = document.createElement('img');
bg2.src = images[bgNum];
bg2.classList.add('bg');
bg2.style.opacity = '0';
bg2.onload = setTimeout(changeOpacity,100); // For some reason, updating the opacity does not work immediately after inserting the element
c.appendChild(bg2);
bgNum++;
bgNum %= images.length; // Reset image counter
}
function changeOpacity() {
c = document.getElementById('bgContainer');
c.childNodes[0].style.opacity = '0';
c.childNodes[1].style.opacity = '1';
}
#bgContainer img {
transition: opacity 1.5s;
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: -2;
}
<div id='bgContainer'><img><img></div>
test text
I could not find any way to replicate this using background-image, but I believe this replicates the behavior you are looking forward to. In order to use it, simply change the interval time and image list, as necessary.
I attempted this by having only two images on the page at a time, stacked on top of each other. However, I believe that having all images together at once and alternating opacity values may be cleaner and remove the need for the setTimeout() call. Oddly, calling console.log() also works instead of setting a delay, but it clutters the console if left running for a long period of time.

Related

Fade in new background and fade out after 10s

I've tried to make my website change background every 10 seconds. It was successful. Now, I want to fade them in and fade them out, so they will appear smoothly. I've searched other forumpages and found related questions, but I wasn't able to understand the answers well.
Javascript:
function run(interval, frames) {
var int = 1;
function func() {
document.body.id = "b"+int;
int++;
if(int === frames) { int = 1; }
}
var swap = window.setInterval(func, interval);
}
run(10000, 6); //milliseconds, frames
CSS:
#b1 { background-image: url("standaard01.jpg"); }
#b2 { background-image: url("standaard02.jpg"); }
#b3 { background-image: url("standaard03.jpg"); }
#b4 { background-image: url("standaard04.jpg"); }
#b5 { background-image: url("standaard05.jpg"); }
#b6 { background-image: url("standaard06.jpg"); }
#b7 { background-image: url("standaard07.jpg"); }
#b8 { background-image: url("standaard08.jpg"); }
#b9 { background-image: url("standaard09.jpg"); }
#b10 { background-image: url("standaard10.jpg"); }
Unfortunately it's not possible to transition between two images set to the background of a single element. (correction: it is, by animating the background-image property of an element - given browser support)
However, you can fade one element out while another element lays behind it.
Jquery has a method called .fadeToggle() that you could use in this case.
Set up a "stack" of img elements or divs with bg images, positioned on top of eachother, with the position:absolute, left, and top CSS properties.
Then, in your javascript loop, every 10 seconds, .fadetoggle() the currently visible div, revealing the next image. You could keep track of the state with an index variable.
Upon reaching the final element, fade the top image again. Then before the second element fades, .show() the remaining elements so they once again visible for the revealing.
A note about z-index: The CSS property z-index will position elements either in front, or behind other elements. So it would be wise to set the correct z-index of each item either in it's css class, or programmatically on loading the page.
Image size note: If the images or divs are different dimensions, you would fade one in, while fading the other out. From here we can talk about different crossfading methods but that's beyond the scope of this discussion
Good luck :)

Transition not working without querying width property

I want to animate a translateX with transition on a click event by adding a class to the div in the js. The transform and transition properties are added in the css file.
var widget = document.getElementById('widget');
widget.style.display = 'block';
document.getElementById('widget2').clientWidth; //comment this line out and it wont work
widget.className = 'visible';
It only works if I query the width property of any element in the dom before adding the class.
here is a jsfiddle:
https://jsfiddle.net/5z9fLsr5/2/
Can anyone explain why this is not working?
That's because you begin your transition and modified the display property "at the same time". Altering display will ruin any transition (citation needed, admittedly), so it would be a good idea to isolate the display changing and actual transiting:
https://jsfiddle.net/5z9fLsr5/3/
document.getElementById('showWidget').addEventListener('click', function(e) {
e.preventDefault();
var widget = document.getElementById('widget');
widget.style.display = 'block';
//document.getElementById('widget2').clientWidth;
window.setTimeout(function(){
widget.className = 'visible';
},0);
});
#widget {
width: 200px;
height: 80px;
background: black;
position: absolute;
transition: transform 500ms;
transform: translateX(-200px);
display: none;
}
#widget.visible {
transform: translateX(200px);
}
#widget2 {
position: absolute;
right: 0
}
show
<div id="widget"></div>
<div id="widget2">xxx</div>
Querying clientWidth seems to "pause" the execution for some time, so it works too.
The issue here is the initial setting of display: none. To the browser's layout manager, this indicates that the layout should be done as if the element in question wasn't even in the DOM (it still is, mind you). This means that the CSS style transform: translateX(-200px); will not be applied.
Doing this:
widget.style.display = 'block';
widget.className = 'visible';
triggers both modifications essentially at the same time - the layout is only re-done after both statements have been executed. Inserting document.getElementById('widget2').clientWidth; (clientHeight works as well) triggers the layout manager to repaint, thus registering transform: translateX(-200px).
As others have mentioned before me, the solution is to either use opacity instead of display (this would be my choice), or to use setTimeout with a delay of 0 (see Why is setTimeout(fn, 0) sometimes useful?).

Change background with setInterval

I want to have the background image of a page change every 5 seconds. There are 5 images and I want them to loop.
I researched thoroughly here and tried different approaches. Can someone please tell me what is wrong with this code:
In my css I have:
html, body, #wrapper {
height:100%;
margin: 0;
padding: 0;
border: none;
background-image:url('images/indexbg01.jpg');
background-repeat:no-repeat;
background-attachment:fixed;
background-position:center center;
}
and my javascript I have:
var imageArray = ['images/indexbg02.jpg', 'images/indexbg03.jpg',
'images/indexbg04.jpg', 'images/indexbg05.jpg',
'images/indexbg01.jpg'];
var imageIndex = 0;
function changeBgImage(){
var imageUrl = "url('" + imageArray[imageIndex] + "')";
$('body').css('background-image', imageUrl);
imageIndex++;
if (imageIndex >= imageArray.length) {
imageIndex = 0;
}
}
setInterval(changeBgImage, 5000);
I first had the imageUrl variable built in the line that follows, but I added this so I could check it was built ok.
In the chrome debugger, when I put a breakpoint on the line following the imageUrl build line, it stops nicely every 5 seconds, the imageUrl is built as it should, yet the background does not change.
I edited the fiddle: http://jsfiddle.net/5Cv49/1/.
Enter and see. The only markup there is the:
<div id="wrapper"></div>
The only css modified is:
adding #wrapper to the selector.
See how background is overlapped by #wrapper's background.
Works in the fiddle.It means you need to run script after page load like the fiddle does:
$(window).load(function(){
//your script
});
Working fiddle
One approach that I personally have done in the past is to have a full page slideshow using jQuery. there are a number of versions of slideshow you can use from the internet. There are 100s of them some better than others. In the slideshow have it times to change every 5 seconds like you wanted. in your html wrap the slideshow in a div (#slideshow_background for example). wrap the rest of your html page into another wrapper (#content). in your CSS set the following..
#slideshow_background {
margin:0;
padding: 0;
position : initial;
width: 100%;
height:100%;
}
the put the css for your #content and set the z-index to 1 so that it lies above the slideshow.hope this helps

Using SuperScrollorama to drop image in from top of page

I'm using SuperScrollorama to trigger a lot of animations on a single page (scrolling) website. All of the images and text that slide in from the left or right work perfectly. The problem is when I try to make an image drop in from the top of the screen the image will bounce up and down the whole time the user scrolls until they finally get down to the point where the image is supposed to "sit" (It basically goes back to it's original position and then down to where it's supposed to stay and then back up again and so on)... Here's my relevant code:
HTML:
<div id="about-pin-div">
<div id="pin-frame-pin" class="pin-frame"><img src="img/about-products.png" style="width: 55%;"></div>
</div>
CSS:
#about-pin-div { position: relative; width: 100%; height: 100%; left: -5%; overflow: hidden; }
.pin-frame { position: absolute; width: 100%; height: 100%; overflow: hidden; }
.pin-frame img { margin-top: -200px; }
JAVASCRIPT:
$(document).ready(function() {
var controller = $.superscrollorama();
controller.addTween('#about-pin-div', TweenMax.from( $('#about-pin-div'), .5, {css:{bottom:'1000px'}, ease:Quad.easeInOut}), 0, 600);
// set duration, in pixels scrolled, for pinned element
var pinDur = 1000;
// create animation timeline for pinned element
var pinAnimations = new TimelineLite();
pinAnimations
.append(TweenMax.from($('#pin-frame-pin img'), .5, {css:{marginTop:80}}))
// pin element, use onPin and onUnpin to adjust the height of the element
controller.pin($('#about-pin-div'), pinDur, {
anim:pinAnimations,
onPin: function() {
$('#about-pin-div').css('height','100%');
},
onUnpin: function() {
$('#about-pin-div').css('height','100%');
}
});
});
Thanks in advance for any help!
I think you are having a number of issues here and I will try to point out some problems that I have had with this plugin.
(1) When in doubt turn off pushFollowers for your pins.
In an effort not to continue to repeat myself
Play through pinned elements in superscrollorama
janpaepke did an excellent job in writing this work around because he had the same issues himself.
(2) Never use margins for adjusting the position, IE handles margins badly sometimes depending on the context won't work the way you want it to.
When to use margin vs padding in CSS
Does a better job at explaining it then I can.
(3) I don't understand the need to trigger on pin functions to adjust the height of #about-pin-div. You are just resetting the starting value over and over that I don't see ever gets changed. Unless you were trying to compensate for the automatically adjusting of pinned elements but the work around in (1) should fix that.

Can I animate the opacity of a CSS background-image?

CSS/Javascript is not my strong point so I would like to ask if is possible to change the background-image opacity to, let's say, 0.5.
I have a div with
background-image: url(images/nacho312.png);
background-position: -50px 0px;
background-repeat: no-repeat no-repeat;
but when I load a certain view it does not look very good, so I want to have a "half-disolve" effect when that view is shown. Is it possible?
Thanks
Here is a start.
var element = document.getElementById('hello'),
targetOpacity = 0.5,
currentOpacity,
interval = false,
interval = setInterval(function() {
currentOpacity = element.getComputedStyle('opacity');
if (currentOpacity > targetOpacity) {
currentOpacity -= 0.1;
element.style.opacity = currentOpacity;
} else {
clearInterval(interval);
}
}, 100);
See it on jsFiddle.
Run this on window.onload = function() { } or research cross browser on DOM ready events.
Of course, it is much easier with a library like jQuery.
$(function() {
$('hello').fadeTo('slow', 0.5);
});
This relies on your container's children inheriting the opacity. To do it without affecting them is a bit of a pain, as you can't reset children's opacity via opacity: 1.
If you want to animate smoothly and without doing too much extra work - this is a good task for jQuery (or another, similar library).
With jQuery you could do:
$('#id_of_div').fadeTo('fast', 0.5);
To get a fast animated fade effect on the relevant DIV.
Update: if you want to actually fade the background image, but not any foreground contents of the DIV, this is a lot harder. I'd recommend using one container DIV with position:relative and two inner DIVs with position:absolute; . The first of the inner DIVs can have the background image and a lower z-index than the second of the DIVs, and the second DIV would contain any text, etc. to show in foreground. When needed you can call $('#id_of_first_div').fadeTo('fast', 0.5); to fade just the DIV containing the background image.
By the way, the literal answer to your question is "No, you cannot animate the opacity of a CSS background image" - you can only (currently) animate the opacity of a DOM element, not its attributes, thus the need for the above hack.
Other Update: if you want to avoid using any third-party library, you can handle the fade of the background DIV using approach in Alex's answer.
background-image: url(images/nacho312.png);
background-position: -50px 0px;
background-repeat: no-repeat no-repeat;
opacity:0.5; //for firefox and chrome
filter:alpha(opacity=50); //for IE

Categories

Resources