easing – CSS-Tricks https://css-tricks.com Tips, Tricks, and Techniques on using Cascading Style Sheets. Mon, 07 Feb 2022 21:46:20 +0000 en-US hourly 1 https://wordpress.org/?v=6.2.2 https://i0.wp.com/css-tricks.com/wp-content/uploads/2021/07/star.png?fit=32%2C32&ssl=1 easing – CSS-Tricks https://css-tricks.com 32 32 45537868 Using Different Color Spaces for Non-Boring Gradients https://css-tricks.com/color-spaces-for-more-interesting-css-gradients/ https://css-tricks.com/color-spaces-for-more-interesting-css-gradients/#respond Mon, 07 Feb 2022 21:46:18 +0000 https://css-tricks.com/?p=363102 A little gradient generator tool from Tom Quinonero. You’d think fading one color to another would be an obvious, simple, solved problem — it’s actually anything but!

Tom’s generator does two things that help make a gradient better:

  1. You


Using Different Color Spaces for Non-Boring Gradients originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
A little gradient generator tool from Tom Quinonero. You’d think fading one color to another would be an obvious, simple, solved problem — it’s actually anything but!

Tom’s generator does two things that help make a gradient better:

  1. You can pick an “interpolation space.” Gradients that use the sRGB color space (pretty much all the color stuff we have in CSS today) have a bad habit of going through a gray dead zone, and if you interpolate the gradient in another color space, it can turn out nicer (and yet convert it back to RGB to use today).
  2. Easing the colors, though the use of multiple color-stops, which can result in a less abrupt and more pleasing look.
Showing a color wheel with a line indicating the two colors in a gradient that goes from yellow to light blue. The resulting gradient is at top showing some gray tones as a result of the color space.
See the gray in the middle there?

Different gradient apps with different color spaces

Josh has another similar app, as does Erik Kennedy. So stinkin’ interesting how different gradients are in different color spaces. Think of the color spaces as a physical map where individual colors are points on the map. Gradients are dumb. They just walk straight from one point on the map to the next. The colors underneath their feet as they walk make a massive difference in how the gradient turns out.

To Shared LinkPermalink on CSS-Tricks


Using Different Color Spaces for Non-Boring Gradients originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/color-spaces-for-more-interesting-css-gradients/feed/ 0 363102
Easing Animations in Canvas https://css-tricks.com/easing-animations-in-canvas/ https://css-tricks.com/easing-animations-in-canvas/#comments Fri, 19 Jun 2020 14:30:25 +0000 https://css-tricks.com/?p=312713 The <canvas> element in HTML and Canvas API in JavaScript combine to form one of the main raster graphics and animation possibilities on the web. A common canvas use-case is programmatically generating images for websites, particularly games. That’s exactly …


Easing Animations in Canvas originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
The <canvas> element in HTML and Canvas API in JavaScript combine to form one of the main raster graphics and animation possibilities on the web. A common canvas use-case is programmatically generating images for websites, particularly games. That’s exactly what I’ve done in a website I built for playing Solitaire. The cards, including all their movement, is all done in canvas.

In this article, let’s look specifically at animation in canvas and techniques to make them look smoother. We’ll look specifically at easing transitions — like “ease-in” and “ease-out” — that do not come for free in canvas like they do in CSS.

Let’s start with a static canvas. I’ve drawn to the canvas a single playing card that I grabbed out of the DOM:

Let’s start with a basic animation: moving that playing card on the canvas. Even for fairly basic things like requires working from scratch in canvas, so we’ll have to start building out functions we can use.

First, we’ll create functions to help calculate X and Y coordinates:

function getX(params) {
  let distance = params.xTo - params.xFrom;
  let steps = params.frames;
  let progress = params.frame;
  return distance / steps * progress;
}


function getY(params) {
  let distance = params.yTo - params.yFrom;
  let steps = params.frames;
  let progress = params.frame;
  return distance / steps * progress;
}

This will help us update the position values as the image gets animated. Then we’ll keep re-rendering the canvas until the animation is complete. We do this by adding the following code to our addImage() method.

if (params.frame < params.frames) {
  params.frame = params.frame + 1;
  window.requestAnimationFrame(drawCanvas);
  window.requestAnimationFrame(addImage.bind(null, params))
}

Now we have animation! We’re steadily incrementing by 1 unit each time, which we call a linear animation.

You can see how the shape moves from point A to point B in a linear fashion, maintaining the same consistent speed between points. It’s functional, but lacks realism. The start and stop is jarring.

What we want is for the object to accelerate (ease-in) and decelerate (ease-out), so it mimics what a real-world object would do when things like friction and gravity come into play.

A JavaScript easing function

We’ll achieve this with a “cubic” ease-in and ease-out transition. We’ve modified one of the equations found in Robert Penner’s Flash easing functions, to be suitable for what we want to do here.

function getEase(currentProgress, start, distance, steps) {
  currentProgress /= steps/2;
  if (currentProgress < 1) {
    return (distance/2)*(Math.pow(currentProgress, 3)) + start;
  }
  currentProgress -= 2;
  return distance/2*(Math.pow(currentProgress, 3)+ 2) + start;
}

Inserting this into our code, which is a cubic ease, we get a much smoother result. Notice how the card speeds towards the center of the space, then slows down as it reaches the end.

Advanced easing with JavaScript

We can get a slower acceleration with either a quadratic or sinusoidal ease.

function getQuadraticEase(currentProgress, start, distance, steps) {
  currentProgress /= steps/2;
  if (currentProgress <= 1) {
    return (distance/2)*currentProgress*currentProgress + start;
  }
  currentProgress--;
  return -1*(distance/2) * (currentProgress*(currentProgress-2) - 1) + start;
}
function sineEaseInOut(currentProgress, start, distance, steps) {
  return -distance/2 * (Math.cos(Math.PI*currentProgress/steps) - 1) + start;
};

For a faster acceleration, go with a quintic or exponential ease:

function getQuinticEase(currentProgress, start, distance, steps) {
  currentProgress /= steps/2;
  if (currentProgress < 1) {
    return (distance/2)*(Math.pow(currentProgress, 5)) + start;
  }
  currentProgress -= 2;
  return distance/2*(Math.pow(currentProgress, 5) + 2) + start;
}

function expEaseInOut(currentProgress, start, distance, steps) {
  currentProgress /= steps/2;
  if (currentProgress < 1) return distance/2 * Math.pow( 2, 10 * (currentProgress - 1) ) + start;
 currentProgress--;
  return distance/2 * ( -Math.pow( 2, -10 * currentProgress) + 2 ) + start;
};

More sophisticated animations with GSAP

Rolling your own easing functions can be fun, but what if you want more power and flexibility? You could continue writing custom code, or you could consider a more powerful library. Let’s turn to the GreenSock Animation Platform (GSAP) for that.

Animation becomes a lot easier to implement with GSAP. Take this example, where the card bounces at the end. Note that the GSAP library is included in the demo.

The key function is moveCard:

function moveCard() {
  gsap.to(position, {
    duration: 2,
    ease: "bounce.out",
    x: position.xMax, 
    y: position.yMax, 
    onUpdate: function() {
      draw();
    },
    onComplete: function() {
      position.x = position.origX;
      position.y = position.origY;
    }
  });
}

The gsap.to method is where all the magic happens. During the two-second duration, the position object is updated and, with every update, onUpdate is called triggering the canvas to be redrawn.

And we’re not just talking about bounces. There are tons of different easing options to choose from.

Putting it all together

Still unsure about which animation style and method you should be using in canvas when it comes to easing? Here’s a Pen showing different easing animations, including what’s offered in GSAP.

Check out my Solitaire card game  to see a live demo of the non-GSAP animations. In this case, I’ve added animations so that the cards in the game ease-out and ease-in when they move between piles.

In addition to creating motions, easing functions can be applied to any other attribute that has a from and to state, like changes in opacity, rotations, and scaling. I hope you’ll find many ways to use easing functions to make your application or game look smoother.


Easing Animations in Canvas originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/easing-animations-in-canvas/feed/ 2 312713
Ease-y Breezy: A Primer on Easing Functions https://css-tricks.com/ease-y-breezy-a-primer-on-easing-functions/ https://css-tricks.com/ease-y-breezy-a-primer-on-easing-functions/#comments Tue, 18 Dec 2018 19:28:24 +0000 http://css-tricks.com/?p=280294 During the past few months, I’ve been actively teaching myself how to draw and animate SVG shapes. I’ve been using CSS transitions, as well as tools like D3.js, react-motion and GSAP, to create my animations.

One thing about …


Ease-y Breezy: A Primer on Easing Functions originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
During the past few months, I’ve been actively teaching myself how to draw and animate SVG shapes. I’ve been using CSS transitions, as well as tools like D3.js, react-motion and GSAP, to create my animations.

One thing about animations in general and the documentation these and other animation tools recommend is using easing functions. I’ve been working with them in some capacity over the years, but to be honest, I would never know which function to choose for which kind of animation. Moreover, I did not know about the magic that goes into each of these functions, the notable differences between them, and how to use them effectively. But I was fine with that because I knew that easing functions somehow “smoothed” things out and mostly made my work look realistic.

Here, I present to you what I learned about easing functions in the form of a primer that I hope gives you a good understanding as you dig into animations.

How I got into easing functions

I tried to re-create a pattern called rotating snakes, an optical illusion that tricks the brains into thinking that circles rotate and “dance” when they are not.

I quickly found a gap in my knowledge when trying to build this out. It’s hard! But in the process, I discovered that easing functions play a big role in it.

I turned to JavaScript to draw a bunch of concentric circles in SVG using a library:

for (i = 1; i <= 10; i++) {
  drawCircle({radius: i * 10});
}

This was the result:

But that clearly does not look anything like the picture.

As I thought things through, I realized that I was looking for a certain property. I wanted the change in radius of the concentric circles to be small at the beginning and then become larger as the radius increases.

This means that the linear increase in radius using i++ won’t do the trick. We need a better formula to derive the radius. So, my next attempt looked something like this:

let i = 1;
let radiusList = [];
let radius = 0;
while (i <= 10) {
  drawCircle({radius: i * 10});
  if(i < 4) { i = i + 0.5 } else { i = i + 1 } 
}

…which got me this:

Hmm, still not what I wanted. In fact, this deviates even further from the pattern. Plus, this code is hardly customizable unwieldy to maintain.

So, I turned to math for one last attempt.

What we need is a function that changes the radius organically and exponentially. I had an “Aha!” moment and maybe you already see it, too. Easing functions will do this!

The radius of each circle should increase slowly at first, then quickly as the circles go outward. With easing, we can make move things along a curve that can slow and speed up at certain points.

A quick Google search landed me at this gist which is a well-documents list of easing functions and really saved my day. Each function takes one input value, runs formulae. and provides an output value. The input value has to be between 0 and 1. (We will dig into this reasoning later.)

A quadratic easing function looked promising because all it does is square the value it receives:

function (t) { return t*t }

Here’s the code I wound up using:

const easing = (t) => {
  return t*t
}
for(i = 0; i<=1; i=i+0.05) {
  const r = easing(i) * 40;
  drawCircle(r);
}

And we have a winner!

The difference between this pattern and my first two attempts was night and day. Yay for easing functions!

This little experience got me really interested in what else easing functions could do. I scoured the internet for cool information. I found old articles, mostly related to Flash and ActionScript which had demos showing different line graphs.

That’s all pretty outdated, so here’s my little primer on easing functions.

What are easing functions?

They’re a type of function that takes a numeric input between 0 and 1. That number runs through the specified function and returns another number between 0 and 1. A value between 0-1 multiplied by another value between 0-1 always results in a value between 0-1. This special property helps us make any computation we want while remaining within specific bounds.

The purpose of an easing function is to get non-linear values from linear value inputs.

This is the crux of what we need to know about easing functions. The explanations and demos here on out are all geared towards driving home this concept.

Easing functions are a manifestation of the interpolation concept in mathematics. Interpolation is the process of finding the set of points that lie on a curve. Easing functions are essentially drawing a curve from point 0 to point 1 by interpolating (computing) different sets of points along the way.

Robert Penner was the first to define easing functions and create formulae for different ones in his book.

The five types of easing functions

There are five types of easing functions. They can be mixed, inverted and even mashed together to form additional, more complex functions. Let’s dig into each one.

Linear easing functions

This is the most basic form of easing. If the interval between the points we interpolate between 0 and 1 are constant, then we then form a linear easing function.

Going back to the concentric circles example earlier, increasing the radius of the initial circle by a constant amount (10px in that example) makes a linear function.

It should come as no surprise that linear is the default easing function. They’re extremely simple because there is no curve to the animation and the object moves in a straight, consistent direction. That said, linear functions have their drawbacks. For example, linear animations tend to feel unnatural or even robotic because real-life objects rarely move with such perfect, straight motion.

Quadratic easing functions

A quadratic easing function is created by multiplying a value between 0 and 1 by itself (e.g. 0.5*0.5). As we learned earlier, we see that this results in a value that is also between 0 and 1 (e.g. 0.5*0.5 = 0.25).

To demonstrate, let’s make 10 values between 0 and 1 with a quadratic function.

const quad_easing = (t) => t*t;
let easing_vals = [];
for(let i = 0; i < 1; i +=0.1) {
  easing_vals.push(quad_easing(i));
}

Here’s a table of all the values we get:

Input Value (x-axis) Quadratic Eased Value (y-axis)
0 0
0.1 0.01
0.2 0.04
0.3 0.09
0.4 0.16
0.5 0.25
0.6 0.36
0.7 0.49
0.8 0.64
0.9 0.81
1 1

If we were to plot this value on a graph with x-axis as the original value and y-axis as the eased value, we would get something like this:

Notice something? The curve is practically the same as the ease-in functions we commonly find, even in CSS!

Cubic, Quartic and Quintic easing functions

The final three types of easing functions behave the same, but work with a different value.

A cubic easing function is creating by multiplying a value between 0 and 1 by itself three times. In other words, it’s some value (e.g. t), cubed (e.g. t3).

Quartic functions do the same, but to the power of 4. So, if t is our value, we’re looking at t4

And, as you have already guessed, a quintic function runs to the power of 5.

The following demo will give you a way to play around with the five types of functions for a good visual of how they differ from one another.

See the Pen Plotting Easing functions by Pavithra Kodmad (@pkodmad) on CodePen.

Easing in and easing out…or both!

“An ease-in-out is a delicious half-and-half combination, like a vanilla-chocolate swirl ice cream cone.”
— Robert Penner

Ease in and ease out might be the most familiar easing animations. They often smooth out a typical linear line by slowing down at the start or end (or both!) of an animation.

Ease-in and ease-out animations can be created using any of the non-linear functions we’ve already looked at, though cubic functions are most commonly used. In fact, the CSS animation property comes with ease-in and ease-out values right out of the box, via the animation-timing-function sub-property.

  • ease-in: This function starts slow but ends faster.
  • ease-out: This function starts fast and ends slower.
  • ease-in-out: This function acts as a combination of the others, starting fast, slowing down in the middle, then ending faster.

See the Pen Easing demo by Pavithra Kodmad (@pkodmad) on CodePen.

Go ahead and play around with them on this cubic-bezier.com.

These curves can be created in JavaScript as well. I personally like and use the bezier-easing library for it. Easing.js is another good one, as is D3’s library (with a nice example from Mike Bostock). And, if jQuery is more your thing, check out this plugin or even this one.

See, it’s pretty “ease”-y!

I hope this little primer helps illustrate easing functions and interpolation in general. There are so many ways these functions can make animations more natural and life-like. Have a look at Easing.css for a UI that allows you to create custom curves and comes with a slew of preset options.

I hope the next time you use an easing function, it won’t be a blackbox to you. You now have a baseline understanding to put easing functions to use and open up a ton of possibilities when working with animations.

More on easing

We’ve only scratched the surface of easing functions here, but there are other good resources right here on CSS-Tricks worth checking out to level up even further.


Ease-y Breezy: A Primer on Easing Functions originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/ease-y-breezy-a-primer-on-easing-functions/feed/ 2 280294
Reversing an Easing Curve https://css-tricks.com/reversing-an-easing-curve/ Mon, 17 Dec 2018 15:12:13 +0000 http://css-tricks.com/?p=280052 Let’s take a look at a carousel I worked on where items slide in and out of view with CSS animations. To get each item to slide in and out of view nicely I used a cubic-bezier for the animation-timing-function


Reversing an Easing Curve originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Let’s take a look at a carousel I worked on where items slide in and out of view with CSS animations. To get each item to slide in and out of view nicely I used a cubic-bezier for the animation-timing-function property, instead of using a standard easing keyword.

See the Pen Carousel with reversed easing curve by Michelle Barker (@michellebarker) on CodePen.

A cubic-bezier can appear confusing at first glance, but when used correctly, it can add a nice touch to the user experience.

While building this carousel, I realized I not only needed a custom animation curve, but had to use it in reverse as well to get the effect right. I figured it was worth sharing what I learned because creating a custom curve and reversing it may seem tricky, but it’s actually pretty straightforward.

First, a primer on easing

Easing is the word used to describe the acceleration and deceleration of an animation’s progress along a timeline. We can plot this as a graph, where x is time and y is the animation’s progress. The graph for a linear animation, which has no acceleration or deceleration (it moves at the same speed all the way through), is a straight line:

Linear easing graph

Non-linear easing is what gives animations a more natural, life-like feel. We can apply easing to transitions and animations in CSS. The animation-timing-function property allows us to define the easing on an animation. (The same options are available for transition-timing-function.) We have four keywords to choose from:

  • linear – as described above
  • ease-in – the animation starts off slow and accelerates as it progresses
  • ease-out – the animation starts off fast and decelerates towards the end
  • ease-in-out – the animation starts off slowly, accelerates in the middle and slows down towards the end
  • ease – the default value, a variant on ease-in-out
  • Getting to know cubic-bezier

    If none of those options suit our animation, we can create a custom easing curve using the cubic-bezier function. Here’s an example:

    .my-element {
      animation-name: slide;
      animation-duration: 3s;
      animation-timing-function: cubic-bezier(0.45, 0.25, 0.60, 0.95);
    }

    If we prefer, we can write these properties as shorthand, like this:

    .my-element {
      animation: slide 3s cubic-bezier(0.45, 0.25, 0.60, 0.95);
    }

    You’ll notice the cubic-bezier function takes four values. These are the two pairs of coordinates needed in order to plot our curve onto the graph. What do those coordinates represent? Well, if you’ve used vector illustration programs, like Illustrator, the idea of vector points and “handles” that control the size and direction of the curve might be familiar to you. This is essentially what we’re plotting with a cubic-bezier curve.

    We don’t need to know about all the maths behind cubic-bezier curves in order to create a nice animation. Luckily there are plenty of online tools, like cubic-bezier.com by Lea Verou, that allow us to visualize an easing curve and copy the values. This is what I did for the above easing curve, which looks like this:

    Cubic-bezier easing graph

    Here, we can see the two points we need to plot, where the cubic-bezier function is cubic-bezier(x1, y1, x2, y2).

    Cubic-bezier easing graph showing co-ordinates

    Applying easing in two directions

    My carousel rotates in both directions — if you click the left arrow, the current item slides out of view to the right, and the next item slides in from the left; and if you click the right arrow, the reverse happens. For the items to slide into or out of view, a class is added to each item, depending on whether the user has clicked the “next” or “previous” button. My initial assumption was that I could simply reverse the animation-direction for items sliding out in the opposite direction, like this:

    .my-element--reversed {
      animation: slide 3s cubic-bezier(0.45, 0.25, 0.60, 0.95) reverse;
    }

    There’s just one problem: reversing the animation also reversed the easing curve! So, now my animation looks great in one direction, but is completely off in the other direction. Oh no!

    In this demo, the first box shows the initial animation (an item sliding left-to-right) and the second box shows what happens when the animation-direction is reversed.

    See the Pen Reverse animation by Michelle Barker (@michellebarker) on CodePen.

    You can see the two animations don’t have the same feel at all. The first box speeds up early on and slows down gently as it progresses, while the second box starts off quite sluggish, then gains a burst of speed before abruptly slowing down. This wouldn’t feel right at all for a carousel.

    We have a choice between two options to achieve this:

    1. We could create a new keyframe animation to animate the items out, and then apply the same easing as before. That’s not too hard in this example, but what if we have a more complex animation? It would take quite a bit more work to create the same animation in reverse, and we could easily make a mistake.
    2. We could use the same keyframe animation (with the animation-direction: reverse) and invert the easing curve so we get the same easing in both directions. This isn’t too hard to do, either.

    To reverse the easing curve for our reversed animation we need to rotate the curve 180 degrees on its axis and find the new coordinates.

    Comparing original easing graph with reversed graph

    We can do this with some simple maths — by switching the coordinate pairs and subtracting each value from 1.

    To visualize this, imagine that our original values are:

    x1, y1, x2, y2

    Our reversed values will be:

    (1 - x2), (1 - y2), (1 - x1), (1 - y1)

    In this demo, the third box shows what we want to happen: the item sliding in the opposite direction, but with the easing reversed to give it the same feel.

    See the Pen CSS Variables to reverse easing by Michelle Barker (@michellebarker) on CodePen.

    Let’s walk through how we can calculate the reversed easing curve.

    Calculating the new curve with CSS variables

    We can use CSS variables to calculate the new curve for us! Lets assign each value to a variable:

    :root {
      --x1: 0.45;
      --y1: 0.25;
      --x2: 0.6;
      --y2: 0.95;
      
      --originalCurve: cubic-bezier(var(--x1), var(--y1), var(--x2), var(--y2));
    }

    Then we can use those variables to calculate the new values:

    :root {
      --reversedCurve: cubic-bezier(calc(1 - var(--x2)), calc(1 - var(--y2)), calc(1 - var(--x1)), calc(1 - var(--y1)));
    }

    Now, if we make any changes to the first set of variables, the reversed curve will be calculated automatically. To make this a bit easier to scan when examining and debugging our code, I like to break these new values out into their own variables:

    :root {
      /* Original values */
      --x1: 0.45;
      --y1: 0.25;
      --x2: 0.6;
      --y2: 0.95;
      
      --originalCurve: cubic-bezier(var(--x1), var(--y1), var(--x2), var(--y2));
      
      /* Reversed values */
      --x1-r: calc(1 - var(--x2));
      --y1-r: calc(1 - var(--y2));
      --x2-r: calc(1 - var(--x1));
      --y2-r: calc(1 - var(--y1));
      
      --reversedCurve: cubic-bezier(var(--x1-r), var(--y1-r), var(--x2-r), var(--y2-r));
    }

    Now all that remains is to apply the new curve to our reversed animation:

    .my-element--reversed {
      animation: slide 3s var(--reversedCurve) reverse;
    }

    To help visualize this, I’ve built a little tool to calculate the reversed values of a cubic-bezier. Enter the original coordinate values to get the reversed curve:

    See the Pen Reverse cubic-bezier by Michelle Barker (@michellebarker) on CodePen.


    Reversing an Easing Curve originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

    ]]> 280052 Easing Linear Gradients https://css-tricks.com/easing-linear-gradients/ https://css-tricks.com/easing-linear-gradients/#comments Mon, 08 May 2017 12:09:58 +0000 http://css-tricks.com/?p=254412 Linear gradients are easy to create in CSS and are extremely useful. As we’ll go through in this article, we can make them visually much smoother by creating them with non-linear gradients. Well, non-linear in the easing sense, anyway! …


    Easing Linear Gradients originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

    ]]>
    Linear gradients are easy to create in CSS and are extremely useful. As we’ll go through in this article, we can make them visually much smoother by creating them with non-linear gradients. Well, non-linear in the easing sense, anyway!

    Here’s an example that shows how harsh a standard linear-gradient() can be compared to how smooth we can make it by easing it:

    Screencap from “The Good, the Bad and the Ugly” with gradients overlaid.
    • Il buono (the good): Smooth gradients in CSS that blends into their context.
    • Il cattivo (the bad): No text protection (bad accessibility).
    • Il brutto (the ugly): Standard linear gradients with sharp edges.

    In this article, we’ll focus on how we can turn Il brutto into Il buono.

    The Frustrating Sharp Edges of background: linear-gradient()

    Lately, I’ve been fiddling with gradients at work. I got frustrated with plain linear gradients because they looked like Il cattivo above.

    /* Sharp edges :( */
    .image__text {
      background-image: linear-gradient(
        hsla(0, 0%, 0%, 0.6),
        transparent;
      );
    }

    I started looking into creating consistently more visually appealing gradients. More accurately, I quickly eyeballed some prettier-looking gradients as one-offs and then started tinkering when I got home.

    Inspiration: Math and Physics

    Since a gradient is a transition of color, I got inspired by how we approach transitions elsewhere.

    I’ve always been fascinated by the The Euler (or Cornu) Spiral, which has a curvature that increases linearly with the curve length, i.e., as we walk along the line from (0, 0) the radius decreases linearly with how far we walk (since the curvature is the reciprocal of the radius).

    The end result is a curve that transitions as smoothly as possible from a straight line to a curve. (Side note: straight lines in Euclidian space are curves with an infinite radius!)

    Euler Spiral by AdiJapan, CC BY-SA 3.0

    This type of curve is called a transition curve and is used in the real word. Next time when you exit a well-built highway, then notice how gradually you turn the steering wheel. We can thank Euler for keeping sudden changes in centripetal acceleration to an absolute minimum, i.e., his math is the reason the car doesn’t flip over just as we exit the highway even at the highway speed limit.

    The image below is an example of how gradual changes the changes are in the curvature of highways.

    Intersection outside of Sagamihara, Japan by @digitalanthill

    Inspiration: Typography

    Type designers throughout history have been obsessed with smooth curves. We’ve done so because we don’t want the letters and numbers to look like a combination of different shapes but in itself form a coherent shape.

    It’s why I’ve made the transition from a straight line to the circle in the “9” below as smooth as possible. It makes the number 9 read as a single shape and not a line plus a circle.

    As type designers we have tools to help us achieve this. FontForge, an open source font editor, even has a Spiro/Euler drawing mode. One of the most popular type design extensions is Speed Punk, which visualizes the curvature.

    Spiro mode in FontForge on the left and Speed Punk visualisation inside Glyphs on the right.

    Inspiration: Design

    Apple uses this approach to line-curve transitions heavily in both digital and hardware design departments. (See Apple’s Icons Have That Shape for a Very Good Reason). When Apple launched iOS7, the icon masks were updated to have a much smoother transition from straight line to rounded corners.

    Visualisation of the curvature of the iOS6 and iOS7 app icons.

    (Side note: The iOS7 shape above is taken directly from Apple HIG, which unfortunately has some minor imperfections especially where the horizontal lines start curving. It’s also sometimes known as a “Squircle”.)

    Inspiration: Web Design

    In web design, we’ve been limited in some cases by what we’re able to do. For example, border-radius doesn’t offer any way to make a squircle like the iOS7 icon. Similarly with linear-gradient, there is no natural easings available.

    However, we do have easings and bezier curves available in animations! They have enabled us to make animations look more natural, smooth, and subtle.

    Screenshot from easings.net

    Gradient Implications

    Most times, in web design, we want the gradient to blend in as much as possible. When we have a text protection gradient like Il buono, we don’t want the user to pay attention to the gradient itself. It should be rather invisible, thus, allowing the reader to focus on the image and text.

    Scrim

    In Material Design style guidelines for images, the designers at Google talk about text protection gradients. They call them a scrim. They recommend:

    [the] gradient should be long… with the center point about 3/10 towards the darker side of the gradient. This gives the gradient a natural falloff and avoids a sharp edge.

    A scrim according to Material Design guidelines

    We can’t create exactly that with linear gradients, but we can (and will) create a “low poly” approximation with more color stops.

    A scrim with 5 color stops to show the principle

    Using only 5 color stops (like in the illustration above) would create some serious banding. Adding more stops makes the gradient a lot smoother. This is exactly what I’ve done in the demo you saw in the first image in this article. Il buono has a 13 color-stop gradient, which makes it blend nicer into the image.

    See the Pen The Good, The Bad & The Ugly – correct text by Andreas Larsen (@larsenwork) on CodePen.

    Compared to the Material Design scrim, I’ve tweaked it to be a bit more linear in the beginning to achieve higher text contrast and gave it a smoother fade out.

    Comparison between the Material Design scrim and mine drawn using 13 color stops.

    If we compare the Material Design scrim to a plain linear gradient, then it will have to be ~60% longer to achieve the same half way contrast whereas my attempt only has to be ~30% longer. The idea is to avoid darkening more of the image than necessary but still blend in smoothly with it.

    The two scrims compared to a plain linear gradient

    I’ve chosen not to include the Material Design scrim as it’s almost identical to the prettier easeOutSine. We can compare how linear-gradient , my scrim-gradient and ease-out-sine-gradient looks here:

    Blending Both Ends

    In the scrim example, we only need to blend one end as the other ends with the image. Sometimes, we need to blend in at both ends, and that’s where the easing functions, such as easeInOutSine comes in handy.

    Linear-gradient vs. ease-in-out-sine approximation.

    Using an easeInOut function, we make sure that both the transition from colorA to gradient and gradient to colorB is as smooth as possible. The same principle is illustrated in this Pen:

    See the Pen.

    How to Draw the Gradients

    On YouTube, there’s a gradient behind the controls when you hover over a video. It’s created using a base64 PNG. This technique also works really well, but you can’t really automate it or easily tweak it.

    Screenshot from YouTube (artist is Wintergatan).

    Most other places use a linear-gradient(hsla(0, 0%, 0%, 0.8), transparent) where the start alpha most times is between 0.6-0.8. This solves the issue of making the text readable, but the resulting gradient is very prominent. An example of this is BBC where I tried using the scrim-gradient instead:

    Screenshots from BBC with linear-gradient (left) and scrim-gradient (right).

    PostCSS to the Rescue

    I created a plugin that creates these gradients for me. Here’s the syntax:

    scrim-gradient(
      black,
      transparent
    );

    becomes:

    linear-gradient(
      hsl(0, 0%, 0%) 0%,
      hsla(0, 0%, 0%, 0.738) 19%,
      hsla(0, 0%, 0%, 0.541) 34%,
      hsla(0, 0%, 0%, 0.382) 47%,
      hsla(0, 0%, 0%, 0.278) 56.5%,
      hsla(0, 0%, 0%, 0.194) 65%,
      hsla(0, 0%, 0%, 0.126) 73%,
      hsla(0, 0%, 0%, 0.075) 80.2%,
      hsla(0, 0%, 0%, 0.042) 86.1%,
      hsla(0, 0%, 0%, 0.021) 91%,
      hsla(0, 0%, 0%, 0.008) 95.2%,
      hsla(0, 0%, 0%, 0.002) 98.2%,
      hsla(0, 0%, 0%, 0) 100%
    );

    The underlying principle is the one we’ve gone through: combining easing functions and multiple color stops to create approximations that look smoother than plain linear-gradients.

    Actually, the scrim-gradient above is generated using a custom set of coordinates but if we look at the easing gradients such as ease-in-out-sine-gradient the steps are:

    1. Run through the .css (or .pcss) and find it.
    2. Generate evenly distributed coordinates along the ease-in-out-sine curve.
    3. Use these coordinates to create color stops. The x-coordinate determines the color mixing ratio, and the y-coordinate determines the color stop position.
    4. Replace the easing-gradient with the generated linear-gradient.
    Ease-in-out-sine coordinate values generated in step 2.

    The plugin currently has two optional settings:

    • precision — correlates to number of color stops generated
    • alphaDecimals — sets the number of decimals used in the hsla() alpha values

    The Plugin: postcss-easing-gradients

    Overall, I’m fairly happy with the output. Things I’m considering to add:

    • Sass version? I’m not using it anymore. Perhaps, someone else would like to write one?
    • The coordinates used to mix the colors for the color stops are distributed evenly over the easing curves. Ideally, the distance between the color stops would be relatively shorter where the delta change in curvature is biggest.
    • Maybe you folks have some ideas?

    You can find it on GitHub, NPM and as a template on CodePen. Go play around with it! Your contributions and suggestions are very welcome.

    CSS

    Preferably, I’d like to be able to write something like ease-in-out-gradient(#bada55, transparent) and have the browser understand it without having to do any custom CSS processing.

    References/Further Reading


    Easing Linear Gradients originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

    ]]>
    https://css-tricks.com/easing-linear-gradients/feed/ 24 254412
    ease-out, in; ease-in, out https://css-tricks.com/ease-out-in-ease-in-out/ https://css-tricks.com/ease-out-in-ease-in-out/#comments Wed, 18 May 2016 14:36:36 +0000 http://css-tricks.com/?p=241825 We got to talking about easing in a recent episode of ShopTalk with Val Head and Sarah Drasner. Easing is important stuff when it comes to animations and transitions. Combined with the duration, it has a huge effect on the …


    ease-out, in; ease-in, out originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

    ]]>
    We got to talking about easing in a recent episode of ShopTalk with Val Head and Sarah Drasner. Easing is important stuff when it comes to animations and transitions. Combined with the duration, it has a huge effect on the feel of change. If you’re taking animation seriously as part of the brand on a project, you should define and consistently use easings.

    That said, it’s a balance between:

    • Crafting/using easings that match your brand
    • Adhering to soft “rules” about what type of easings are appropriate when

    Let’s look at one particular best practice, as I understand it. But first, another observation.

    The default transition-timing-function in CSS (the easing) is ease.

    .thing {
    
      /* The default, as in, you get this without defining anything */
      transition-timing-function: ease;
    
      /* Also the same as */
      transition-timing-function: cubic-bezier(0.25, 0.1, 0.25, 1);
      
    }

    It’s a pretty nice one! I’m guilty of hardly ever changing it. I set and tweak the durations and generally leave it to ease. Too nice, perhaps? I wonder if we would be more proactive about choosing well-fitting easings if CSS defaulted to the more boring/lifeless linear easing. Although linear can be quite useful, I’ve found, when the change is very small, like only moving a few pixels or a color changing shade.

    The ease timing function is so nice, perhaps, because it’s a variant of ease-in-out. That is, the change happens slowly both at the beginning and end, and speeds up only in the middle somewhere. This gives soft edges (metaphorically) to the change and generally feels good.

    ease vs. ease-in-out. They look quite different but are in the same vein. From cubic-bezier.com

    There are two other built-in CSS timing functions:

    • ease-in: slow at the beginning, fast/abrupt at the end
    • ease-out: fast/abrupt at the beginning, slow at the end

    While they make a certain intuitive sense looked at that way, the general “rule” (in quotes) is to use them opposite of how they are named:

    • ease-in: when things are moving out.
    • ease-out: when things are moving in.

    Think of a knight’s squire. When the knight calls them, they better arrive at a run, and slow down into place. When the knight sends them away, they’d better very quickly get moving out of there.

    That feels like a best practice. Like the animation is being courteous and obedient on both sides. Get here in a hurry, but compose yourself. Get out of here even faster and without delay.

    Here’s the CSS that goes along with that kind of thinking. This changes the easing function depending on if the element in question is being shown or being hid, as well as the timing.

    .container .alert {
    
      /* This timing applies on the way OUT */
      transition-timing-function: ease-in;
    
      /* Quick on the way out */
      transition: 0.2s;
    
      /* Hide thing by pushing it outside by default */
      transform: translateY(130%);
    
    }
    
    .container.alert-is-shown .alert {
    
      /* This timing applies on the way IN */
      transition-timing-function: ease-out;
    
      /* A litttttle slower on the way in */
      transition: 0.25s;
      
      /* Move into place */
      transform: translateY(0);
    
    }

    See the Pen Different eases for “in” and “out” by Chris Coyier (@chriscoyier) on CodePen.

    I put this CSS-based demo together based on the smart things Val and Sarah were talking about as well as recently seeing Google’s design spec for this exact movement.

    Google is saying don’t ease-out on the way out, presumably as it looks like it’s lagging getting the heck out of your way. Also, entering over 0.225 seconds and exiting over 0.195 seconds.

    The animation timings we’re using here are also in “rule” territory, as Val generally described: 0.1-0.2s for simple interface movements, and up to 0.5s for more complex or larger movements.

    In summary:

    • ease is pretty nice, but you might want to customize some easings that feel right for your brand
    • ease and ease-in-out have soft edges on both sides, but sometimes it’s more appropriate to use ease-in or ease-out
    • You don’t have to use a single easing for both directions of an animation, you can switch it up
    • You can change duration also

    Also, here’s a handy-dandy reference to the defaults and their matching cubic-bezier in case you want to start with one of them and customize from there:

    .examples {
    
      transition-timing-function: linear;
      transition-timing-function: cubic-bezier(0, 0, 1, 1);
    
      transition-timing-function: ease;
      transition-timing-function: cubic-bezier(0.25, 0.1, 0.25, 1);
    
      transition-timing-function: ease-in-out;
      transition-timing-function: cubic-bezier(0.42, 0, 0.58, 1);
    
      transition-timing-function: ease-in;
      transition-timing-function: cubic-bezier(0.42, 0, 1, 1);
    
      transition-timing-function: ease-out;
      transition-timing-function: cubic-bezier(0, 0, 0.58, 1);
    
    }

    ease-out, in; ease-in, out originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

    ]]>
    https://css-tricks.com/ease-out-in-ease-in-out/feed/ 3 241825