White background during fadeOut() and fadeIn() - javascript

Currently I'm using this code to create a slideshow in my homepage:
var images = [
"/d/assets/images/IT/homepage/slider-1.jpg",
"/d/assets/images/IT/homepage/slider-2.jpg",
"/d/assets/images/IT/homepage/slider-3.jpg",
"/d/assets/images/IT/homepage/slider-4.jpg",
"/d/assets/images/IT/homepage/slider-5.jpg",
];
var imageHead = document.getElementById( "slider-home" );
var i = 0;
setInterval(function() {
$('#slider-home').fadeOut(200,
function() {
imageHead.style.backgroundImage = "url(" + images[i] + ")";
i = i + 1;
if (i == images.length) {
i = 0;
}
$('#slider-home').fadeIn(200)
}
);
}, 5000);
The code works perfectly and change the background-image every 5 seconds. Unfortunately between every change there is a small white background and the transition not appear to be "clean" and "fluid" like the Ryanair slideshow in homepage: https://www.ryanair.com/it/it/
Where is the problem that generate this and how I can solve it?

You're fading one image out, waiting for that transition to complete, then fading the next one in. That's effectively transitioning to the page background in between the images.
Making those transitions simultaneous by stacking two elements and transitioning between them would help, but it still wouldn't be perfect: you still wind up with the background peeking through during the transition while both images are partially transparent.
Instead, to get a smooth transition, just fade out the "top" image in the stack, revealing the one behind it:
yourswap = function() {
if ($('#div1').is(':visible')) {
fadeout = "#div1";
fadein = "#div2";
} else {
fadeout = "#div2";
fadein = "#div1";
}
// fade one out, then fade the other in
$(fadeout).fadeOut(function() {
$(fadein).fadeIn()
});
}
badswap = function() {
$('#div1, #div2').fadeToggle(); // transitions both elements in and out
}
goodswap = function() {
$('#div1').fadeIn(0); // make sure the background element is visible
$('#div2').fadeToggle(); // transitions the top element in and out
}
.block-div {
position: absolute;
height: 200px;
width: 400px;
color: #fff;
font-size: 40px;
text-align: center;
}
.container {
position: relative
}
#div1 {
background-color: red;
}
#div2 {
background-color: brown;
display: none;
}
#div3 {
background-color: blue
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<button onclick="yourswap()">Your transition</button>
<button onclick="badswap()">Simultaneous transition</button>
<button onclick="goodswap()">Single transition</button>
<div class="container">
<div class="block-div" id="div3">(This is the page background)</div>
<div class="block-div" id="div1">1</div>
<div class="block-div" id="div2">2</div>
</div>

Try this example
https://codepen.io/dudleystorey/pen/ehKpi
No need to write JS for that.
But through CSS it's possible.
CSS :
animation: 30s slidy infinite;
set property "animation:30s slidy infinite;" (number of seconds to change the Image in slider.)

Related

How to make an image change to another one with a transition effect using vanilla Javascript?

on a website I'm creating I have some accordions, and each of them has an image at the top. When you open the accordion, there's a description inside, and the image changes to another one. Then when you close the accordion, the image switches back to the first one.
The problem is that I'd like this image change to have a smooth transition, with a fade effect, and right now it's just an abrupt change. How can I do it?
Let's say that the accordion button has an id of "button"; and the tag that contains the first image (which will change to the second image) has an id of "firstimage".
This is the code in Javascript:
let counter = 1;
let button = document.querySelector("#button");
button.addEventListener("click", function () {
let image = document.querySelector("#firstimage");
image.setAttribute(
"src",
"(url of the first image)"
);
counter++;
if (counter > 2) {
counter = 1;
image.setAttribute(
"src",
"(url of the second image)"
);
}
});
Maybe this is something I should edit in the CSS? I already tried adding a transition to the first image in CSS ( transition: all 360ms ease-in-out ) but it didn't work.
You can just put two images on top of one another and set the opacity.
document.querySelector('.wrapper').addEventListener("click", function (e) {
e.currentTarget.classList.toggle("active");
});
.wrapper {
position: relative;
display: inline-block;
}
.wrapper > img + img {
position: absolute;
left:0;
opacity: 0;
transition: opacity 2s ease-in-out;
}
.wrapper.active > img + img {
opacity: 1;
transition: opacity 2s ease-in-out;
}
<div class="wrapper">
<img src="http://placekitten.com/200/300" />
<img src="http://placekitten.com/g/200/300" />
</div>

Smooth scrolling slider with play/pause button

I'm doing a project where I need a scrollable slider with play pause button like www.gap.com. I got this below code from W3C but not sure why multiple images are not showing fully. If I change the width value in CSS code, only first image portion scrolls but it totally ignores the 2nd image. Please anyone help me.
var speed=20 // speed of scroller
var step=3 // smoothness of movement
var StartActionText= "Scroll" // Text for start link
var StopActionText = "Pause" // Text for stop link
var x, scroll, divW, sText=""
function onclickIE(idAttr,handler,call){
if ((document.all)&&(document.getElementById)){idAttr[handler]="Javascript:"+call}
}
function addLink(id,call,txt){
var e=document.createElement('a')
e.setAttribute('href',call)
var linktext=document.createTextNode(txt)
e.appendChild(linktext)
document.getElementById(id).appendChild(e)
}
function getElementStyle() {
var elem = document.getElementById('scroller');
if (elem.currentStyle) {
return elem.currentStyle.overflow;
} else if (window.getComputedStyle) {
var compStyle = window.getComputedStyle(elem, '');
return compStyle.getPropertyValue("overflow");
}
return "";
}
function addControls(){
// test for CSS support first
// test for the overlow property value set in style element or external file
if (getElementStyle()=="hidden") {
var f=document.createElement('div');
f.setAttribute('id','controls');
document.getElementById('scroller').parentNode.appendChild(f);
addLink('controls','Javascript:clickAction(0)',StopActionText);
onclickIE(document.getElementById('controls').childNodes[0],"href",'clickAction(0)');
document.getElementById('controls').style.display='block';
}
}
function stopScroller(){clearTimeout(scroll)}
function setAction(callvalue,txt){
var c=document.getElementById('controls')
c.childNodes[0].setAttribute('href','Javascript:clickAction('+callvalue+')')
onclickIE(document.getElementById('controls').childNodes[0],"href",'clickAction('+callvalue+')')
c.childNodes[0].firstChild.nodeValue=txt
}
function clickAction(no){
switch(no) {
case 0:
stopScroller();
setAction(1,StartActionText);
break;
case 1:
startScroller();
setAction(0,StopActionText);
}
}
function startScroller(){
document.getElementById('tag').style.whiteSpace='nowrap'
var p=document.createElement('p')
p.id='testP'
p.style.fontSize='25%' //fix for mozilla. multiply by 4 before using
x-=step
if (document.getElementById('tag').className) p.className=document.getElementById('tag').className
p.appendChild(document.createTextNode(sText))
document.body.appendChild(p)
pw=p.offsetWidth
document.body.removeChild(p)
if (x<(pw*4)*-1){x=divW}
document.getElementById('tag').style.left=x+'px'
scroll=setTimeout('startScroller()',speed)
}
function initScroller(){
if (document.getElementById && document.createElement && document.body.appendChild) {
addControls();
divW=document.getElementById('scroller').offsetWidth;
x=divW;
document.getElementById('tag').style.position='relative';
document.getElementById('tag').style.left=divW+'px';
var ss=document.getElementById('tag').childNodes;
for (i=0;i<ss.length;i++) {sText+=ss[i].nodeValue+" "};
scroll=setTimeout('startScroller()',speed);
}
}
function addLoadEvent(func) {
if (!document.getElementById | !document.getElementsByTagName) return
var oldonload = window.onload
if (typeof window.onload != 'function') {
window.onload = func;
} else {
window.onload = function() {
oldonload()
func()
}
}
}
addLoadEvent(initScroller)
body {font:1em verdana,sans-serif; color:#000; margin:0}
/* position:relative and overflow:hidden are required */
#scroller { position:relative; overflow:hidden; width:30em; border:1px solid #008080; }
/* add formatting for the scrolling text */
#tag { margin:2px 0; }
/* #testP must also contain all text-sizing properties of #tag */
#testP { visibility:hidden; position:absolute; white-space:nowrap; }
/* used as a page top marker and to limit width */
#top { width:350px; margin:auto; }
<div id="scroller">
<div id="tag">
<img src="https://picsum.photos/1500/600/?image=1"/>
<img src="https://picsum.photos/1500/600/?image=2"/>
</div>
</div>
I got a bit lost in the given JS, and wonder if it is necessary for this relatively simple task.
Here is a method using HTML and CSS for the continuous scrolling and with JS just for the pause/play part.
Because you want continuous scrolling with no gap or jump when the sequence of images goes back to the beginning you need two copies. The tag element is scrolled to the left by half of its width which means that the set of images overwrite themselves so giving a smooth effect.
The JS for the button uses the running value and toggles that.
.playpause {
top: 10%;
left: 10%;
position: absolute;
z-index: 1;
}
#scroller {
width: min(30em, 100vw);
height: min(20em, 100vh);
display: inline-block;
white-space: nowrap;
overflow: hidden;
position: relative;
}
#scroller #tag {
height: 100%;
animation: scroll 10s linear infinite;
animation-fill-mode: forwards;
display: inline-block;
font-size: 0;
}
#keyframes scroll {
0% {
transform: translateX(0);
}
100% {
transform: translateX(-50%);
}
}
img {
height: 100%;
width: auto;
display: inline-block;
}
<div id="scroller">
<button class="playpause" onclick="document.querySelector('#tag').style.animationPlayState = (document.querySelector('#tag').style.animationPlayState != 'paused') ? 'paused' : 'running';">PLAY/PAUSE</button>
<div id="tag">
<img src="https://picsum.photos/1500/600/?image=1" />
<img src="https://picsum.photos/1500/600/?image=2" />
<!-- second copy of all the imaages -->
<img src="https://picsum.photos/1500/600/?image=1" />
<img src="https://picsum.photos/1500/600/?image=2" />
</div>
</div>
Observation: the site linked to in the question (gap) has a slightly unpleasant 'jump' half way through the images so I think they must be using a different method to achieve continuous scrolling.

In what cases are CSS transitions removed?

I'm pretty new to Javascript, and I have a webpage I'm trying to make that uses the same HTML file, and just cross-fades content instead of redirecting to new pages. I'm using event listeners to know when the current page has faded out and that triggers the new page to come in. Why is it that in the example below, the new pages don't fade in slowly (they just appear suddenly, ignoring the transition property)? Why is the content no longer responding to the CSS transition?
Edit: I'll try to clarify what I'm asking here. I'm aware that the display feature cannot be transitioned, and that's actually why I'm using the event listener at all. I'm trying to make it so that when the content of one page fades out, the next one fades in in the same place, which I believe cannot be achieved with visibility.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<!-- CSS -->
<style>
/* navagation bar style */
#navbar {
overflow: hidden;
background-color: #000000;
text-align: center;
width: 100%;
height: 36px;
}
#navbar a {
display: inline-block;
color: #ffffff;
padding: 10px 15px 10px 15px;
font-size: 16px;
}
/* content style*/
.page {
padding: 50px;
text-align: center;
transition: opacity 1s;
}
</style>
<!-- Javascript -->
<script>
window.onload = function() {setup()};
function setup() {
var page1link = document.getElementById("page1link");
var page1 = document.getElementById("page1");
page1.style["opacity"] = "1";
var page2link = document.getElementById("page2link");
var page2 = document.getElementById("page2");
page2.style["opacity"] = "0";
page2.style["display"] = "none";
var page3link = document.getElementById("page3link");
var page3 = document.getElementById("page3");
page3.style["opacity"] = "0";
page3.style["display"] = "none";
page1link.onclick = function() {fade(page1, page2, page3)};
page2link.onclick = function() {fade(page2, page1, page3)};
page3link.onclick = function() {fade(page3, page1, page2)};
}
function fade(page_1, page_2, page_3) {
let on_page;
if (page_2.style["opacity"] != "0") {
on_page = page_2
} else if (page_3.style["opacity"] != "0") {
on_page = page_3
} if (on_page != undefined) {
on_page.addEventListener('transitionend', fadePageIn)
on_page.style["opacity"] = "0";
function fadePageIn() {
on_page.style["display"] = "none";
page_1.style["display"] = "";
page_1.style["opacity"] = "1";
on_page.removeEventListener('transitionend', fadePageIn);
}
}
}
</script>
<title>Example</title>
</head>
<body>
<div id="navbar">
<a id="page1link" href="javascript:void(0)">Page 1</a>
<a id="page2link" href="javascript:void(0)">Page 2</a>
<a id="page3link" href="javascript:void(0)">Page 3</a>
</div>
<div class="page" id="page1">
page 1 content here
</div>
<div class="page" id="page2">
page 2 content here
</div>
<div class="page" id="page3">
page 3 content here
</div>
</body>
</html>
You can't animate the display property. So when you set opacity and display at the same time, the opacity will transition but the display value changes immediately.
As an alternative, the visibility property can be animated. Interpolation between its values happens at the halfway point, so if you want to make it work with transition that might complicate things. But I've had success in the past using CSS animations to change opacity and visibility at the same time. Using animations like this:
#keyframes becomeVisible {
0% { visibility: visible; }
100% { visibility: visible; }
}
#keyframes becomeHidden {
0% { visibility: visible; }
100% { visibility: visible; }
100% { visibility: hidden; }
}
#keyframes fadein {
0% { opacity: 0; }
100% { opacity: 1; }
}
#keyframes fadeout {
0% { opacity: 1; }
100% { opacity: 0; }
}
This is an interesting question.
Basically, as Mark points out, you can't animate it because setting the display property isn't possible to animate, thus nullifying your other transitions.
Therefore, as long as you can update the transition-able properties later in the event loop, then it will work as intended. A very easy way to do this is to use a setTimeout with 0 time.
function transitionEndCallback() {
oldPage.style["display"] = "none";
newPage.style["display"] = "block";
// add the setTimeout somewhere in this function
setTimeout(() => {
page_1.style["opacity"] = "1";
}, 0)
on_page.removeEventListener('transitionend', transitionEndCallback);
}
This way, it gets called in a different event loop callback, but still updates almost immediately afterwards. There maybe a better callback function or feature because it's a bit hacky, but I can verify it works.

Using JavaScript to populate text in div, but animation applies only to first text

I'm trying to create a landing page where a series of texts are displayed on the screen and rotated through continuously. In addition, these texts need to be animated with a typewriter-like effect. I have the animation for the text working, but it only applies to the first text. When cycling through the rest of the texts, they are just shown on the page. Any idea how to fix this issue? I was thinking trying to add the animation CSS with JavaScript for every single text refresh, but this seems cumbersome and not the most efficient way.
document.addEventListener('DOMContentLoaded', function(event) {
// array with texts to type in typewriter
var dataText = ["Hi, I'm Ned.", "Developer.", "Writer."];
function typeWriter(i) {
// add next text to h1
document.querySelector("h1").innerHTML = dataText[i] + '<span aria-hidden="true"></span>';
// wait for a while and call this function again for next text
setTimeout(function() {
typeWriter((i + 1) % 3)
}, 10000);
}
// start the text animation
typeWriter(0);
});
.typewriter h1 {
font-weight: bold;
color: #000;
font-family: "Lucida Console";
font-size: 2em;
overflow: hidden;
/*Hide content before animation*/
border-right: .1em solid white;
/*Cursor*/
white-space: nowrap;
/*Keep text on same line*/
margin: 0 auto;
/*Scrolling effect while typing*/
letter-spacing: .1em;
animation: typing 3s steps(30, end), blink-caret .75s steps(1, end) infinite alternate;
}
/* The typing effect */
#keyframes typing {
from {
width: 0
}
to {
width: 100%
}
}
/* The typewriter cursor effect */
#keyframes blink-caret {
from,
to {
border-color: transparent
}
50% {
border-color: white;
}
}
<div class="jumbotron" id="jumbotron">
<div class="typewriter">
<h1></h1>
</div>
</div>
The problem here is, that once the CSS animation is finished it wont be triggered again for that element. The only ways you can achieve a repeat is by either removing a css class (with the animation) from that element, wait for a bit and then readd it, or to destroy that element and re-create it.
For your example, I would simply create a new h1-element, edit its content and add that to the DOM. (And obviously removing the old one) Using jQuery, you can easily do that with
var h = $("<h1>"); //creating the element
h.innerHTML = ...;
$(".typewriter").empty(); //remove all children
$(".typewriter").append(h); //add new h1 element
Plain JS Method:
var h = document.createElement("h1"); //creating the element
h.innerHTML = ...; //setting its content
var typewriter = document.querySelector(".typewriter");
typewriter.innerHTML = ''; //remove all children
typewriter.appendChild(h); //add the new h1 element
Also note that the way you have selected your query selector, these changes will apply to ALL <h1> elements.
You can use JQuery to make it easier, I added also a function to stop animation when your data is completely displayed.
<script type="text/javascript">
$(function() {
var dataText = [ "Hi, I'm Ned.", "Developer.", "Writer."];
function typeWriter(i) {
var content = '<h1>' + dataText[i] +'<span aria-hidden="true"></span></h1>'
$(".typewriter").append(content);
// wait for a while and call this function again for next character
var myFunc = setTimeout(function() {
typeWriter((i + 1)%3)
}, 10000);
if (i == dataText.length - 1) {
clearTimeout(myFunc);
}
}
// start the text animation
typeWriter(0);
})
</script>
<div class="jumbotron" id="jumbotron">
<div class="typewriter">
</div>
</div>
You can check it there : https://jsfiddle.net/z4cryxx0/2/
Let me know if I answered your question.
I think I could achieve what you want. Check it out:
var dataText = [ "Hi, I'm Ned.", "Developer.", "Writer."];
function typeWriter(i) {
// add next character to h1
var h1 = document.createElement("h1");
h1.innerHTML = dataText[i] +'<span aria-hidden="true"></span>';
document.querySelector(".typewriter").append(h1);
// wait for a while and call this function again for next character
setTimeout(function() {
document.querySelector(".typewriter").innerHTML = ''; // add if(i === 2) to display the whole phrase
typeWriter((i + 1)%3)
}, 10000);
}
// start the text animation
typeWriter(0);
.typewriter h1 {
font-weight: bold;
color: orange;
font-family: "Lucida Console";
font-size: 7em;
overflow: hidden; /*Hide content before animation*/
border-right: .1em solid white; /*Cursor*/
white-space: nowrap; /*Keep text on same line*/
margin: 0 auto; /*Scrolling effect while typing*/
letter-spacing: .1em;
animation:
typing 3s steps(30, end),
blink-caret .75s steps(1, end) infinite alternate;
}
/* The typing effect */
#keyframes typing {
from {
width: 0
}
to {
width: 100%
}
}
/* The typewriter cursor effect */
#keyframes blink-caret {
from, to {
border-color: transparent
} 50% {
border-color: white;
}
}
<div class="jumbotron" id="jumbotron">
<div class="typewriter">
<h1></h1>
</div>
The trick is to make css animation work again. To do that, every time I create a new h1 element. Once a part/the whole phrase is displayed I just remove all h1 elements and repeat the process.
You could set the animation as infinite and change the length of the animation to the delay you want between the change in the text, and then set it to finish after 3 seconds (which is at 30% here) or however long you want a single animation to last:
.typewriter h1 {
...
animation:
typing 10s steps(30, end) infinite,
blink-caret .75s steps(1, end) infinite alternate;
}
#keyframes typing {
0% {
width: 0;
}
30% {
width: 100%;
}
}
The downside of this approach is that if you want to change the length of the delay between the texts, you have to modify both the JavaScript delay and the CSS animation length.
JSFiddle

Is it possible to loop changing opacity values in HTML5 or css?

This is the code I'm currently working with. It works to my purposes of layering the two images. What I am trying to do is have the layer0 opacity lower to 0 as the layer1 opacity increases to 100 over a few seconds. {and then on to layer1 with layer2 and so on eventually looping back to layer0}
Any help would be appreciated.
<head>
<style>
div.layer0
{
width: 371px;
height: 345px;
background:url(image2.jpg);
opacity:1;
filter:alpha(opacity=100); /* For IE8 and earlier */
}
div.layer1
{
width: 371px;
height: 345px;
background:url(image3.jpg);
opacity:0;
filter:alpha(opacity=0); /* For IE8 and earlier */
}
</style>
</head>
<body>
<div class="layer0">
<div class="layer1">
</div>
</div>
</body>
To continually do this in a loop, you'll need some javascript to add an appropriate active class to the image you want displayed. Then using CSS transitions you can achieve the fading between images that you require.
I created a jsfiddle to give you an example of this working: http://jsfiddle.net/pacso/H6dqq/
The basics are as follows.
Some simple HTML divs which you'll be fading:
<div class='red square active'></div>
<div class='yellow square'></div>
<div class='green square'></div>
<div class='blue square'></div>
These are just going to be coloured squares, but yours could contain images.
Next, some CSS markup:
.red {
background-color: red;
}
.blue {
background-color: blue;
}
.green {
background-color: green;
}
.yellow {
background-color: yellow;
}
.square {
width: 200px;
height: 200px;
position: absolute;
top: 20px;
left: 20px;
opacity: 0;
transition: opacity 2s;
-webkit-transition: opacity 2s; /* Safari */
}
.active {
opacity: 1;
}
Note that my transition will alter the opacity of the div itself. You may need to change this as needed.
Now the javascript to make it work on an endless loop:
jQuery(function() {
window.setInterval(function () {
activeSquare = $('.active');
nextSquare = activeSquare.next()
if (nextSquare.length == 0) {
nextSquare = activeSquare.siblings().first();
}
nextSquare.addClass('active');
activeSquare.removeClass('active');
}, 3000);
});
Fairly straightforward. Click the link to my fiddle and hit the run button if you want to see a working demo.
Short answer: not easily.
You're probably better off with javascript for the looping. You could make a delayed keyframe animation, but that won't allow you to loop from the start again: jsfiddle.net/G4PTM (firefox/ie10) -- You could make a lot of keyframes with different timings and you can make it work, but it would require quite a bit of code and not scale well (say you wanted to add another layer/image the code would quickly become unmanagable)
With some javascript, you can just loop through the divs and add and remove a classname to trigger the transitions, like Jon mentioned. Here is a working demo (using jQuery for simplicity, let me know if you need vanilla js)
html
<div class="layer0">
</div>
<div class="layer1">
</div>
<div class="layer2">
</div>
css
div {
width: 371px;
height: 345px;
opacity: 0;
position: absolute;
transition: opacity 2s;
}
div.active {
opacity: 1;
}
div.layer0 {
background:url(http://lorempixel.com/373/345);
}
div.layer1 {
background:url(http://lorempixel.com/372/345);
}
div.layer2 {
background:url(http://lorempixel.com/374/345);
}
js+jquery
var firstDiv = $(".layer0");
var current;
function loopsie() {
// if first iteration or reached end, use first div
if (!current || !current.length) current = firstDiv;
current.addClass("active");
setTimeout(function() {
current.removeClass("active");
setTimeout(function() {
current = current.next();
loopsie(); // recurse
}, 2000);
}, 2000);
}
//initialize
loopsie();
Working demo at http://jsfiddle.net/G4PTM/2/
Plain JavaScript (Without jQuery):
var firstDiv = document.querySelector(".layer0"); // IE 8+
var current;
function loopsie() {
// if first iteration, use first div
if (!current) current = firstDiv;
current.classList.add("active"); // IE 10+, shim at https://developer.mozilla.org/en-US/docs/Web/API/Element.classList
setTimeout(function() {
current.classList.remove("active");
// account for text node (if there is whitespace in html)
if (current.nextSibling && current.nextSibling.nodeName == "DIV") {
current = current.nextSibling;
} else if (current.nextSibling && current.nextSibling.nextSibling && current.nextSibling.nextSibling.nodeName == "DIV") {
current = current.nextSibling.nextSibling;
} else {
// reached end
current = firstDiv;
}
loopsie(); // recurse
}, 2000);
}
//initialize
loopsie();
http://jsfiddle.net/G4PTM/6/
You can use CSS transitions. The example below fades .layer0 in and out in a timespan of 500 ms:
div.layer0 {
opacity: 1;
-webkit-transition:opacity 500ms ease-out;
-moz-transition:opacity 500ms ease-out;
-o-transition:opacity 500ms ease-out;
transition:opacity 500ms ease-out;
}
div.layer0:hover {
opacity: 0;
}

Categories