Skip to content

[css-easing] Allow steps() to accept an easing function as the <step-position> #11970

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
bramus opened this issue Mar 20, 2025 · 6 comments
Open
Labels
css-easing-2 Current Work

Comments

@bramus
Copy link
Contributor

bramus commented Mar 20, 2025

Recently Vasilis asked:

Dearest CSS working group, I want to be able to define a transition between the steps in an animation-timing-function. Can you please fix this?

They needed this create the seconds hand of this clock which uses an ease between every second it ticks: https://vasilis.nl/clocks/station-clock/01/

As a workaround I pointed them to creating a bunch of keyframes and setting the animation-timing-function per keyframe, which they did, resulting in a lot of code.:

/* 
Very annoying, but this is, for now, the only way to 
transition between steps() in a keyframe animation.
Had to write out every percentage. 
*/
@keyframes ticking {
	0% {
		rotate: 0deg;
		animation-timing-function: ease;
	}
	1.66666666% {
		rotate: 6deg;
		animation-timing-function: ease;
	}
	3.33333333% {
		rotate: 12deg;
		animation-timing-function: ease;
	}
	…
	98.33333333% {
		rotate: 354deg;
		animation-timing-function: ease;
	}
	100% {
		rotate: 360deg;
		animation-timing-function: ease;
	}
}
.seconds {
  animation: ticking 58s linear;
}

(Not sure why they chose 58s, though)

If steps() were to accept another easing function as the <step-position>, the code could be simplified to the following:

@keyframes ticking {
  to {
    rotate: 360deg;
  }
}

.seconds {
  animation: ticking 60s steps(60, ease);
}
@bramus bramus added the css-easing-2 Current Work label Mar 20, 2025
@birtles
Copy link
Contributor

birtles commented Mar 21, 2025

Can't you do it with a really long linear() function?

That said, I could imagine a few different animations where this would be useful. If CSS had SMIL's accumulate attribute this would be easier still 😅

@bramus
Copy link
Contributor Author

bramus commented Mar 21, 2025

Can't you do it with a really long linear() function?

Yes, but then you’d need a generator to generate the contents for linear(), resulting in a long and highly unreadable string. In contrast, steps(60, ease); is very readable, concise, and clearly conveys what it does.

@ydaniv
Copy link
Contributor

ydaniv commented Mar 23, 2025

@bramus not sure I understand, are they asking to be able to set the keyframe-wide easing once in the animation-timing-function? If so then this is already what that does, unlike the new animation-easing property we resolved to add.
So not setting ease in each keyframe and putting it once in the animation shorthand is already equivalent.

@bramus
Copy link
Contributor Author

bramus commented Mar 24, 2025

are they asking to be able to set the keyframe-wide easing once in the animation-timing-function?

No, they are asking to set the easing between the steps. Like this:

Image

@ydaniv
Copy link
Contributor

ydaniv commented Mar 24, 2025

Gotcha! Then your proposal sounds fine, however, I wonder if we have any other use-cases beside creating an animated clock?
That aside, this could have been possible today with WAAPI in one line if we had iterationComposite cross-browser: https://jsbin.com/yulefimane/1/edit?css,js,output 😀 🙏 (don't open in Chromium)

@birtles
Copy link
Contributor

birtles commented Mar 25, 2025

That aside, this could have been possible today with WAAPI in one line if we had iterationComposite cross-browser: https://jsbin.com/yulefimane/1/edit?css,js,output

Ah, yes, I forgot we specified that. I think that's more useful for this case because it allows you to easily have a flat part followed by an ease part which seems more clock-like to me, e.g.

window.target.animate({
  rotate: ['0deg', '0deg', '6deg']
}, {
  duration: 1000,
  iterations: Infinity,
  iterationComposite: 'accumulate',
  easing: 'ease'
});

JSbin

I'm not sure how you'd achieve that with the steps(3, ease) approach.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
css-easing-2 Current Work
Projects
None yet
Development

No branches or pull requests

3 participants