Tag: Animations

Writing Animations That Bring Your Site to Life

Web animation is one of the factors that can strongly enhance your website’s look and feel. Sadly, unlike mobile apps, there aren’t as many websites using animation to their benefit as you would think. We don’t want to count yours among those, so this article is for you and anyone else looking for ways to use animation for a better user experience! Specifically, we’re going to learn how to make web interactions delightful using CSS animations.

Here’s what we’re going to build together:

Live Demo GitHub Repo

Before we move ahead, it’s worth mentioning that I’m going to assume you have at least some familiarity with modern front-end frameworks and a basic understanding of CSS animations. If you don’t, then no fear! CSS-Tricks has a great guides on React and Vue, as well as a thorough almanac post on the CSS animation property.

Good? OK, let’s talk about why we’d want to use animation in the first place and cover some baseline information about CSS animations.

Why would we to animate anything?

We could probably do an entire post on this topic alone. Oh, wait! Sarah Drasner already did that and her points are both poignant and compelling.

But, to sum things up based on my own experiences:

  • Animations enhance the way users interact with an interface. For example, smart animations can reduce cognitive load by giving users better context between page transitions.
  • They can provide clear cues to users, like where we want them to focus attention.
  • Animations serve as another design pattern in and of themselves, helping users to get emotionally attached to and engage with the interface.
  • Another benefit of using animations is that they can create a perception that a site or app loads faster than it actually does.

A couple of house rules with animations

Have you ever bumped into a site that animates all the things? Wow, those can be jarring. So, here’s a couple of things to avoid when working with animations so our app doesn’t fall into the same boat:

  • Avoid animating CSS properties other than transform and opacity. If other properties have to be animated, like width or height, then make sure there aren’t a lot of layout changes happening at the same time. There’s actually a cost to animations and you can see exactly how much by referring to CSS Triggers.
  • Also, just because animations can create perceived performance gains, there’s actually a point of diminishing return when it comes to using them. Animating too many elements at the same time may result in decreased performance.

Now we can get our hands dirty with some code!

Let’s build a music app

We’re going to build the music app we looked at earlier, which is inspired by Aurélien Salomon’s Dribbble shot. I chose this example so that we can focus on animations, not only within a component, but also between different routes. We’ll build this app using Vue and create animations using vanilla (i.e. no framework) CSS.

Animations should go hand-in-hand with UI development. Creating UI before defining their movement is likely to cost much more time. In this case, the Dribbble shot provides that scope for us.

Let’s start with the development.

Step 1: Spin up the app locally

First things first. We need to set up a new Vue project. Again, we’re assuming some base-level understanding of Vue here, so please check out the Learning Vue guide for more info on setting up.

We need a couple of dependencies for our work, notably vue-router for transitioning between views and sass-loader so we can write in Sass and compile to CSS. Here’s a detailed tutorial on using routes and Sass can be installed by pointing the command line at the project directory and using npm install -D sass-loader node-sass.

We have what we need!

Step 2: Setting up routes

For creating routes, we’re first going to create two bare minimum components — Artists.vue and Tracks.vue. We’ll drop a new file in the src folder called router.js and add routes for these components as:

import Vue from 'vue' import Router from 'vue-router' import Artists from './components/Artists.vue' import Tracks from './components/Tracks.vue'  Vue.use(Router) export default new Router({ 	mode: 'history', 	routes: [ 		{ 			path: '/', 			name: 'artists', 			component: Artists 		}, 		{ 			path: '/:id', 			name: 'tracks', 			component: Tracks 		} 	] })

Import router.js into the main.js and inject it to the Vue instance. Lastly, replace the content of your App.vue by <router-view/>.

Step 3: Create the components and content for the music app

We need two components that we’ll transition between with animation. Those are going to be:

  1. Artists.vue: a grid of artists
  2. Tracks.vue: An artist image with a back button

If you wanna jump ahead a bit, here are some assets to work with:

  1. Images and sample data in JSON format.
  2. Content for the components

When all is said and done, the two views will come out to something like this:

Artists.vue (left) and Tracks.vue (right)

Step 4: Animate!

Here we are, the part we’ve really wanted to get to all this time. The most important animation in the app is transitioning from Artists to Tracks when clicking on an artist. It should feel seamless where clicking on an artist image puts that image in focus while transitioning from one view into the next. This is exactly the type of animation that we rarely see in apps but can drastically reduce cognitive load for users.

To make sure we’re all on the same page, we’re going to refer to the first image in the sequence as the “previous” image and the second one as the “current” image. Getting the effect down is relatively easy as long as we know the dimensions and position of the previous image in the transition. We can animate the current image by transforming it as per previous image.

The formula that I’m using is transform: translate(x, y) scale(n), where n is equal to the size of previous image divided by the size of current image. Note that we can use a static value of n since the dimensions are fixed for all the images. For example, the image size in the Artists view is 190x190 and 240x240 in the Tracks view. Thus, we can replace n by 190/240 = 0.791. That means the transform value becomes translate(x, y) scale(0.791) in our equation.

Animating from Artists to Tracks

Next thing is to find x and y. We can get these values though click event in the Artists view as:

const {x, y} = event.target.getBoundingClientRect()

…and then send these values to the Tracks view, all while switching the route. Since we aren’t using any state management library, the two components will communicate via their parent component, which is the top level component, App.vue. In App.vue, let’s create a method that switches the route and sends the image info as params.

gotoTracks(position, artistId) { 	this.$ router.push({ 		name: 'tracks', 		params: { 			id: artistId, 			position: position 		} 	}) }

Here’s the relevant code from the repo to reference, in case you’re interested.

Since we have received the position and ID of the image in Tracks, we have all the required data to show and animate it. We’ll first fetch artist information (specifically the name and image URL) using artist ID.

To animate the image, we need to calculate the transform value from the image’s starting position. To set the transform value, I’m using CSS custom properties, which can be done with CSS-in-JS techniques as well. Note that the image’s position that we received through props will be relative to window. Therefore we’ll have to subtract some fixed offset caused by the padding of the container <div> to even out our math.

const { x, y } = this.$ route.params.position // padding-left const offsetLeft = 100 // padding-top const offsetTop = 30  // Set CSS custom property value document.documentElement.style.setProperty( 	'--translate',  	`translate($ {x - offsetLeft}px, $ {y - offsetTop}px) scale(0.792)` )

We’ll use this value to create a keyframe animation to move the image:

@keyframes move-image { 	from { 		transform: var(--translate); 	} }

This gets assigned to the CSS animation:

.image { 	animation: move-image 0.6s; }

…and it will animate the image from this transform value to its original position on component load.

Transitioning from Artists to Tracks

We can use the same technique when going the opposite direction, Tracks to Artists. As we already have the clicked image’s position stored in the parent component, we can pass it to props for Artists as well.

Transitioning from Tracks to Artists

Step 5: Show the tracks!

It’s great that we can now move between our two views seamlessly, but the Tracks view is pretty sparse at the moment. So let’s add the track list for the selected artist.

We’ll create an empty white box and a new keyframe to slide it upwards on page load. Then we’ll add three subsections to it: Recent Tracks, Popular Tracks, and Playlist. Again, if you want to jump ahead, feel free to either reference or copy the final code from the repo.

The Tracks view with content

Recent Tracks is the row of thumbnails just below the artist image where each thumbnail includes the track name and track length below it. Since we’re covering animations here, we’ll create a scale-up animation, where the image starts invisible (opacity: 0) and a little smaller than it’s natural size (scale(0.7)), then is revealed (opacity: 1 )and scales up to its natural size (transform: none).

.track { 	opacity: 0; 	transform: scale(0.7); 	animation: scale-up 1s ease forwards; }  @keyframes scale-up { 	to { 		opacity: 1; 		transform: none; 	} }

The Popular Tracks list and Playlist sit side-by-side below the Recent Tracks, where Popular tracks takes up most of the space. We can slide them up a bit on initial view with another set of keyframes:

.track { 	... 	animation: slide-up 1.5s; }  @keyframes slide-up { 	from { 		transform: translateY(140px); 	} }

To make the animation feel more natural, we’ll create a stagger effect so the Recent Tracks lead a little ahead of the Popular Tracks and Playlist using an incremental animation delay to each item.

@for $ i from 1 to 5 { 	&:nth-child(#{$ i + 1}) { 		animation-delay: #{$ i * 0.05}s; 	} }

The code above is basically looking for each child element, then adding a 0.05 second delay to each element it finds. So, for example, the first child gets a 0.05 second delay, the second child gets a 0.10 second delay and so on.

Check out how nice and natural this all looks:

Bonus: micro-interactions!

One of the fun things about working with animations is thinking through the small details because they’re what tie things together and add delight to the user experience. We call these micro-interactions and they serve a good purpose by providing visual feedback when an action is performed.

Depending on the complexity of the animations, we might need a library like anime.js or GSAP. This example is pretty straightforward, so we can accomplish everything we need by writing some CSS.

First micro-interaction: The volume icon

Let’s first get a volume icon in SVG format (Noun Project and Material Design are good sources). On click, we’ll animate-in and out its path element to show the level of volume. For this, we’ll create a method which switches its CSS class according to the volume level.

<svg @click="changeVolume"> 	<g :class="`level-$ {volumeLevel}`"> 		<path d="..."/> <!-- volume level 1 --> 		<path d="..."/> <!-- volume level 2 --> 		<path d="..."/> <!-- volume level 3 --> 		<polygon points="..."/> 	</g> </svg>

Based on this class, we can show and hide certain path elements as:

path { 	opacity: 0; 	transform-origin: left; 	transform: translateX(-5px) scale(0.6); 	transition: transform 0.25s, opacity 0.2s; }  .level-1 path:first-child, .level-2 path:first-child, .level-2 path:nth-child(2), .level-3 path { 	opacity: 1; 	transform: none; }
The animated volume control

Second micro-interaction: The favorite icon

Do you like it when you click on Twitter’s heart button? That’s because it feels unique and special by the way it animates on click. We’ll make something similar but real quick. For this, we first get an SVG heart icon and add it to the the markup. Then we’ll add a bouncy animation to it that’s triggered on click.

@keyframes bounce { 	0%, 100% { 		transform: none; 	} 	30% { 		transform: scale(1.3); 	} 	60% { 		transform: scale(0.9); 	} }

Another fun thing we can do is add other small heart icons around it with random sizes and positions. Ideally, we’d add a few absolute-positioned HTML elements that a heart as the background. Let’s Arrange each of them as below by setting their left and bottom values.

We’ll also include a fade away effect so the icons appear to dissolve as they move upward by adding a keyframe animation on the same click event.

@keyframes float-upwards { 	0%, 100% { 		opacity: 0; 	} 	50% { 		opacity: 0.7; 	} 	50%, 100% { 		transform: translate(-1px, -5px); 	} }
The animated favorite button

Summing up

That’s all! I hope you find all this motivating to try animations on your own websites and projects.

While writing this, I also wanted to expand on the fundamental animation principles we glossed over earlier because I believe that they help choose animation durations, and avoid non-meaningful animations. That’s important to discuss because doing animations correctly is better than doing them at all. But this sounds like a whole another topic to be covered in a future article.

The post Writing Animations That Bring Your Site to Life appeared first on CSS-Tricks.

CSS-Tricks

, , , ,

Slide an Image to Reveal Text with CSS Animations

I want to take a closer look at the CSS animation property and walk through an effect that I used on my own portfolio website: making text appear from behind a moving object. Here’s an isolated example if you’d like to see the final product.

Here’s what we’re going to work with:

See the Pen
Revealing Text Animation Part 4 – Responsive
by Jesper Ekstrom (@jesper-ekstrom)
on CodePen.

Even if you’re not all that interested in the effect itself, this will be an excellent exercise to expand your CSS knowledge and begin creating unique animations of your own. In my case, digging deep into animation helped me grow more confident in my CSS abilities and increased my creativity, which got me more interested in front-end development as a whole.

Ready? Set. Let’s go!

Step 1: Markup the main elements

Before we start with the animations, let’s create a parent container that covers the full viewport. Inside it, we’re adding the text and the image, each in a separate div so it’s easier to customize them later on. The HMTL markup will look like this:

<!-- The parent container --> <div class="container">    <!-- The div containing the image -->   <div class="image-container">   <img src="https://jesperekstrom.com/wp-content/uploads/2018/11/Wordpress-folder-purple.png" alt="wordpress-folder-icon">   </div>   <!-- The div containing the text that's revealed -->   <div class="text-container">     <h1>Animation</h1>   </div> </div>

We are going to use this trusty transform trick to make the divs center both vertically and horizontally with a position: absolute; inside our parent container, and since we want the image to display in front of the text, we’re adding a higher z-index value to it.

/* The parent container taking up the full viewport */ .container {   width: 100%;   height: 100vh;   display: block;   position: relative;   overflow: hidden; }  /* The div that contains the image  */ /* Centering trick: https://css-tricks.com/centering-percentage-widthheight-elements/ */ .image-container {   position: absolute;   top: 50%;   left: 50%;   transform: translate(-50%,-50%);   z-index: 2; /* Makes sure this is on top */ }  /* The image inside the first div */ .image-container img {   -webkit-filter: drop-shadow(-4px 5px 5px rgba(0,0,0,0.6));   filter: drop-shadow(-4px 5px 5px rgba(0,0,0,0.6));   height: 200px; }  /* The div that holds the text that will be revealed */ /* Same centering trick */ .text-container {   position: absolute;   top: 50%;   left: 50%;   transform: translate(-50%,-50%);   z-index: 1; /* Places this below the image container */   margin-left: -100px; }

We’re leaving vendor prefixes out the code examples throughout this post, but they should definitely be considered if using this in production environment.

Here’s what that gives us so far, which is basically our two elements stacked one on top of the other.

See the Pen
Revealing Text Animation Part 1 – Mail Elements
by Jesper Ekstrom (@jesper-ekstrom)
on CodePen.

Step 2: Hide the text behind a block

To make our text start displaying from left to right, we need to add another div inside our .text-container:

<!-- ... -->    <!-- The div containing the text that's revealed -->   <div class="text-container">     <h1>Animation</h1>     <div class="fading-effect"></div>   </div>    <!-- ... -->

…and add these CSS properties and values to it:

.fading-effect {   position: absolute;   top: 0;   bottom: 0;   right: 0;   width: 100%;   background: white; }

As you can see, the text is hiding behind this block now, which has a white background color to blend in with our parent container.

If we try changing the width of the block, the text starts to appear. Go ahead and try playing with it in the Pen:

See the Pen
Revealing Text Animation Part 2 – Hiding Block
by Jesper Ekstrom (@jesper-ekstrom)
on CodePen.

There is another way of making this effect without adding an extra block with a background over it. I will cover that method later in the article. 🙂

Step 3: Define the animation keyframes

We are now ready for the fun stuff! To start animating our objects, we’re going to make use of the animation property and its @keyframes function. Let’s start by creating two different @keyframes, one for the image and one for the text, which will end up looking like this:

/* Slides the image from left (-250px) to right (150px) */ @keyframes image-slide {   0% { transform: translateX(-250px) scale(0); }   60% { transform: translateX(-250px) scale(1); }   90% { transform: translateX(150px) scale(1); }   100% { transform: translateX(150px) scale(1); }   }  /* Slides the text by shrinking the width of the object from full (100%) to nada (0%) */ @keyframes text-slide {   0% { width: 100%; }   60% { width: 100%; }   75%{ width: 0; }   100% { width: 0; } }

I prefer to add all @keyframes on the top of my CSS file for a better file structure, but it’s just a preference.

The reason why the @keyframes only use a small portion of their percent value (mostly from 60-100%) is that I have chosen to animate both objects over the same duration instead of adding an animation-delay to the class it’s applied to. That’s just my preference. If you choose to do the same, keep in mind to always have a value set for 0% and 100%; otherwise the animation can start looping backward or other weird interactions will pop up.

To enable the @keyframes to our classes, we’ll call the animation name on the CSS property animation. So, for example, adding the image-slide animation to the image element, we’d do this:

.image-container img {   /* [animation name] [animation duration] [animation transition function] */   animation: image-slide 4s cubic-bezier(.5,.5,0,1); }

The name of the @keyframes works the same as creating a class. In other words the name doesn’t really matter as long as it’s called the same on the element where it’s applied.

If that cubic-bezier part causes head scratching, then check out this post by Michelle Barker. She covers the topic in depth. For the purposes of this demo, though, it’s suffice to say that it is a way to create a custom animation curve for how the object moves from start to finish. The site cubic-bezier.com is a great place to generate those values without all the guesswork.

We talked a bit about wanting to avoid a looping animation. We can force the object to stay put once the animation reaches 100% with the animation-fill-mode sub-property:

.image-container img {   animation: image-slide 4s cubic-bezier(.5,.5,0,1);   animation-fill-mode: forwards; }

So far, so good!

See the Pen
Revealing Text Animation Part 3 – @keyframes
by Jesper Ekstrom (@jesper-ekstrom)
on CodePen.

Step 4: Code for responsiveness

Since the animations are based on fixed (pixels) sizing, playing the viewport width will cause the elements to shift out of place, which is a bad thing when we’re trying to hide and reveal elements based on their location. We could create multiple animations on different media queries to handle it (that’s what I did at first), but it’s no fun managing several animations at once. Instead, we can use the same animation and change its properties at specific breakpoints.

For example:

@keyframes image-slide {   0% { transform: translatex(-250px) scale(0); }   60% { transform: translatex(-250px) scale(1); }   90% { transform: translatex(150px) scale(1); }   100% { transform: translatex(150px) scale(1); } }  /* Changes animation values for viewports up to 1000px wide */ @media screen and (max-width: 1000px) {   @keyframes image-slide {     0% { transform: translatex(-150px) scale(0); }     60% { transform: translatex(-150px) scale(1); }     90% { transform: translatex(120px) scale(1); }     100% { transform: translatex(120px) scale(1); }   } }

Here we are, all responsive!

See the Pen
Revealing Text Animation Part 4 – Responsive
by Jesper Ekstrom (@jesper-ekstrom)
on CodePen.

Alternative method: Text animation without colored background

I promised earlier that I’d show a different method for the fade effect, so let’s touch on that.

Instead of using creating a whole new div — <div class="fading-effect"> — we can use a little color trickery to clip the text and blend it into the background:

.text-container {   background: black;   -webkit-background-clip: text;   -webkit-text-fill-color: transparent; }

This makes the text transparent which allows the background color behind it to bleed in and effectively hide it. And, since this is a background, we can change the background width and see how the text gets cut by the width it’s given. This also makes it possible to add linear gradient colors to the text or even a background image display inside it.

The reason I didn’t go this route in the demo is because it isn’t compatible with Internet Explorer (note those -webkit vendor prefixes). The method we covered in the actual demo makes it possible to switch out the text for another image or any other object.


Pretty neat little animation, right? It’s relatively subtle and acts as a nice enhancement to UI elements. For example, I could see it used to reveal explanatory text or even photo captions. Or, a little JavaScript could be used to fire the animation on click or scroll position to make things a little more interactive.

Have questions about how any of it works? See something that could make it better? Let me know in the comments!

The post Slide an Image to Reveal Text with CSS Animations appeared first on CSS-Tricks.

CSS-Tricks

, , , ,
[Top]

Toggling Animations On and Off

A nicely detailed tutorial by Kirupa that gets into how you might provide a UI with persisted options that control whether animations run or not.

The trick is custom properties that control the movement:

body {   --toggle: 0;   --playState: "paused"; }

Which are used within animations and transitions:

.animation {   animation: bobble 2s infinite;   animation-play-state: var(--playState); }  .transition {   transition: transform calc(var(--toggle) * .15s) ease-in-out; }

And toggle-able by JavaScript:

// stop animation document.body.style.setProperty("--toggle", "0"); document.body.style.setProperty("--playState", "paused");  // play animation document.body.style.setProperty("--toggle", "1"); document.body.style.setProperty("--playState", "running");

Then get into using the media query to test for reduced motion off the bat, and storing the preferred value in localStorage.

Direct Link to ArticlePermalink

The post Toggling Animations On and Off appeared first on CSS-Tricks.

CSS-Tricks

,
[Top]

CSS Animations and Transitions in Email

We don’t generally think of CSS animations or transitions inside of email, or really any movement at all outside of an awkward occasional GIF. But there is really no reason you can’t use them inside HTML emails, particularly if you do it in a progressive enhancement-friendly way. Like, you could style a link with a hover state and a shaking animation, but if the animation (or even the hover) doesn’t work, it’s still a functional link. Heck, you can use CSS grid in email, believe it or not.

Jason Rodriguez just wrote Understanding CSS Animations in Email: Transitions and Keyframe Animations that covers some of the possibilities. On the supported list of email clients that support CSS transitions and keyframe animations is Apple Mail, Outlook, and AOL mail, among others.

Other things to look at:

The post CSS Animations and Transitions in Email appeared first on CSS-Tricks.

CSS-Tricks

, ,
[Top]