Adding Fade to My Body Background Slider - javascript

I've created a background body slider which will switch through body backgrounds with 'next' and 'back' buttons. Live example here:
https://ts564737-container.zoeysite.com/lookbook
This functions perfectly (ignore the large images causing it to load slowly), but I can't seem to add a crossfade effect like on this website:
http://northamerica.triangl.com/pages/lookbook-swimwear
I tried this with CSS transition: all 0.5s ease-out but the transition is poor and loaded horribly.
Could anybody please advise where I can add a crossfade to this so that it's like the website above? Thank you for your help and time.
HTML & jQuery etc.
<!-- Remove header from lookbook page only and add background1 -->
<script>
jQuery(document).ready(function() {
if (top.location.pathname === '/lookbook')
{
jQuery("#root-header-cp-41e961ff2cbb3d4e6ae72927272f2db5").addClass("removeheader");
jQuery("body").addClass("background1");
}
});
</script>
<!-- Change background -->
<script>
jQuery(document).ready(function() {
var current = 1; // current background index
var max_backgrounds = 3; // number of backgrounds it will work with any number
jQuery(".next").click(function() {
jQuery("body").removeClass("background" + current);
// next background index or first one if it's the last one
current++;
if (current > max_backgrounds) {
current = 1;
}
// change background to background1, background2 ...
jQuery("body").addClass("background" + current);
});
jQuery(".back").click(function() {
jQuery("body").removeClass("background" + current);
// previous background index or last one if current is the first one
current--;
if (current < 1) {
current = max_backgrounds
}
// change background to background1, background2 ...
jQuery("body").addClass("background" + current);
});
});
</script>
<!-- Container plus images -->
<div id="toggle" width="100%">
<img src="/media/import/icons/back.png" class="back">
<img src="/media/import/icons/next.png" class="next">
</div>
CSS
/* Body background options */
.background1 {
background: url('/media/import/backgrounds/background1.jpg') no-repeat center center fixed;
background-size: cover;
overflow: hidden;
}
.background2 {
background: url('/media/import/backgrounds/background2.jpg') no-repeat center center fixed;
background-size: cover;
overflow: hidden;
}
.background3 {
background: url('/media/import/backgrounds/background3.jpg') no-repeat center center fixed;
background-size: cover;
overflow: hidden;
}
/* Toggle Buttons */
#toggle .next {
float: right;
margin-right: 20px !important;
}
#toggle .back {
margin-left: 20px !important;
}
#toggle img {
margin-top: 400px;
display: inline;
}
#toggle img:hover {
cursor: pointer;
opacity: 0.8;
}

The trick is to use multiple elements, which are all positioned in the exact same place. All elements must have an opacity: 0, except the active one (opacity: 1).
When you navigate to the next/previous item, you need to toggle an active class on them, which removes/sets opacity: 1
Simplified example with divs:
(function () {
var prevButton = $('.previous'),
nextButton = $('.next'),
allImages = $('.background-images li');
nextButton.click(function(e) {
// Find the active element
activeElement = $('li.bg-active');
// remove the 'bg-active'-class from this element
activeElement.removeClass('bg-active');
// if current element is the last one, make sure to add 'bg-active'-class to the very first element.
if (activeElement[0] === allImages.last()[0]){
allImages.first().addClass('bg-active');
} else {
// Add 'bg-active'-class to the next element
activeElement.next().addClass('bg-active');
}
});
prevButton.click(function(e) {
activeElement = $('li.bg-active');
activeElement.removeClass('bg-active');
// if current element is the first one, make sure to add 'bg-active'-class to the very lst element.
if (activeElement[0] === allImages.first()[0]){
allImages.last().addClass('bg-active');
} else {
// add 'bg-active'-class to the previous element
activeElement.prev().addClass('bg-active');
}
});
})();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Slider</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<style>
ul {
overflow: auto;
}
li {
width: 100px;
height: 100px;
position: absolute;
left: 0;
}
.bg {
opacity: 0;
transition: all 0.5s ease-out;
}
.bg-active {
opacity: 1;
}
.bg1 {
background-color: red;
}
.bg2 {
background-color: green;
}
.bg3 {
background-color: blue;
}
</style>
</head>
<body>
previous
next
<ul class="background-images">
<li class="bg bg1 bg-active"></li>
<li class="bg bg2"></li>
<li class="bg bg3"></li>
</ul>
</body>
</html>

Try using
#Crossfade img {
position:absolute;
left:0;
-webkit-transition: opacity 1s ease-in-out;
-moz-transition: opacity 1s ease-in-out;
-o-transition: opacity 1s ease-in-out;
transition: opacity 1s ease-in-out;
}
This should give you the crossfade that you want.

Instead of toggling classes you could just swap out the image, here's a quick proof of concept you can run in your console:
jQuery("body").css({'background-image':'url(/media/import/backgrounds/background3.jpg)', 'transition':'all 0.5s ease-out'});
Adapting this for your code would look something like:
jQuery
jQuery(".next").click(function() {
current++;
if (current > max_backgrounds) {
current = 1;
}
jQuery("body").css({'background-image':'url(/media/import/backgrounds/background' + current + '.jpg');
});
jQuery(".back").click(function() {
current--;
if (current < 1) {
current = max_backgrounds
}
jQuery("body").css({'background-image':'url(/media/import/backgrounds/background' + current + '.jpg');
});
CSS
body {
transition: all 0.5s ease-out;
}

There many ways you can about this and this gentleman has showcase many of them
Some pointers:
The page you've given as an example loads every image when the page loads.
Performance wise, you don't want that. If you're going to do such an effect, make sure you load the images only when they actually required.
They achieve the effect by pilling all images on top of each other, then animating the opacity in/out when clicking the arrows.
Since they all have position:absolute, you'll get the crossfade effect you wish for.

Related

Setting element to visible does not run css animation

I have the following html code
var feedback = document.getElementById('openNotification');
feedback.addEventListener('click', function (){
a = document.getElementById("notification");
a.style.visibility = "visible";
});
#notification {
position: fixed;
z-index: 101;
bottom: 0;
transform: translateY(calc(100% + 10px));
left: 10vw;
right: 10vw;
text-align: center;
height: 20vh;
overflow: hidden;
background-color: #ededed;
color: #000;
}
#keyframes slideUp {
0% { transform: translateY(calc(100% + 10px)); }
100% { transform: translateY(0); }
}
#notification {
animation: slideUp 2.5s ease forwards;
}
<button id="openNotification">
Open notification
</button>
<!--If I remove the (style="visibility: hidden;") the animation works as expected-->
<div id="notification" style="visibility: hidden;">
121
</div>
The CSS for this div contains "transform" code to make the notification slide up the screen...
When I run the following code in a setTimeout function the notification simply appears on the screen and does not slide up as it should.
a = document.getElementById("notification");
a.style.visibility = "visible";
How do I fix this?
On further testing I can see that the animation code seems to be running from the moment the code is loaded. I assume I need to somehow change this behaviour so the animation code is kicked off by the setTimout function or in this case the button click. Any examples on how to do this?
The animation takes place but as it only lasts a short time, by the time you come to push the button it has finished, and you then make the thing visible.
Instead we remove the animation from the initial state of the element and add it (by adding a class in this case) only when you click the button.
Note: if you want this to be repeatable you will have to include sensing the animationend event and removing the slide class at that point. Otherwise the system will think it's done the animation and needn't do it again.
var feedback = document.getElementById('openNotification');
feedback.addEventListener('click', function (){
a = document.getElementById("notification");
a.style.visibility = "visible";
a.classList.add('slide');
});
#notification {
position: fixed;
z-index: 101;
bottom: 0;
transform: translateY(calc(100% + 10px));
left: 10vw;
right: 10vw;
text-align: center;
height: 20vh;
overflow: hidden;
background-color: #ededed;
color: #000;
}
#keyframes slideUp {
0% { transform: translateY(calc(100% + 10px)); }
100% { transform: translateY(0); }
}
#notification.slide {
animation: slideUp 2.5s ease forwards;
}
<button id="openNotification">
Open notification
</button>
<!--If I remove the (style="visibility: hidden;") the animation works as expected-->
<div id="notification" style="visibility: hidden;">
121
</div>

Fading in a background image using javascript or css on hover

So far, i've been able to make it such that when the cursor hovers over the div a background image in the body appears. I need to add a fade in animation to this. Ive been looking for solutions here but havent been able to work around it. I don't have any experience in javascript.
enter code here
<script>
changeBgImage = () => {
document.body.style.backgroundImage = "url('../Images/Background/wraithback.jpg')";
console.log("working")
}
ogBgImage = () => {
document.body.style.backgroundImage = "url('../Images/Background/black.jpg')";
console.log("working")
}
</script>
<style>
body {
background-image: url('../Images/Background/black.jpg');
}
</style>
<body>
<div class="gwraith"><a href="../Legends/wraith.html ">
<img src="../Images/Legends_pics/wraithchibi.png" width="130vw" class="wraith"
onmouseover="changeBgImage();" onmouseout="ogBgImage();">
</a>
</body>
Add a transition rule to the body tag. The same can be done in css, without javascript.
function changeBgImage() {
document.body.style.backgroundImage = "url('https://s1.1zoom.ru/big0/284/Summer_Pond_Fence_Trees_496376.jpg')";
}
function ogBgImage() {
document.body.style.backgroundImage = "url('https://pristor.ru/wp-content/uploads/2017/02/leto12.jpg')";
}
body {
background-image: url('https://pristor.ru/wp-content/uploads/2017/02/leto12.jpg');
background-repeat: no-repeat;
background-size: cover;
transition: all 0.7s linear;
}
<body>
<div class="gwraith">
<a href="../Legends/wraith.html">
<img src="https://begin-english.ru/img/word/refresh.jpg" width="130vw" class="wraith"
onmouseover="changeBgImage();" onmouseout="ogBgImage();">
</a>
</div>
</body>
I didn't manage to do it with body. But you can stretch the underlying div and change its opacity.
const appDiv = document.getElementById("app");
appDiv.addEventListener("mouseover", showBodyBackground);
appDiv.addEventListener("mouseout", hideBodyBackground);
function showBodyBackground() {
document.getElementById("bg").classList.add("hidden");
}
function hideBodyBackground() {
document.getElementById("bg").classList.remove("hidden");
}
.visible {
background: url('https://www.bouwendnederland.nl/media/6502/rijnhaven-impressie-602-x-402.jpg');
transition: opacity 1.5s linear;
opacity: 1;
}
.hidden {
opacity: 0;
}
.stretched {
position: absolute;
width: 100%;
height: 100%;
}
#app {
width: 100px;
height:50px;
background: lightblue;
text-align: center;
margin: 0 auto;
position: relative;
}
<body>
<div class="stretched visible" id="bg"></div>
<div id="app">Hover me!</div>
</body>
Be aware, that everything will disappear in the element with opacity: 0. It means, your button and other elements you want to keep on the screen shouldn't be children of that div.
We can't just fade body, or indeed any wrapper div which may replace it, as that would fade everything. We also can't directly fade a background image as CSS doesn't have that ability. But we can put the two background images into the two pseudo elements, before and after, of body and these can then be animated to fade in and out. The code wants to fade in one background on mouseover, and fade it out on mouseout.
There are two background images used, one called black. The code here fades that out as the other image fades in, but that can be easily removed if required.
Mouse over the gear image to fade in the second image, and mouseout of the gear to fade it out.
<!DOCTYPE html>
<html>
<head>
<script>
changeBgImage = () => {
<!--document.body.style.backgroundImage = "url('../Images/Background/wraithback.jpg')";-->
document.body.classList.toggle('showbefore');
document.body.classList.toggle('showafter');
console.log("working")
}
ogBgImage = () => {
<!--document.body.style.backgroundImage = "url('christmas card 2020 front.jpg')";-->
document.body.classList.toggle('showbefore');
document.body.classList.toggle('showafter');
console.log("working")
}
</script>
<style>
body {
position: relative;
height: 100vh; /* I added this just to cover the whole window you may not want it */
}
body:before, body:after {
opacity: 0;
content: ' ';
display: block;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: -1;
background-size:cover; /* I added this just to get the background over the whole window - you may or may not want it */
background-repeat: no-repeat no-repeat;
background-position: center center;
animation-duration: 2s; /* change to what you want it to be */
animation-fill-mode: forwards;
}
body:before {
background-image: linear-gradient(black, black); /*change this to url('your background image');*/
animation-name: shown;
}
body:after {
background-image: url('https://ahweb.org.uk/christmas card 2020 front.jpg');
animation-name: unshown;
}
body.showbefore:before, body.showafter:after {
animation-name: show;
}
body.showafter:before, body.showbefore:after {
animation-name: unshow;
}
#keyframes unshown {
from {
opacity: 0;
}
to {
opacity: 0;
}
}
#keyframes shown {
from {
opacity: 1;
}
to {
opacity: 1;
}
}
#keyframes unshow {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
#keyframes show {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
</style>
</head>
<body class="showbefore">
<div class="gwraith"><!--<a href="../Legends/wraith.html ">-->
<!--<img src="../Images/Legends_pics/wraithchibi.png" width="130vw" class="wraith"
onmouseover="changeBgImage();" onmouseout="ogBgImage();">-->
<img src="https://ahweb.org.uk/gear.jpg" width="130vw" class="wraith"
onmouseover="event.preventDefault();event.stopPropagation();changeBgImage();" onmouseout="event.preventDefault();event.stopPropagation();ogBgImage();">
<!--</a>-->
</body>
</body>
</html>

Background transition does not work properly

I'm going to change back ground an element in a setInterval function. the background is getting changed imediately, but I would like to make it transited in couple of seconds.
var act = true;
setInterval(function(){
if (act) {
$("div").addClass("back2")
$("div").removeClass("back")
act = false
} else {
$("div").addClass("back")
$("div").removeClass("back2")
act = true
}
}, 10000)
.back{
width:100px;
height:100px;
background-image:url("https://www.skoobe.de/static/v/7b2334ac8a86ab5d764bc6e94df87df4aa5b4e2adc78c783e73ae2cbaf613745.jpg");
display:block;
transition: .5s ;
}
.back2{
width:100px;
height:100px;
background-image:url("https://www.skoobe.de/static/v/a5c0d3825217f88c4c893e7b630c4f1c5eb4c9bec834e1112383614270b5d583.jpg");
display:block;
transition: .5s;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="c">tz</div>
background-image is not an animatable property. As you can see in this list on the mozilla dev page, this is not possible: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_animated_properties
What you can do is have two divs with one background image each overlapping each other and then make one of them transparent to create a blending effect.
I made a fiddle to illustrate the idea:
https://jsfiddle.net/Lpduw3mq/
// find elements
var firstDiv = $("#first")
var secondDiv = $("#second")
// Swap backgrounds
var act = true;
setInterval(function(){
if (act) {
firstDiv.addClass("transparent")
secondDiv.removeClass("transparent")
act = false
} else {
firstDiv.removeClass("transparent")
secondDiv.addClass("transparent")
act = true
}
}, 5000)
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
.base {
position: absolute;
top: 0;
left: 0;
}
.back {
width: 100px;
height: 100px;
background-image: url("https://www.skoobe.de/static/v/7b2334ac8a86ab5d764bc6e94df87df4aa5b4e2adc78c783e73ae2cbaf613745.jpg");
display: block;
opacity: 1;
transition: opacity 0.5s;
}
.back2 {
width: 100px;
height: 100px;
background-image: url("https://www.skoobe.de/static/v/a5c0d3825217f88c4c893e7b630c4f1c5eb4c9bec834e1112383614270b5d583.jpg");
display: block;
opacity: 1;
transition: opacity 0.5s;
}
.transparent {
opacity: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="first" class="base back"></div>
<div id="second" class="base back2 transparent"></div>
You can use an unordered list of two items absolutely styled with the image backgrounds and use keyframe animation to change between these two items while smoothly changing a background opacity. Check this out http://tympanus.net/codrops/2012/01/02/fullscreen-background-image-slideshow-with-css3/

css transition opacity is not working where element had display:none then changed to display:block

Like the title said. I have this code: https://jsfiddle.net/fwo9ym1o/
//javascript
var container = document.querySelector("#container");
container.style.display = "block";
//this is not working
//container.style.opacity = 1;
//this is working
setTimeout(function() {
container.style.opacity = 1;
}, 0);
/css
.container {
height: 200px;
width: 200px;
background-color: salmon;
display: none;
border-radius: 5px;
opacity: 0;
transition: opacity 2s ease-in-out;
}
//html
<div id="container" class="container"></div>
So, I've changed the container.style.display = "block"; then applied container.style.opacity = 1; and the transition is not happening.
It works if I run everything in a new thread.
NOTE: I can't use visibility. It has to be display:none
It's because of the way styles are figured out. Style changes are expensive so they are effectively saved up until they are needed (a recalc check like .offsetHeight is called or the next frame needs to be drawn).
The following code should work. It includes an explanation of what (I think) is going on:
container.style.display = "block";
// container is actually still invisible
// current style hasn't been calculated
container.offsetHeight;
// this forces a style recalc
// so the current style for the container is figured out.
// without this recalc, this element effectively has no style,
// and so when you transition from its current style (null) to a different one (opacity: 1), it just snaps to the new value.
container.style.opacity = 1;
// this triggers the transition.
// because the style was recalced before the transition was triggered,
// it will transition _from_ those values.
jsFiddle
May I suggest you use animation instead, it is much more appropriate than force a redraw.
var container = document.querySelector("#container");
container.classList.add('animateme');
.container {
display: none;
height: 150px;
width: 150px;
background-color: red;
}
.animateme {
display: block;
animation: animate 2s linear;
}
#keyframes animate {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
<div id="container" class="container"></div>
Despite the marked 'right' answer I vote for the answer from LGSon above due to it being not a workaround but using natural CSS capability.
Plus it gives a cleaner code in JS due to the ease of toggling a class (container.classList.toggle('animateme')) and separation of concerns (JS does not manipulate CSS properties directly).
However I experienced the animation animate getting reset at the end to its zero keyframe i.e. to opacity: 0;
To make it stay I added animation-fill-mode: forwards; to .animateme selector like this (taken from this stackoverflow answer)
.animateme {
display: block;
animation: animate 2s linear;
animation-fill-mode: forwards;
}
Try this:
var container = document.querySelector("#container");
container.style.opacity = 1;
<div id="container" class="container"></div>
.container {
height: 200px;
width: 200px;
background-color: salmon;
display: block;
border-radius: 5px;
opacity: 0;
transition: opacity 2s ease-in-out;
}
JSFiddle

How do I add a cycle style repeating image phase background to my website?

The question title says it all, I am not sure how to organize it in to my websites HTML due to the fixed menu bar, and its over all build. So to say, I want my website to have multiple backgrounds that fade in and out. I intend on adding more backgrounds over time. What I listed below is what I've been attempting to work with.
body {
width: 400px;
height: 400px;
}
/* set `#slideshow` parent background color */
.slideshow {
background: #000;
display:block;
width:inherit;
height:inherit;
}
#slideshow {
width: 100%;
height: 100%;
display: block;
opacity: 0.0;
background-color: #000;
/*
set background images as `url(/path/to/image)` here,
separated by commas
*/
background-image: url("http://lorempixel.com/400/400/cats/?1"),
url("http://lorempixel.com/400/400/animals/?2"),
url("http://lorempixel.com/400/400/nature/?3"),
url("http://lorempixel.com/400/400/technics/?4"),
url("http://lorempixel.com/400/400/city/?5");
background-size: cover, 0px, 0px, 0px;
/* set transtitions at 3000ms
-webkit-transition: background-image 3000ms linear;
-moz-transition: background-image 3000ms linear;
-ms-transition: background-image 3000ms linear;
-o-transition: background-image 3000ms linear;
transition: background-image 3000ms linear;
*/
}
Javascript below.
$(function() {
$.fx.interval = 0;
(function cycleBgImage(elem, bgimg) {
// `elem`:`#slideshow`
// set, reset, delay to `1000` after background image reset
elem.css("backgroundImage", bgimg)
// fade in background image
.fadeTo(3000, 1, "linear", function() {
// fade in background image
$(this).delay(3000, "fx").fadeTo(3000, 0, "linear", function() {
// split background image string at comma , creating array
var img = $(this).css("backgroundImage").split(","),
// concat first background image to `img` array,
// remove first background image from `img` array
bgimg = img.concat(img[0]).splice(1).join(",");
// recursively call `cycleBgImage`
cycleBgImage(elem, bgimg);
});
});
}($("#slideshow")));
});
The division script, which I'm not sure I have a use for unless I make my whole website one large div which seems pointless.
<div class="slideshow">
Here is a quick hack. I would probably do something more elegant with management of the images in an array, but this should get you going.
function swap(){
var $targets = $("#slideshow img");
var className = "active";
var $next = $targets.filter(".active").next();
if ($next.length === 0) { $next = $targets.first(); }
$targets.removeClass(className);
$next.addClass(className)
}
swap();
window.setInterval(swap, 5 * 1000);
#slideshow {
background-color: #000;
width: 400px;
height: 400px;
border: solid 1px;
overflow: hidden;
position: relative;
}
#slideshow img {
position:absolute;
opacity: 0;
transition: opacity 2s ease-in-out;
}
#slideshow img.active {
opacity: 1;
}
<div id="slideshow">
<img src="http://lorempixel.com/400/400/cats/?1" />
<img src="http://lorempixel.com/400/400/animals/?2" />
<img src="http://lorempixel.com/400/400/nature/?3" />
<img src="http://lorempixel.com/400/400/technics/?4" />
<img src="http://lorempixel.com/400/400/city/?5" />
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Categories