Tom’s generator does two things that help make a gradient better:
…
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.
]]>Tom’s generator does two things that help make a gradient better:
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.
Safari Tech Preview has experimental CSS gradient colorspaces and I had tons of fun playing around last night with it!
— Adam Argyle (@argyleink) February 6, 2022
“`#css
background: linear-gradient(
to right in var(–colorspace),
black, white
);
“`
basic black to white can be so different!https://t.co/ltCWtzUD23 pic.twitter.com/rlUIiDFJu9
To Shared Link — Permalink 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.
]]><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.
]]><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.
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.
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;
};
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.
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.
]]>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.
]]>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.
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.
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.
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.
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.
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!
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.
“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.
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.
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.
]]>animation-timing-function
…
Reversing an Easing Curve originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.
]]>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.
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:
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 aboveease-in
– the animation starts off slow and accelerates as it progressesease-out
– the animation starts off fast and decelerates towards the endease-in-out
– the animation starts off slowly, accelerates in the middle and slows down towards the endease
– the default value, a variant on ease-in-out
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:
Here, we can see the two points we need to plot, where the cubic-bezier function is cubic-bezier(x1, y1, x2, y2)
.
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:
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.
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.
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.
]]>Easing Linear Gradients originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.
]]>
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:
In this article, we’ll focus on how we can turn Il brutto into Il buono.
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.
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!)
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.
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.
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.
(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”.)
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.
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.
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.
We can’t create exactly that with linear gradients, but we can (and will) create a “low poly” approximation with more color stops.
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.
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.
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:
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.
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:
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.
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:
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:
The plugin currently has two optional settings:
precision
— correlates to number of color stops generatedalphaDecimals
— sets the number of decimals used in the hsla()
alpha valuesOverall, I’m fairly happy with the output. Things I’m considering to add:
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.
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.
Easing Linear Gradients originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.
]]>ease-out, in; ease-in, out originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.
]]>That said, it’s a balance between:
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.
There are two other built-in CSS timing functions:
ease-in
: slow at the beginning, fast/abrupt at the endease-out
: fast/abrupt at the beginning, slow at the endWhile 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.
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 brandease
and ease-in-out
have soft edges on both sides, but sometimes it’s more appropriate to use ease-in or ease-outAlso, 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.
]]>