Tooltip to Gallery Transition

Today I’d like to share a little tooltip transition concept with you. The main idea is to show a preview of some sort of gallery with a rapid run through the thumbnails while we hover over some link in a text. Visually, this gets enhanced with a line animation that “frames” the thumbnail. Once we click the link, the thumbnail image animates to a larger version. The lines move along and the resting thumbnails animate in. In one last step, we can still click the bigger image and it will animate to a fullscreen view. The thumbnail navigation moves to the lower part of the page.

All these layout changes are facilitated by GreenSock’s Flip plugin. It makes it really simple to move things around and into new levels of content.

Note that this is an experimental concept where the gallery navigation is not implemented.

This is the initial view:

When hovering the link in the text, the tooltip shows:

The thumbnails get animated in a quick slideshow. When clicking on the link, the current thumbnail animates to the position of the text and enlarges:

Now we can still click on the larger image and it will animate to fill the screen:

And this is how it all comes together:

I really hope you enjoy this little concept and find it inspirational!

The images are by Google’s DeepMind on Unsplash.

Inline Layout Switch Ideas

After our last exploration of page transitions using covering elements we are now going to have a play with another kind of effect. The first idea is to have an inline-based layout with some text and images and then move the images to another column-based layout. The second idea is to hide the initial view using an animated clip-path, and show an underlying grid of images. The direction of motion in this animation is key to the effect.

The first experiment is quite similar to one of our previous demos which also shows an inline-based layout initially with some thumbnails that animate to a large version.

Our initial view of the first demo looks like this:

The column based layout looks as follows:

The animation looks like this:

The second demo shows how a clip-path can be used to create a page transition:

Hope you enjoy these two little experiments and find them useful!

Unreveal Effects for Content Previews

Some time ago, we explored a cover page transition that would hide some initial content and show another level of content, i.e. “unreveal” it. Today I’d love to share some more ideas for showing another page or preview, including one that uses CSS clip-path to achieve the effect.

This is our initial view:

When clicking on an item, we hide the current content by covering it with an expanding circle. Then uncover the preview by expanding a clip-path. This is the next view:

And this is how it all looks in action:

There are three different effects. Hope you enjoy them and find them useful!

Thanks for checking by!

Large Image to Content Page Transition

Today I’d like to share a little scroll effect and a page transition with you. It is inspired by Vitalii Burhonskyi‘s wonderful Dribbble shot. The idea is to have a parallax-like scroll effect on a main page with large images and titles. When clicking on an item, the large image animates to a smaller version in a content view.

For the smooth page scroll we are using Lenis and GSAP’s Flip plugin lets us easily animate the large image to its place in the content area.

The scroll effect contains a bit of an asymmetric scale animation, which gives it an interesting touch.

This is the initial view:

When we click on an item, the image animates to its place in a content area with more text:

And this is how it all comes together:

I hope you enjoy this little animation and find it useful!

Thanks for checking by 🙂

Tiny Grid Layout Animation

Today I’d like to share a very simple demo with you where we animate a tiny grid to a big one. For this kind of page transition we’re using GreenSocks’s Flip plugin which allows us to transition between two states in a super-easy way.

Another demo where we used the Flip plugin is the Lines To Content Layout Transition.

Here’s the initial view of our tiny grid:

Once we click on one of the tiny grid items, we animate the whole grid to its new position and show a big title.

Here we can hover each item and a little title is shown.

This is how it all looks animated:

If you view this on a small screen you will see how the layout is changed to a two-column grid.

Hope this inspires you somehow and thanks for checking by!

The post Tiny Grid Layout Animation appeared first on Codrops.

How to Create a Cover Page Transition

The other day I saw this nice Dribbble shot by Vitalii Burhonskyi that shows several lovely transitions. One of them is what I would call a “cover transition” where a black cover animates to hide some content and then some new content reveals on top of the cover (which is of a different color than the previous view).

I love the fact that we can have a plethora of different animations here to “unreveal” or show the new content. So I’ve created a sequence that we’ll explore today in a short tutorial where we’ll have a look at some highlights of the structure and animations.

We’ll be using GSAP from GreenSock as animation library.

Markup and Styles

Our initial view will show three items in a grid structure:

Let’s have a look at the markup for this. We’ll have a division for all items:

<div class="content">
	<div class="item">
		<span class="item__meta">2020</span>
		<h2 class="item__title">Alex Moulder</h2>
		<div class="item__img"><div class="item__img-inner" style="background-image:url(img/1.jpg)"></div></div>
		<p class="item__desc">I am only waiting for love to give myself up at last into his hands. That is why it is so late and why I have been guilty of such omissions.</p>
		<a class="item__link">view</a>
	</div>
	<div class="item">
		<span class="item__meta">2021</span>
		<h2 class="item__title">Aria Bennett</h2>
		<div class="item__img"><div class="item__img-inner" style="background-image:url(img/2.jpg)"></div></div>
		<p class="item__desc">They come with their laws and their codes to bind me fast; but I evade them ever, for I am only waiting for love to give myself up at last into his hands.</p>
		<a class="item__link">view</a>
	</div>
	<div class="item">
		<span class="item__meta">2022</span>
		<h2 class="item__title">Jimmy Hughes</h2>
		<div class="item__img"><div class="item__img-inner" style="background-image:url(img/3.jpg)"></div></div>
		<p class="item__desc">Clouds heap upon clouds and it darkens. Ah, love, why dost thou let me wait outside at the door all alone?</p>
		<a class="item__link">view</a>
	</div>
</div>

First, our whole page will be of a grid layout:

main {
	padding: 1.5rem 2.5rem 3rem;
	height: 100vh;
	display: grid;
	grid-template-columns: 100%;
	grid-template-areas: 'frame' 'content';
	grid-template-rows: min-content 1fr;
	grid-row-gap: 8vh;
}

The content division will have the following style to show the items in a grid:

.content {
	grid-area: content;
	max-width: 400px;
}

@media screen and (min-width: 53em) {
	.content {
		max-width: none;
		display: grid;
		grid-template-columns: repeat(3,1fr);
		grid-template-rows: 100%;
		grid-column-gap: 5vw;
	}
}

We only want to show the items side-by-side when we are on a large screen. So we add a media query.

For the item’s inner elements we’ll have the following style:

.item {
	margin-bottom: 5rem;
	display: grid;
	grid-template-columns: 100%;
	grid-template-rows: 1rem auto auto 1fr auto;
}

.item__title {
	font-family: kudryashev-d-excontrast-sans, sans-serif;
	font-weight: 300;
	font-size: 2rem;
	margin-bottom: 0.5rem;
}

.item__img {
	position: relative;
	overflow: hidden;
	width: 100%;
	aspect-ratio: 500/333;
}

.item__img-inner {
	background-position: 50% 45%;
	background-size: cover;
	width: 100%;
	height: 100%;
}

.item__desc {
	margin-top: 2.5rem;
	line-height: 1.1;
}

.item__link {
	cursor: pointer;
	text-transform: lowercase;
	width: 100%;
	padding: 1rem;
	color: var(--color-text);
	border: 1px solid var(--color-border);
	border-radius: 2rem;
	text-align: center;
}

.item__link:hover {
	background: var(--color-text);
	border-color: var(--color-text);
	color: var(--color-text-alt);
}

@media screen and (min-width: 53em) {
	.item {
		margin-bottom: 0;
	}
	.item__title {
		font-size: clamp(1.25rem,3vw,2rem);
	}
}

The image element has a nested structure that will allow us to make a little zoom effect. An interesting thing here is the aspect-ratio property that allows us to set responsive image dimensions according to its real size while using the background-image property.

When we click on the item button, we’ll show a cover animation. This will be the two elements animating their scale transform to cover the entire page:

<div class="overlay">
	<div class="overlay__row"></div>
	<div class="overlay__row"></div>
</div>

Let’s add the following style:

.overlay {
	position: fixed;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	display: grid;
	grid-template-columns: 100%;
	pointer-events: none;
	grid-template-rows: repeat(2,1fr);
}

.overlay__row {
	background: var(--color-overlay);
	transform: scaleY(0);
	will-change: transform;
}

.overlay__row:first-child {
	transform-origin: 50% 0%;
}

.overlay__row:last-child {
	transform-origin: 50% 100%;
}

Setting the right transform origins for each one of the “rows” will make sure that they animate from up and from down, “closing” the current view and hiding it.

Next, let’s have a look at the view we will see after. This section will be called “previews” and we’ll add the following content:

<section class="previews">
	<div class="preview">
		<div class="preview__img"><div class="preview__img-inner" style="background-image:url(img/1_big.jpg)"></div></div>
		<h2 class="preview__title oh"><span class="oh__inner">Moulder</span></h2>
		<div class="preview__column preview__column--start">
			<span class="preview__column-title preview__column-title--main oh"><span class="oh__inner">Alex Moulder</span></span>
			<span class="oh"><span class="oh__inner">2020</span></span>
		</div>
		<div class="preview__column">
			<h3 class="preview__column-title oh"><span class="oh__inner">Location</span></h3>
			<p>And if it rains, a closed car at four. And we shall play a game of chess, pressing lidless eyes and waiting for a knock upon the door.</p>
		</div>
		<div class="preview__column">
			<h3 class="preview__column-title oh"><span class="oh__inner">Material</span></h3>
			<p>At the violet hour, when the eyes and back, turn upward from the desk, when the human engine waits.</p>
		</div>
		<button class="unbutton preview__back"><svg width="100px" height="18px" viewBox="0 0 50 9"><path vector-effect="non-scaling-stroke" d="m0 4.5 5-3m-5 3 5 3m45-3h-77"></path></svg></button>
	</div>

	<!-- preview -->

	<!-- preview -->
	
</section>

The large image will animate with a reveal/unreveal animation that is explained in detail in this tutorial. That’s why we use a nested structure just like on the item image. For the texts that we want to show by translating (and being cut off by the parent), we’ll use the .oh > .oh__inner structure. The idea behind this is to translate the oh__inner element to hide it. For multi-line text we will add this structure dynamically with JavaScript. The paragraphs in our preview__column divisions will be broken into lines using SplitType.

Let’s add the following styles for the line magic to work:

.oh {
	position: relative;
    overflow: hidden;
}

.oh__inner {
	will-change: transform;
    display: inline-block;
}

.line {
	transform-origin: 0 50%;
	white-space: nowrap;
	will-change: transform;
}

Now, let’s get this baby animated.

The JavaScript

Let’s define and instantiate some things first:

import { gsap } from 'gsap';
import { Item } from './item';
import { Preview } from './preview';

// body element
const body = document.body;

// .content element
const contentEl = document.querySelector('.content');

// frame element
const frameEl = document.querySelector('.frame');

// top and bottom overlay overlay elements
const overlayRows = [...document.querySelectorAll('.overlay__row')];

// Preview instances array
const previews = [];
[...document.querySelectorAll('.preview')].forEach(preview => previews.push(new Preview(preview)));

// Item instances array
const items = [];
[...document.querySelectorAll('.item')].forEach((item, pos) => items.push(new Item(item, previews[pos])));

Now, when we open an item, we’ll first set our content to not be clickable anymore. That’s done with a class.

Then we hide all those lines and elements that we want to animate in once we show the preview content. The preview-visible class helps us set some colors and pointer events. We also use it to hide our little frame at the top of the page, so that we can then show it again with an animation once the cover hides the initial view.

The image gets unrevealed by translating the image element in one direction and the inner element (which actually contains the background-image) in the opposite direction.

We also show all the lines and oh__inner elements finally.

const openItem = item => {
    
    gsap.timeline({
        defaults: {
            duration: 1, 
            ease: 'power3.inOut'
        }
    })
    .add(() => {
        // pointer events none to the content
        contentEl.classList.add('content--hidden');
    }, 'start')

    .addLabel('start', 0)
    .set([item.preview.DOM.innerElements, item.preview.DOM.backCtrl], {
        opacity: 0
    }, 'start')
    .to(overlayRows, {
        scaleY: 1
    }, 'start')

    .addLabel('content', 'start+=0.6')

    .add(() => {
        body.classList.add('preview-visible');

        gsap.set(frameEl, {
            opacity: 0
        }, 'start')
        item.preview.DOM.el.classList.add('preview--current');
    }, 'content')
    // Image animation (reveal animation)
    .to([item.preview.DOM.image, item.preview.DOM.imageInner], {
        startAt: {y: pos => pos ? '101%' : '-101%'},
        y: '0%'
    }, 'content')
    
    .add(() => {
        for (const line of item.preview.multiLines) {
            line.in();
        }
        gsap.set(item.preview.DOM.multiLineWrap, {
            opacity: 1,
            delay:0.1
        })
    }, 'content')
    // animate frame element
    .to(frameEl, {
        ease: 'expo',
        startAt: {y: '-100%', opacity: 0},
        opacity: 1,
        y: '0%'
    }, 'content+=0.3')
    .to(item.preview.DOM.innerElements, {
        ease: 'expo',
        startAt: {yPercent: 101},
        yPercent: 0,
        opacity: 1
    }, 'content+=0.3')
    .to(item.preview.DOM.backCtrl, {
        opacity: 1
    }, 'content')

};

When we close the preview, we’ll need to do some reverse animations:

const closeItem = item => {
    
    gsap.timeline({
        defaults: {
            duration: 1, 
            ease: 'power3.inOut'
        }
    })
    .addLabel('start', 0)
    .to(item.preview.DOM.innerElements, {
        yPercent: -101,
        opacity: 0,
    }, 'start')
    .add(() => {
        for (const line of item.preview.multiLines) {
            line.out();
        }
    }, 'start')
    
    .to(item.preview.DOM.backCtrl, {
        opacity: 0
    }, 'start')

    .to(item.preview.DOM.image, {
        y: '101%'
    }, 'start')
    .to(item.preview.DOM.imageInner, {
        y: '-101%'
    }, 'start')
    
    // animate frame element
    .to(frameEl, {
        opacity: 0,
        y: '-100%',
        onComplete: () => {
            body.classList.remove('preview-visible');
            gsap.set(frameEl, {
                opacity: 1,
                y: '0%'
            })
        }
    }, 'start')

    .addLabel('grid', 'start+=0.6')

    .to(overlayRows, {
        //ease: 'expo',
        scaleY: 0,
        onComplete: () => {
            item.preview.DOM.el.classList.remove('preview--current');
            contentEl.classList.remove('content--hidden');
        }
    }, 'grid')
};

Let’s not forget the eventListeners:

for (const item of items) {
    // Opens the item preview
    item.DOM.link.addEventListener('click', () => openItem(item));
    // Closes the item preview
    item.preview.DOM.backCtrl.addEventListener('click', () => closeItem(item));
}

This is how it all comes together:

You can do a lot of different things here, either to animate the content in or out. The key is to keep things interesting when animating in and do a swift closing animation so that the user doesn’t have to wait to long for the initial view to come back 😉 Now it’s your turn! Explore the code and try to do some other animations, timing and easings to give it another feel and see what works and what doesn’t! Hope you have fun!

Thanks for checking by ✌ Hit me up if you want to work with me!

The post How to Create a Cover Page Transition appeared first on Codrops.

Image To Grid Transition

Today I have yet another image transition for you. This time, we’ll do something super simple: animate a large image to its place in a grid. This is certainly the first step of something more creative… think of two images, or three! Or maybe changing the size more dramatically! I hope this little experiment gives you some creative ideas 🙂

This is the initial view:

When clicking on the enter button, we animate the image to its tiny place in the grid:

If you are curious about how this grid is made, have a look at the HTML and the inline styles of each grid item: The grid is a responsive 100 ✕ 100 cell grid. We use some variables to set the column, row and the “size” by setting a proper span value over the column or row, like this:

<div class="grid__item" style="--c: 18;--r: 1;--cs: 22;--rs: 26;">
	<div class="grid__item-img" style="background-image:url(img/5.jpg)"></div>
	<h3 class="grid__item-title oh"><span class="oh__inner">Carrutha Method</span></h3>
</div>

The variables are then used in the CSS like this:

.grid__item {
	position: relative;
	display: grid;
	grid-template-areas: 'grid-img' 'grid-title';
	grid-template-rows: 100% auto;
	grid-column: var(--c) / span var(--cs);
	grid-row: var(--r) / span  var(--rs);
	will-change: opacity, transform;
}

This makes it easy to inspect the grid in the web inspector and then set the variables visually.

Let’s see how everything looks in a flow:

Thanks for checking by and hope you enjoy this little animation!

The post Image To Grid Transition appeared first on Codrops.

Stack to Content Layout Transition

Today I’d like to share a little experiment with you that is based on the layout transition of Aristide Benoist’s amazing homepage. Basically, I’m trying to rotate this layout just like Siddarth did in this shot. No WebGL for this experiment so we definitely don’t reach the slickness level of Aristide’s work but it’s fun to try it out.

Our initial scrollable view looks as follows:

Once we click on an item, we animate the stack to the right side, enlarging the items and showing our content:

Here we can now navigate using the arrows. Once we scroll, we move back to the initial stack view.

Here’s the whole flow in a video:

Please keep in mind that this is very experimental and that there might be bugs 😉

I really hope you have fun with this little experiment! Thanks for checking by!

The post Stack to Content Layout Transition appeared first on Codrops.

Image Trail Animation for an Intro

I’m very fascinated with the GSAP Flip plugin and I was itching to try more examples where a layout is animated. So today I’d like to share another experiment with you that shows how easy it is to make these kind of layout changes happen using this magical plugin. Once you understand what you can do with it, there’s just so many possibilities and you realize what a powerful tool it is. It accelerates development and I don’t want to miss it anymore, that’s for sure.

I based the design on this beautiful loading animation by Alex Tkachev and borrowed some design elements from this fantastic Behance presentation by Rron Berisha and Arlind Aliu.

The initial view is the loading screen that shows an increasing percentage on the left and the image on the right:

Once our fake loader reached 100%, we’ll animate the image into another view, using a trail effect:

When we click on the enter button, the title and image will move to yet another layout:

The flip plugin makes it super easy to move from one state to another while taking care of all the nasty details.

Let’s look at all the animations happening:

Hope you enjoy this demo and find this experiment useful!

The post Image Trail Animation for an Intro appeared first on Codrops.

Lines to Content Layout Animation

Today I’d like to share a little layout animation with you. The idea is to switch from a line view to a larger content view while animating a tiny image. This time, I used GreenSock’s Flip plugin which made things a lot easier as it does most of the work for transitioning an element to a new state and new layout.

The effect is inspired by part of this cool video by Holographik:

Typography elements disappear while images get animated to larger views.

The initial view of our layout is the following:

When clicking on one of the images, we transition to a new layout which looks as follows:

The whole flow looks like this:

The Flip plugin is a very useful tool that you can use for many complex cases. It also factors in nested transforms which is something quite special as it allows for powerful view switching without compromising your structures.

Hope you enjoy this demo and find it useful! Thanks for checking by!

The post Lines to Content Layout Animation appeared first on Codrops.