17

I'm trying to add a transition effect when switching between projects. This code currently works, but I'd rather have something like having a fade effect when switching projects. Is this possible?

Here is a jsfiddle if that helps at all. Thanks!

My code:

HTML

<body>
  <div id="proj_name"></div>
  <div id="proj_description"></div>
  <img id="proj_img" src=""><br>
  <button id="proj_switcher">Next Project</button>
</body>

JavaScript

/**
 * Constructor function for Projects
 */
function Project(name, description, img) {
  this.name = name;
  this.description = description;
  this.img = img;
}

// An array containing all the projects with their information
var projects = [
  new Project('Project 1', 'Project 1 Description', 'http://bit.ly/1E0IzpX'),
  new Project('Project 2', 'Project 2 Description', 'http://bit.ly/1FHLGOt'),
  new Project('Project 3', 'Project 3 Description', 'http://bit.ly/1H5wRt7'),
  new Project('Project 4', 'Project 4 Description', 'http://bit.ly/1ECIQht'),
  new Project('Project 5', 'Project 5 Description', 'http://bit.ly/1CYeY9F')
];

// Cacheing HTML elements
var projName   = document.querySelector('#proj_name');
var projDescr  = document.querySelector('#proj_description');
var projImg    = document.querySelector('#proj_img');
var projButton = document.querySelector('#proj_switcher');

// Index of the current project being displayed
var projIndex = 0;

projButton.addEventListener('click', function() {
  projName.innerHTML = projects[projIndex].name;
  projDescr.innerHTML = projects[projIndex].description;
  projImg.src = projects[projIndex].img;
  projImg.style.width = '250px';
  projImg.style.height = '150px';

  projIndex = (projIndex + 1) % projects.length;
});
Saad
  • 49,729
  • 21
  • 73
  • 112
  • 2
    Depending on type of transition and how complex it is, you might have to have an "offscreen" buffer div that you switch between content to achieve this. I.e fade in and fade out at the same time, probably requires 2 overlapping divs (positioned absolute on top of each other) where one is at opacity 1 and the other at opacity 0 and as transition, inject new content to the invisible div and afterward, set fade out transition on the visible div and fade in on the invisible div, and your code need to keep track which one is which since you will toggle between the two. – Jimmy Chandra Apr 15 '15 at 02:48
  • @JimmyChandra Thanks! I am most likely going to follow your advice and use a fadeOut and fadeIn div. – Saad Apr 15 '15 at 05:28

3 Answers3

18

You can easily do that using a CSS transition. First you turn the opacity of the fields to 0, and then you replace the content and you make the fields appear again.

For doing this, first you wrap the project fields:

<body>
  <div id="project"></div>
     <div id="proj_name"></div>
     <div id="proj_description"></div>
     <img id="proj_img" src=""><br>
  </div>
  <button id="proj_switcher">Next Project</button>
</body>

Add the following CSS code:

<style>
#project {
   -webkit-transition: opacity .5s ease-in-out;
   -moz-transition: opacity .5s ease-in-out;
   -ms-transition: opacity .5s ease-in-out;
   -o-transition: opacity .5s ease-in-out;
   transition: opacity .5s ease-in-out;
}
</style>

And then, add before the change:

var project = document.querySelector('#project');
project.style.opacity = 0;

And after it:

project.style.opacity = 1;

The final javascript would be:

/**
 * Constructor function for Projects
 */
function Project(name, description, img) {
  this.name = name;
  this.description = description;
  this.img = img;
}

// An array containing all the projects with their information
var projects = [
  new Project('Project 1', 'Project 1 Description', 'http://bit.ly/1E0IzpX'),
  new Project('Project 2', 'Project 2 Description', 'http://bit.ly/1FHLGOt'),
  new Project('Project 3', 'Project 3 Description', 'http://bit.ly/1H5wRt7'),
  new Project('Project 4', 'Project 4 Description', 'http://bit.ly/1ECIQht'),
  new Project('Project 5', 'Project 5 Description', 'http://bit.ly/1CYeY9F')
];

// Cacheing HTML elements
var project = document.querySelector('#project');
var projName   = document.querySelector('#proj_name');
var projDescr  = document.querySelector('#proj_description');
var projImg    = document.querySelector('#proj_img');
var projButton = document.querySelector('#proj_switcher');

// Index of the current project being displayed
var projIndex = 0;

projButton.addEventListener('click', function() {
  // Fade out
  project.style.opacity = 0;

  // Wait for the transition 
  setTimeout(function(){ 
      // Load new content
      projName.innerHTML = projects[projIndex].name;
      projDescr.innerHTML = projects[projIndex].description;
      projImg.src = projects[projIndex].img;
      projImg.style.width = '250px';
      projImg.style.height = '150px';
      projIndex = (projIndex + 1) % projects.length;
      // Fade in
      project.style.opacity = 1;
  },500);
});

You can try it here: https://jsfiddle.net/9c4mx7p9/

EDIT

Version with CSS classes: https://jsfiddle.net/y4p1y0ch/

Community
  • 1
  • 1
Álvaro Reneses
  • 691
  • 3
  • 8
  • Thanks for taking the time to answer! However, it seems like this code still isn't having a fade effect? I'm most likely going to do what JimmyChandra said which is two use two divs on top of each other and then use JS and css transitions to make the content in the fadeIn appear as the content in the fadeOut disappears. – Saad Apr 15 '15 at 05:30
  • Ops! I had one spelling error and I forgot to include the waiting function. It was not possible to see the changes because we were setting the opacity to one just after hiding it. I have updated the changes, and you can try it here: https://jsfiddle.net/9c4mx7p9/ – Álvaro Reneses Apr 15 '15 at 05:46
  • No need to use two divs. Just set the opacity back to 1 after a short delay (1ms should be enough): `setTimeout(function () { project.style.opacity = 1 }, 1);`. I'd recommend using a class instead though and keep all styling in the CSS. – powerbuoy Apr 15 '15 at 05:48
  • Thanks Álvaro, that really helped! And thanks for the tip @powerbuoy, I'm going to create fadeIn and fadeOut classes and just add them to the class list instead of altering styling within the JS. – Saad Apr 15 '15 at 07:01
  • @ÁlvaroReneses, quick question - Is there a way to use classes to do the same thing you did? It only seems to work for the first project switch for me. https://jsfiddle.net/9c4mx7p9/1/ – Saad Apr 15 '15 at 07:40
  • Yes! Here you have the code: https://jsfiddle.net/y4p1y0ch/ . The problem was that you weren't removing the other class before adding a new one, and therefore `reveal` was always the latest. – Álvaro Reneses Apr 15 '15 at 11:58
  • Note, for the visitors in the future: you don't need all of those multiple CSS declarations with the `-webkit / -moz / -o` prefixes. Just use the `transition` property directly. – wgrant Jan 31 '23 at 21:31
0

This seems like a great opportunity for me to present to you the ever awesome GreenSock Animation Platform (or GSAP in short).

GSAP is arguably the most respected animation platform out there for Flash and JavaScript developers alike. Head over to their website for more information about this tool-set.

On to codes. Assuming that you have added TweenMax in your HTML:

var objectsToAnimate=[projName, projDescr, projImg];
var duration=.4;

projImg.style.width = '250px';
projImg.style.height = '150px';

projButton.addEventListener('click', function() {
    TweenMax.to(objectsToAnimate, duration, {opacity:0, ease:Power4.easeIn, onComplete:function(){
        projName.innerHTML = projects[projIndex].name;
        projDescr.innerHTML = projects[projIndex].description;
        projImg.src = projects[projIndex].img;        
        projIndex = (projIndex + 1) % projects.length;
        TweenMax.to(objectsToAnimate, duration, {opacity:1, ease:Power4.easeOut});
    }});
});

Take a look at this jsFiddle I forked from yours.

P.S. I am not affiliated with this project in any way. I am just a big fan of this library and have been using it in my projects for as long as I have been coding professionally. :)

Tahir Ahmed
  • 5,687
  • 2
  • 17
  • 28
  • Cool solution! However, I'd rather try do this without any other libraries/frameworks. Thanks for taking the time to answer though! – Saad Apr 15 '15 at 05:29
  • 1
    I understand, no worries. One comment though, you may want to take out `style` changes to your `projImg` _image_ tag because I think it doesn't need to be applied over and over again on every click. Do you see what I am suggesting? – Tahir Ahmed Apr 15 '15 at 06:35
  • Yes, good point! Just some sloppy left over code when I was testing it out, I'm going to move that to the CSS file :p – Saad Apr 15 '15 at 06:56
0

This is an answer without using wrapping. Suppose I have to replace element with repID with pagID, where repID element dims for 0.5sec and padID element becomes opaque for the next 0.5 sec, then it can be done using the following code in CSS,

#repIdName{
transition: opacity .5s ease-in-out;}

and the following in JavaScript

function replaceID(repId,pagID){
var mainContent = document.getElementById(repID);
var homeContent = document.getElementById(pagID).innerHTML;
mainContent.style.opacity = 0;
window.setTimeout(function () {
                                mainContent.innerHTML = homeContent;
                                console.log(pagID+"opened");
                                mainContent.style.opacity = 1;
                                },500);}

in HTML the function calling would be somewhat like this

<a href="#"onclick="replaceID('repIdName','pagIdName)">
Harsha
  • 99
  • 1
  • 6