Jump to content
GreenSock

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

Animating modals

Recommended Posts

Hi all,

 

I would like to replicate the App Store Featured App/Games animation. See this to see what it may look like: https://alfian.d.pr/B7ZbXP

 

Basically, there will be 2 elements in which the styles would be the animated before modal is opened and a different styling after modal is opened. In the App Store case, its the image (increase width size) and the modal title (change x value position).

 

In my Codepen, I would like to replicate such an animation but I have no clue to using the GSAP code to do this. I know I asked a similar question to which the answer was to use SPA (Single-Page Application), but for this case I think its possible to animate with modals. I am using this plugin for the full screen modal pop-up.

 

Any ideas?

 

Thanks,

Alfian

See the Pen wmWzPR by aahlfeeyann (@aahlfeeyann) on CodePen

Link to post
Share on other sites

You know, this is something I've been thinking about doing ever since the App Store update ... I think it would be a great blog navigation element :)

 

You've pushed me to do it :) I'll let you know how it goes!

  • Like 2
Link to post
Share on other sites

Had a bit of time this afternoon ... here is a quick crack at it.

 

A few notes ... the HTML, CSS, and JS are setup to support progressive enhancement. If JS isn't available, you'd simply get a tile with a background image and an overlaid title. Clicking would push through the the target URL.

 

jQuery does some restructuring to get better control from both a CSS and a Tweening perspective. I'm also using jQuery to handle the simple click events.

 

I'm sure adjusting some timings (or even tween orders) would produce a better result ... I haven't gotten there yet :)

 

Big note ... I wouldn't look it here in the embedded CodePen ... I would go out and view it in a narrower viewport.

 

See the Pen JLKbBm?editors=0010 by sgorneau (@sgorneau) on CodePen

 

 

  • Like 6
Link to post
Share on other sites
5 hours ago, Shaun Gorneau said:

Had a bit of time this afternoon ... here is a quick crack at it.

 

A few notes ... the HTML, CSS, and JS are setup to support progressive enhancement. If JS isn't available, you'd simply get a tile with a background image and an overlaid title. Clicking would push through the the target URL.

 

jQuery does some restructuring to get better control from both a CSS and a Tweening perspective. I'm also using jQuery to handle the simple click events.

 

I'm sure adjusting some timings (or even tween orders) would produce a better result ... I haven't gotten there yet :)

 

Big note ... I wouldn't look it here in the embedded CodePen ... I would go out and view it in a narrower viewport.

 

See the Pen JLKbBm?editors=0010 by sgorneau (@sgorneau) on CodePen

 

 

 

Hey Shaun,

 

Thanks for the amazing CodePen. I think that's exactly what I want to do. However, I'm still quite a beginner in JS and GSAP. There are some parts of the JS code that I don't 100% understand. I do understand that the styling of the card happens in the TimelineMax, but in the .each function() what does that code do? And the .on function() what does it affect?

 

Thanks!

Link to post
Share on other sites
12 hours ago, alfianridwan said:

 

Hey Shaun,

 

Thanks for the amazing CodePen. I think that's exactly what I want to do. However, I'm still quite a beginner in JS and GSAP. There are some parts of the JS code that I don't 100% understand. I do understand that the styling of the card happens in the TimelineMax, but in the .each function() what does that code do? And the .on function() what does it affect?

 

Thanks!

 

Hi @alfianridwan, no problem at all. I'll break down a few things that are happening here ...

 

First and foremost ... I'm using jQuery to make some tasks much easier. If you're new to JS, you may or may not know the ins and outs of cross-browser compatibility. In short ... jQuery fights that battle for us. So your questions and my answers are addressing jQuery :)

 

$('document').ready( function(){

 

Is just waiting for the DOM to be ready before we do anything.

 

$('.blog-card img').each( function(){

 

So .each() is a jQuery method that allows us to iterate over the matched set ... in this case, all elements returned with the selector ".blog-card img". So what happens here is the DOM is scoured for all <img>  within elements with the class ".blog-card". Now that that images are returned as a set, jQuery's .each() will iterate over each one to perform all the actions with the .each(){ }. In plain english, here is what is happening within that,

  1. Find the <img>'s nearest (up the DOM tree) enclosing element with the class "blog-card". This is the card that the image belongs to.
  2. Within that card, inject an element before all its children ...  a new div using the current <img>'s (i.e. the <img> currently being referenced as we iterate with .each() ) src as the css background-image
  3. move the <h2> within the card to now be a child element of the new <div class="blog-card-background">
  4. Add in a new div to represent the "close" X in the top of the expanded card.
  5. remove the <img> from this card (we no longer need it)

Now, for the why to all the above :)

  1. We do this just to make a simple reference rather than asking jQuery to look up the tree many times. In this particular case, the hit is negligible. But it's good practice that if you are going to ask for something multiple times ... simply create a variable to hold it.
  2. For me, positioning and animating a div with a background image applied is much easier than positioning and animating the <img> itself. For example ... applying an image as a background with background-size: cover and background-position: 50% 50% tackles so many issues on its own when dealing with responsive images!
  3. Because the new <div class="blog-card-background"> is positioned relatively, it allows us to stick the (now) absolutely positioned <h2> to the bottom of the image (with padding) by using the CSS bottom property without any concern for how many lines the <h2> may be.
  4. We have to be able to close it! :)
  5. No use in keeping it in the DOM ... we are now using that image as a background for the <div class="blog-card-background">

You'll notice we did a lot of manipulation at this point with jQuery. But why? Why not just do all of this in the markup? Well, for several reasons.

  • If javascript isn't available (or some other script causes it to fail), we want the user to have something that
    • a. looks approriate and functions as expected (i.e. click a blog card and navigate go through to that blog post as a new web page)
    • b. doesn't present interface elements that perform no action

My basic rule ... if Javascript is required to interact, then Javascript is responsible for creating the element. So make sure it's usable without JS.

 

$('#some-blog').on( 'click', '.blog-card.inactive', fucntion(){ ...

 

This one is a bit nuanced, but I'll explain here. We want things to happen when something is clicked. Someting "A" when clicked in a "card" state and something "B" to happen when clicked in an open state. Now, I could have simply used ...

 

$('.blog-card.inactive').click( function(){ ...

 

Buuuuut, that does something a bit unexpected. A unique click handler get's bound to each matching element from that point forward .. regardless of losing the "inactive" class down the road. You might say, "that's OK, we're using a different element to close the open state.". And that's true ... but, clicking anywhere else anywhere within, in this example, the open blog post would still cause this handler to fire. We could do  some detection to remove this handler while in an open state and rebind after. But it's so much easier to do $('someSharedParentElement').on( 'click' , 'target', function(){ ... because it creates a single handler for all matching elements AND allows the handler to be bound to dynamically created elements down the road! Think of a blog with infinite scroll, for example. And, when the "blog-card" has its class changed from "inactive" to "active", this event handler is no longer bound. When it goes back to "inactive" it is bound :) Noice!

 

 

  • Like 6
Link to post
Share on other sites

Thank you Shaun for your patience and explanation. After a few trial and errors I finally managed to understand the code! Thank you so much once again :)

  • Like 2
Link to post
Share on other sites

@Shaun Gorneau

 

If you had a lot of content (many images, etc in blog post, or fetching static html from another file on server?) in each expanded "post", do you know the best way (or common approach) to fetch that post data and inject it into the modal/overlay container ("preloaded-content" above) upon executing the modal? 

I think what I'd like to do is have the thumbnail expand to the hero image in the same way, while simultaneously fetching the additional relative content below that hero image.

 

I hope this makes sense. Im not sure if you could still load the initial page and successfully prefetch the preloaded-content areas if they have a lot more data. (same dom approach as above? static?)  Or a better way to fetch the posts dynamically? Something like jquery load? 

 

Also, what if you were to paginate between the "post" content thats revealed, would you have to remove the thumbnail and headline from the dom prior to animating the hero/headline states? 

 

Im new to js, gsap and all that. I vaguely remember something years ago using jquery load to fetch that stuff ala ajax, but I'm not sure what's the best way to create a smooth hero transition from a card/thumbnail to an expanded view dynamically. 

 

Cheers ! 

 

 

 

Link to post
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.

×