Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
schmolzp

Chrome issue with animation

Recommended Posts

Hi,
I created this page several months ago and everything was working great on all major browsers. Now when I check it on chrome and click on "See their time fly", it will start the animation and look good until it starts to render weird and only show part of a photo. Eventually it just kind of breaks. Do you have any idea why this is happening?
 
This page continues to work great on Safari and Firefox.
 
Here is my code:

var photoItem = $('.photo_item'),
    groupOne = $('.group-one .photo_item'),
    groupTwo = $('.group-two .photo_item'),
    groupThree = $('.group-three .photo_item'),
    groupFour = $('.group-four .photo_item'),
    groupFive = $('.group-five .photo_item'),
    beforeLastPhoto = $('.photo_item.mod-before-last'),
    pulseEl = $('.photo_item.mod-last'),
    lastPhoto = $('.photo_item.mod-last'),
    currentItem = 0,

    rotateValues = ["-20deg", "20deg", "-10deg", "10deg", "0deg"],

    widthOffset = 100,
    heightOffset = 100,
    containerWidth = $('.photos').width() - widthOffset,
    containerHeight = $('.photos').height() - heightOffset,

    masterTimeline = new TimelineMax(),
    replayTimeline = new TimelineMax();

    Draggable.create(photoItem, {type:"x,y", edgeResistance:0.2 });

$('.js-btn').one('click', function(){
  start();
});


$('.js-restart-btn').on('click', function() {
  restartTimeline();
});


function start() {
  $('.js-btn').addClass('is-not-visible');
  $('.js-restart-btn').addClass('is-visible');
  masterTimeline.set(photoItem, { clearProps:"zIndex" })
  .add(beginGroupOne())
  .add(beginGroupTwo(), "-=.7")
  .add(beginGroupThree(), "-=.5")
  .add(beginGroupFour(), "-=.3")
  .add(beginGroupFive(), "-=.05");
}


function beginGroupOne() {
  var tl = new TimelineMax();
  groupOne.each(function(index, element) {
    tl.set(element, { x: getRandomInt(100, containerWidth), y: getRandomInt(50, containerHeight), rotation: getRandomRotate(), xPercent: -50, yPercent: -50 })
  });
  tl.staggerTo(groupOne, 1.25, { scale:1, autoAlpha:1, ease: Expo.easeOut }, .5, 0);
  return tl;
}


function beginGroupTwo() {
  var tl = new TimelineMax();
  groupTwo.each(function(index, element) {
    tl.set(element, { x: getRandomInt(100, containerWidth), y: getRandomInt(50, containerHeight), rotation: getRandomRotate(), xPercent: -50, yPercent: -50 })
  });
  tl.staggerTo(groupTwo, .75, { scale:1, autoAlpha:1, ease: Expo.easeOut }, .3, 0);
  return tl;
}


function beginGroupThree() {
  var tl = new TimelineMax();
  groupThree.each(function(index, element) {
    tl.set(element, { x: getRandomInt(100, containerWidth), y: getRandomInt(50, containerHeight), rotation: getRandomRotate(), xPercent: -50, yPercent: -50 })
  });
  tl.staggerTo(groupThree, .5, { scale:1, autoAlpha:1, ease: Expo.easeOut }, .2, 0);
  return tl;
}


function beginGroupFour() {
  var tl = new TimelineMax();
  groupFour.each(function(index, element) {
    tl.set(element, { x: getRandomInt(100, containerWidth), y: getRandomInt(50, containerHeight), rotation: getRandomRotate(), xPercent: -50, yPercent: -50 })
  });
  tl.staggerTo(groupFour, .25, { scale:1, autoAlpha:1, ease: Expo.easeOut }, .1, 0);
  return tl;
}


function beginGroupFive() {
  var tl = new TimelineMax();
  groupFive.each(function(index, element) {
    tl.set(element, { x: getRandomInt(100, containerWidth), y: getRandomInt(50, containerHeight), rotation: getRandomRotate(), xPercent: -50, yPercent: -50 })
  });
  tl.staggerTo(groupFive, 1.75, { scale:1, autoAlpha:1, ease: Expo.easeOut }, 1, 0);
  tl.to(beforeLastPhoto, 1.75, { x: -65, y: 115, xPercent: 0, yPercent: 0, scale:1, rotation: -20, autoAlpha:1, ease: Expo.easeOut }, "-=.5")
  .to(lastPhoto, 1.75, { x: 0, y: 0, xPercent: -50, yPercent: -50, scale:1, rotation: 10, autoAlpha:1, ease: Expo.easeOut }, "-=.5")
  .addCallback(finished, "+=1");
  return tl;
}


function moveOff() {
  var tl = new TimelineMax();
  tl.to([groupOne], 1.5, { yPercent: -1000 }, 0)
  .to(groupTwo, 1.5, { xPercent: -1000, }, 0)
  .to([groupThree, beforeLastPhoto], 1.5, { yPercent: 1000 }, 0)
  .to([groupFour, groupFive, lastPhoto], 1.5, { xPercent: 1000 }, 0);
  return tl;
}


function finished() {
  pulseEl.addClass('is-animating');
}


function restartTimeline() {
  masterTimeline.set(photoItem, { clearProps:"zIndex" })
  pulseEl.removeClass('is-animating');

  replayTimeline.add(moveOff())
  .addCallback(restart);
}

function restart() {
  masterTimeline.restart();
}

function getRandomRotate() {
  return rotateValues[Math.floor(Math.random() * rotateValues.length)];
}

function getRandomInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

See the Pen by homepage (@homepage) on CodePen

Link to comment
Share on other sites

I didn't have time to look through all the code, but I wanted to point out that in my experience, Chrome typically refuses to render transforms on elements that have display:inline. Perhaps that's the problem here? 

  • Like 1
Link to comment
Share on other sites

Hello schmolzp and welcome to the GreenSock Forum!

 

Jack is right.. according to the CSS spec.. see below link:

 

https://drafts.csswg.org/css-transforms-1/#terminology

 

transformable element
 

A transformable element is an element in one of these categories:

So you need to have a box model present in order for the browser to calculate the element properly.

 

When you use display:inline it is not a block-level element. If you do use display:inlein you will probably need to define a height and width. But still to play it safe use display:block.

 

Hope this sheds some light on why you see that issue in Chrome.

 

Resources:

https://developer.mozilla.org/en-US/docs/Web/HTML/Block-level_elements

https://drafts.csswg.org/css-transforms-1/#terminology

 

:)

  • Like 5
Link to comment
Share on other sites

Thanks for the reply. On the elements I am animating in, they are display: block, so I don't think that's the issue here. The strange thing is that when you click on the button, it will start animating great and then once it gets to the third batch of photos it starts to screw up. Several months ago, it was working great in Chrome. It would do exactly as it does now in Firefox/Safari. Are you able to see the issue I am talking about in Chrome? 

 

Thanks again for any help you can provide!

Link to comment
Share on other sites

Hi schmolzp,

 

Just to say that I do see the issue you're reporting. I don't have the time to look into it right now but will do some investigating later to see if I can see what might be the issue.

 

If, in the meantime, you could setup a little reduced-case demo that replicates the issue in CodePen or JSFiddle, it would be great as it would save me a to of time going over all the unrelated code on the site. You might end up discovering the issue yourself while deconstructing it - it has happened to me several times in the past.

 

 

  • Like 2
Link to comment
Share on other sites

Hello schmolzp,

 

By default the <img> element has a value of display: inline that it uses for its computed value.

 

You might have display:block in the CSS stylesheet. But the inline style of the <img> element shows display:inline in the browser inspector..

<img style="display:inline;" class="lazy" alt="" src="/homepage/2016_graduation/images/_first/02_lind_sayjane-4.jpg">

x

That inline style will override the display property you have in your stylesheet!

 

You can override the inline style by using the CSS !important declaration.

.photos .group figure > img {
  display: block !important;
}

Also to get the best help you should really create a reduced codepen demo otherwise it will be hard for us to see your code in context. And helps so we dont have to go through all the unrelated code you have on your site. In codepen we can test your code live in an editable environment.

 

:)

  • Like 4
Link to comment
Share on other sites

Thanks! I have created a reduced codepen demo. Hopefully, that will help you guys pinpoint the issue on Chrome. I also added

.photo_item > img { display: block !important; }

to the pen like you said. Let me know what you think.

 

See the Pen zojmPw by schmolzp (@schmolzp) on CodePen

 

:)

Link to comment
Share on other sites

Hello Again schmolzp

 

This should fix your issue.

 

See the Pen zojeoo by jonathan (@jonathan) on CodePen

 

It wasn't really a GSAP or Chrome bug. Just the way you were using the CSS will-change property ;)

 

Why this happens:

 

The issue in Chrome was that you are using the will-change property Line 20 for CSS rule .photo-item in the CSS panel. So i commented out the will-change property since it will cause more harm then good. So you don't need it!

will-change: transform, opacity;

/* will-change: transform, opacity; */

You wont need the will-change property. It should only be used in certain instances as a last resort. And can cause havoc when used.

 

https://developer.mozilla.org/en-US/docs/Web/CSS/will-change

 

The will-change property was being applied to many multiple elements and was causing the clipping of the Polaroid elements towards the end of animating the last several elements. That is why you only saw the clipping and fragmentation of elements rendering to the last elements being animated in.

 

will-change has some rules to its use. So in your case you don't need it since it is causing rendering issues, and your applying it to tremendous amount of DOM elements:

  • Don't apply will-change to too many elements.
  • Use sparingly.
  • Don't apply will-change to elements to perform premature optimization.
  • Be aware, that will-change may actually influence the visual appearance of elements

That is why it was causing your issue.

 

If you need to help GSAP record all your values upfront to improve performance you can start your masterTimline instance in a paused state by setting paused:true

masterTimeline = new TimelineMax({
      paused:true /* start timeline in paused state */ 
}),

in your start() function i added the last two methods progress() and play()

.add(beginGroupOne())
.add(beginGroupTwo(), "-=.7")
.add(beginGroupThree(), "-=.5")
.add(beginGroupFour(), "-=.3")
.add(beginGroupFive(), "-=.05")
.progress(1).progress(0) /* pre-record values and properties for optimazation */
.play(); /* play timeline */ 

progress(1) moves the playhead to the end and then back again to start using progress(0) to allow GSAP to pre-record the start and end values.

 

Hope this helps! Happy Tweening :)

  • Like 5
Link to comment
Share on other sites

Good find, Jonathan.

 

Also, there's an article I wrote about the dangers of will-change at http://greensock.com/will-change that might be worth a read. It's a property that was intended to help animators, but it actually does the opposite in many situations which is quite disturbing. I hope the browser vendors "will change" the way they implement that feature (see what I did there?) ;)

  • Like 4
Link to comment
Share on other sites

Thank you so much! 

 

You know, it's kinda funny. As I was constructing the codepen, I noticed and remembered that I had 'will-change' on that selector. I remembered how will-change was supposed to be helpful (in the beginning) but became much more harmful for developers to use. I deleted 'will-change' on my project to test it out and for some reason, it wasn't changing anything. But now that I try it again, it seems to be back to normal and working correctly for me. 

 

Also, thanks for the little tip on performance with starting the timeline in a paused state. This will help a lot!

 

You guys are the best!

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×