Jump to content
GreenSock

walltea

Tweening and Media Queries

Warning: Please note

This thread was started before GSAP 3 was released. Some information, especially the syntax, may be out of date for GSAP 3. Please see the GSAP 3 migration guide and release notes for more information about how to update the code to GSAP 3's syntax. 

Recommended Posts

Hi there,

 

I'm new to GSAP. I'm doing my first build with it and am loving it. I am running in to a bit of a problem in regards to element placement and where they are defined with media queries. 

 

My app defines its animations and initializes them all on page load. This is working wonderfully for all my animations with the exception of the home page. The problem with this animation is I am currently using media queries to position an element based on browser viewport size, so certain elements don't overlap, etc. This works fine when the page is loaded for the first time. GSAP grabs the correct CSS offset and animates the element in via: 

animations.homeSection.from("#home-art", 0.75, {css:{opacity:0, left: -100}}, "homeart")

The problem is, when this animation is initialized on page load, it grabs that CSS and sets it on the element in-line. Now if I resize the browser window, the element does not respond to the media queries and things overlap. I was trying to do some window.onresize things but have been largely unsuccessful at this point. If I manually set the css:left property of the element based on window sizing inside of a window onresize, when the page is reanimated, it reverts to the originally calculated position by GSAP. Is there any way around this? 

 

Thanks ahead of time.

 

Link to comment
Share on other sites

Hello and Welcome to the GreenSock Forums

 

Without seeing any or all of your code... You could try setting a resize event handler:

$(window).on('resize', function(){
         animations.homeSection.from("#home-art", 0.75, {css:{opacity:0, left: -100}}, "homeart");
});

also depending on your media query you can also check your content widths and adjust accordingly:

$(window).on('resize',function(){

        if($('#content').width() >= 400){
              // tweens or code can go here
        } else if($('#content').width() >= 800){
              // tweens or code can go here
        } 
});

you get the idea.. you basically check the width of the container you are testing against for the width in the media query and then apply your tweens when it meets your specif widths

 

or test between a specific width range:

if($('#content').width() >= 400 && $('#content').width() <= 800 ){
     // tweens or code can go here   
}

this would check to see if the content width was above 400px but below 800px

 

does that what you mean?

Link to comment
Share on other sites

I'm not sure this will achieve anything. Let me give you some code as an example.

$(function(){
    app.init();
});


var app = new App();


function App() {
    var animations = {
        homeSection = new TimelineMax({paused: true});
    }
    function _initAnimations() {
        animations.homeSection.from("#home .background", 1, {css:{opacity:0}})
            .from("#home-art", 0.75, {css:{opacity:0, left: -100}}, "homeart")
    }
    this.init = function() {
        _initAnimations();
    }
}

This is the basic setup of my App.

 

My problem is, when _initAnimations() fires on page start, the CSS (dependent on media queries is called) is pulled in by GSAP.  For example:

#home-art {
    background: url(../images/ui/sections/home/art.png);
    width: 1327px;
    height: 769px;
    position: absolute;
    left: 0;
}
@media (max-width: 1780px) {
    #home-art {
        left: -200px;
    }
}
@media (max-width: 1350px) {
    #home-art {
        left: -350px;
    }
}

So for example, the page is loaded with a window between 1350px and 1780px. #home-art will become left: -200px. If I resize the page to between 1000px and 1350px and I use a $(window).on('resize') event, like this:

$(window).resize(function(){
    var ww = $(window).width(),
        ha = $('#home-art');


    if(ww < 1350) ha.css('left', '-350px');
    if(ww < 1780 && ww >= 1350) ha.css('left', '-200px');
})

The left is set to -350px via javascript and all is well.

 

The PROBLEM, however, occurs if I change sections, and then go back to the home section (meaning I am replaying the animation). GSAP still thinks that the #home-art offset is still -200px and animates to that, when it should be -350px, now (based on media-query or javascript).

 

I guess real question is. If my animations are defined on load, how do I repopulate the {css:{left: x}} offset in real time? Defer the home animation initialization and have it define on resize? Or is there a way for me to modify this value in GSAP on the fly?

 

 

 

Link to comment
Share on other sites

you could try using one of the GSAP kill methods to stop / clear / kill the animation so when the resize event fires and checks with your if statement that the animation is killed and runs the tween again:

 

here are the available kill methods:

_________________________________________________________________

 

kill()

 

Kills the animation entirely or in part depending on the parameters.

 

http://api.greensock.com/js/com/greensock/core/Animation.html#kill()

//kill the entire animation:
myAnimation.kill();

//kill only the "x" and "y" properties of the animation (all targets):
myAnimation.kill({x:true, y:true});

//kill all parts of the animation related to the target "myObject" (if the tween has multiple targets, the others will not be affected):
myAnimation.kill(null, myObject);

//kill only the "x" and "y" properties of animations of the target "myObject":
myAnimation.kill({x:true, y:true}, myObject);

//kill only the "opacity" properties of animations of the targets "myObject1" and "myObject2":
myAnimation.kill({opacity:true}, [myObject1, myObject2]);

_________________________________________________________________

 

killAll()

 

Kills all tweens and/or delayedCalls/callbacks, and/or timelines, optionally forcing them to completion first.

 

http://api.greensock.com/js/com/greensock/TweenMax.html#killAll()

//kill everything
TweenMax.killAll();
//kill only tweens, but not delayedCalls or timelines
TweenMax.killAll(false, true, false, false);
//kill only delayedCalls
TweenMax.killAll(false, false, true, false);

_________________________________________________________________

 

killChildTweensOf()

 

Kills all tweens of the children of a particular DOM element, optionally forcing them to completion first.

 

http://api.greensock.com/js/com/greensock/TweenMax.html#killChildTweensOf()

<div id="d1">
<div id="d2">
<img src="photo.jpg" id="image" />
</div>
</div>
<div id="d3"></div>

TweenMax.to( document.getElementById("d2"), 1, {css:{left:100}});
TweenMax.to( document.getElementById("image"), 1, {css:{left:100}});
TweenMax.to( document.getElementById("d3"), 1, {css:{left:100}});
//only kills the first 2 tweens because those targets are child elements of the "d1" DOM element.
TweenMax.killChildTweensOf( document.getElementById("d1") );

_________________________________________________________________

 

killTweensOf()

 

Kills all the tweens (or specific tweening properties) of a particular object or the delayedCalls to a particular function.

 

http://api.greensock.com/js/com/greensock/TweenMax.html#killTweensOf()

TweenMax.killTweensOf(myObject);

TweenMax.killTweensOf(myObject, {opacity:true, x:true});

_________________________________________________________________

 

You could use any of the above GSAP methods to stop the animation which.. or kills the animation entirely or in part depending on the parameters and what method you use

 

In your case you can try using the killTweensOf() method:

$(window).resize(function(){

    var ww = $(window).width();

    if(ww < 1350) {
           var ha = document.getElementById(home-art);
           TweenMax.killTweensOf(document.getElementById(home-art));
           TweenMax.set(ha,{'left','-350px'});
    }

    if(ww < 1780 && ww >= 1350) {
           var ha = document.getElementById(home-art);
           TweenMax.killTweensOf(document.getElementById(home-art));
           TweenMax.set(ha,{'left','-200px'});
    }
})

if you notice i have the ha variable in each if statement so it only tries to find that element if the width meets the conditional. This way the resize event doesnt have to keep checking the DOM when the width if conditional isn't true.

 

also using document.getElementById() is faster than using the jQuery element object selector.

 

http://jsperf.com/getelementbyid-vs-jquery-id/13

 

also you will notice i used the GSAP set() method to set the css properties instead of using the jQuery css() method

 

http://api.greensock.com/js/com/greensock/TweenLite.html#set()

 

try that and see if that helps.. :)

  • Like 1
Link to comment
Share on other sites

Not sure I'm following everything but initially you said that your media queries weren't kicking in because of the inline styles that GSAP created on those elements.

 

You can use

TweenLite.set(element, {clearProps:"all"});

or 

TweenLIte.set(element, {clearProps:"left"});

To clear the inline styles.

 

This should work for the cases where you just want to make sure that elements get positioned "off screen" properly.

 

As for how elements animate at each screen size, you very well may have to kill() timelines (as Jonathan has suggested) and run your own custom functions to re-create new timelines with all the end values for the current screen size. 

  • Like 1
Link to comment
Share on other sites

Thanks for the responses. I'll start playing with these options.

 

I am getting an "Uncaught SyntaxError: Unexpected string" if I try to use:

TweenMax.set("#home-art",1,{'left','-350px'});

however.

 

Any idea why?

Link to comment
Share on other sites

Hi,

 

The reason is that set() instances are a shorthand equivalent to zero duration tweens, so you don't have to pass a second argument into the constructor after the tween target.

//GOOD SYNTAX

TweenLite.set(element, {vars});
//this is the same that the following line
TweenLite.to(element, 0, {vars});

//BAD SYNTAX
TweenLite.set(element, time, {vars});
//The engine is not expecting the time value so it returns an error

Take a look at the API reference:

 

http://api.greensock.com/js/com/greensock/TweenLite.html#set()

 

Rodrigo.

  • Like 3
Link to comment
Share on other sites

Even with the correct syntax

TweenLite.set(element, {vars});

I still get an unexpected string error. I'll try again in a few.

Link to comment
Share on other sites

if you can provide a

See the Pen by pen (@pen) on CodePen

or jsfiddle example it will be very helpful in helping you track down the issue..

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.
×