pixelcog / parallax.js

Simple parallax scrolling effect inspired by Spotify.com implemented as a jQuery plugin
MIT License
3.53k stars 840 forks source link

React Animation Transition Issue #247

Open dailenspencer opened 6 years ago

dailenspencer commented 6 years ago

Hey guys,

I've been cooking on an issue for awhile and cant seem to figure out the root of it. My site is a SPA built on React.js and uses animations to transition from url to url.

When the user transitions from the blog page(www.dailenspencer.com/blog) to a blog post page (www.dailenspencer.com/blog/0001) - parallax doesnt work as expected.

Case 1(failure case): • head to www.dailenspencer.com/blog • click on the first blog item to initialize the transition to the page with parallax.js • result: parallax.js not working.

Case 2(failure case): • head to www.dailenspencer.com/blog/0001 • result: parallax.js is working

Case 3(success case): • head to www.dailenspencer.com/blog • click on the first blog item to initialize the transition to the page with parallax.js • click the back button and then re-click on the first blog item • result: parallax.js is working

Case 4(success case): • head to www.dailenspencer.com/blog/0001 • hit the back button • click on the first blog item to initialize the transition to the page with parallax.js • result: parallax.js is working

My conclusion is that the parallax.js implementation is working as expected, only when the user loads up a clean page(i.e. hit www.dailenspencer.com/blog/0001) OR when the user initializes parallax.js once(doesnt work first time around), and then leaves the page and returns.

I'm using the Alpha version. Here is my parallax.js initialization

$('.parallax-window').parallax({
    speed: .2,
    sliderSelector: '>.parallax-slider',
    mirrorSelector: '.page-blogpost',
    scrollingSelector: '.page-blogpost'
})

You can see the HTML/CSS on the live site at www.dailenspencer.com/blog/0001

At first, I thought this issue would be related to parallax.js not re-calculating the window size when the animation starts/ends. But i've added a Mutation Observer that watches for the animation and then rapidly calls a resize & scroll event throughout the animation. $(window).trigger('resize').trigger('scroll') If you head to dailenspencer.com and perform the correct steps(head from dailenspencer.com/blog -> dailenspencer.com/blog/0001), you will see the resize console log being triggered. The numbers are coming from a log I placed inside the loadDimensions() function.

Parallax.wH = $win.height();
Parallax.wW = $win.width();
Parallax.dH = $se[0].scrollHeight || $se.height();
Parallax.dW = $se[0].scrollWidth || $se.width();
console.log(Parallax.wH, Parallax.wW, Parallax.dH, Parallax.dW)

These numbers are very consistent so I know its not the window calculation causing the issue :/

As I continue to investigate i'll be making some updates to this issue. If anyone would like access to the repo i'd be happy to add you on. I've made a few minor changes to jquery.parallax.js but none that I see would cause this sort of issue. Will appreciate any and all help!!

UPDATE: With further investigation, I can see now that the results vary from load to load. You may find that the cases I laid out before do not match your results.

dailenspencer commented 6 years ago

This is a bit hacky so i'd like to keep this issue open until a response. You guys might have another solution you see right off the bat thats a bit less hack. For those wondering - here is the solution. I add a mutation observer when my component mounts(this component holds the parallax.js implementation). When the page is done transitioning, i disconnect the observer. However, there is still the issue of parallax.js not working on the initial load. The first time I go from /blog to /blog/0001, no bueno. But every time after that, it works fine. Interesting stuff..

var count = 0;
        var initWindowResize = _.throttle(function(){
            if (count > 2 && !$('.transitioning').length) { //disconnect observer when page is done transitining
                observer.disconnect();
            } else if (count > 2) { //for some reason, we cant trigger the resize/scroll event for two counts. If we do it before, parallax.js will get funky
                $(window).trigger('resize').trigger('scroll')
            }
            count++;
        }, 10)

        var observer = new MutationObserver((mutations) => {
            mutations.forEach((mutationRecord) => {
               initWindowResize();
            });    
        });

        var target = document.getElementById('blog-post');
        observer.observe(target, { attributes : true, attributeFilter : ['style'] });
wstoettinger commented 6 years ago

hey @dailenspencer !

the problem has got something to do with performance optimizations. in this case the problem is the assumption, that the aspect ratio of the scrolling container stays about the same throughout the session. since in your case the parallax is already initialized when the transition starts, the aspect ratio is way too high.

you could try setting the aspect ratio to null after the transition is completed and trigger a resize afterwards

$('.parallax-window').data('__parallax').o.aspectRatio = null;
$(window).trigger('resize').trigger('scroll')

that's also a bit hacky to access the options element directly but maybe a bit smoother ;) there has been a plan to implement a "configure" function where you could pass such parameters after the instance has been created already.

hope that helps!

dailenspencer commented 6 years ago

@wstoettinger Ah I see now. Thank you for the help :) That seemed to assist a few of the issues i've been seeing. I've updated the site and am still getting some varied results. I cant pick up on a pattern, but the images being supplied to parallax will successfully load in some cases, but not in others. If you head to the site I think you'll see what I mean. I wanted to think that its relative to the loading speed but both my mobile device and laptop are seeing the same results.

Pretty much i'm just refreshing dailenspencer.com/blog/0001 to get the results

wstoettinger commented 6 years ago

@dailenspencer although I cannot reproduce the issue, I'm guessing that this happens when the parallax is initialized before the image is loaded, which should normally not cause a problem.

nevertheless I would recommend you to decrease the size of the image (or images in general). A 1 Mb is about 10 times too big for such an image. In case of having a gradient in a PNG (the shadow) you could also consider converting it into a jpeg and compress it with mozJPEG at 85%-90% quality. I just got a 100k jpg out of it with negligible impact on quality.

dailenspencer commented 6 years ago

@wstoettinger You're definitely onto something. I reduced the size of both the images and now I consistently get back the first image with each load. The second image is consistently not loaded though. So following your train of thought - i've reduced the size of the first image, and it has appropriate time to load but the second does not. Going to look through the parallax file later today to see if theres any functions I could call to get the proper refresh for the images

dailenspencer commented 6 years ago

UPDATE:

ended up removing the if statement inside the Parallax refresh function so that we recalculate the aspect ratio every time.

// if (!options.aspectRatio) {

Not sure the scope of what this will impact but i've just got some higher priority objectives to push through so until it breaks something big, i'm happy :) closing issue

wstoettinger commented 6 years ago

make sure you test it on safari and firefox quantum. most performance issues are related to those two.

i'll reopen this and flag it as a feature suggestion for something like:

options.forceRecalculateAspectRatio = true;