Set CSS transition to use speed instead of duration?

No, there is no transition-speed css property, however there is a transition-timing-function-property

If you use that function, you can set the speed of the transition relative to the duration, and can use steps as well. As per the spec:

The ‘transition-timing-function’ property describes how the intermediate values used during a transition will be calculated. It allows for a transition to change speed over its duration. These effects are commonly called easing functions. In either case, a mathematical function that provides a smooth curve is used.

Timing functions are either defined as a stepping function or a cubic Bézier curve. The timing function takes as its input the current elapsed percentage of the transition duration and outputs the percentage of the way the transition is from its start value to its end value. How this output is used is defined by the interpolation rules for the value type.

A stepping function is defined by a number that divides the domain of operation into equally sized intervals. Each subsequent interval is a equal step closer to the goal state. The function also specifies whether the change in output percentage happens at the start or end of the interval (in other words, if 0% on the input percentage is the point of initial change).

I believe this transition timing function property is the closest thing to what you want, but I am aware that it's not the same as a speed property.


As you can't set speed, I made 2 samples, where the smaller box moves slightly faster in sample 1, which of course it has to, as it has a longer way to travel within the same time frame.

In sample 2 I compensated that by setting the bigger box's duration to 3s, where they now (almost) have the same speed.

Best way would likely be to calculate the distance to travel, based on the size of the box, and use that value to calculate the duration needed, to make boxes, no matter size, to travel at the same speed.

.div1 div {
    width: 100px;
    height: 100px;
    background-color: red;
    position: relative;
    animation-name: example1;
    animation-duration: 4s;
    animation-iteration-count: infinite;
    animation-timing-function: linear;
}
.div2 div {
    width: 200px;
    height: 200px;
    background-color: blue;
    position: relative;
    animation-name: example2;
    animation-duration: 4s;
    animation-iteration-count: infinite;
    animation-timing-function: linear;
}


@keyframes example1 {
    0%   {left:0px; top:0px;}
    100%  {left:400px; top:0px;}
}
@keyframes example2 {
    0%   {left:0px; top:0px;}
    100%  {left:300px; top:0px;}
}


.div3 div {
  width: 100px;
  height: 100px;
  background-color: red;
  position: relative;
  animation-name: example3;
  animation-duration: 4s;
  animation-iteration-count: infinite;
  animation-timing-function: linear;
}
.div4 div {
  width: 200px;
  height: 200px;
  background-color: blue;
  position: relative;
  animation-name: example4;
  animation-duration: 3s;
  animation-iteration-count: infinite;
  animation-timing-function: linear;
}


@keyframes example3 {
  0%   {left:0px; top:0px;}
  100%  {left:400px; top:0px;}
}
@keyframes example4 {
  0%   {left:0px; top:0px;}
  100%  {left:300px; top:0px;}
}
<br>Sample 1<br>

<div class="div1">
  <div></div>
</div>
<div class="div2">
  <div></div>
</div>

<br>Sample 2<br>

<div class="div3">
  <div></div>
</div>
<div class="div4">
  <div></div>
</div>

CSS offers no way to do this, so you have to calculate the duration in JavaScript yourself and set it.

For instance, consider this animation (with a fixed duration, and thus a variable speed):

@keyframes slideball {
  0%   { margin-left: 0px; }
  100% { margin-left: calc(100% - 30px); }
}
.slider {
    height: 30px;
    background: blue;
    border-radius: 20px;
    margin: 10px;
    padding: 5px;
}
#slider1 {
    width: 80px;
}
#slider2 {
    width: 200px;
}
#slider3 {
    width: 500px;
}
.ball {
    height: 30px;
    width: 30px;
    border-radius: 30px;
    background: red;
    animation: slideball linear 10s forwards;
}
<div id="slider1" class="slider">
    <div class="ball"></div>
</div>
<div id="slider2" class="slider">
    <div class="ball"></div>
</div>
<div id="slider3" class="slider">
    <div class="ball"></div>
</div>

Suppose we want the balls to all advance at 40px per second, regardless of how wide the slider containing them is. We can then compute the resulting animation duration in JavaScript and set the animation style property from JavaScript:

function startAnimation(slider) {
    const ball = slider.children[0],
          speed = 40, // px per second
          distancePx = (
              slider.offsetWidth
              - parseInt(getComputedStyle(slider).paddingLeft)
              - parseInt(getComputedStyle(slider).paddingRight)
              - ball.offsetWidth
          ),
          duration = distancePx / speed;
    ball.style.animation = `slideball linear ${duration}s forwards`;
}

startAnimation(document.getElementById('slider1'));
startAnimation(document.getElementById('slider2'));
startAnimation(document.getElementById('slider3'));
@keyframes slideball {
  0%   { margin-left: 0px; }
  100% { margin-left: calc(100% - 30px); }
}
.slider {
    height: 30px;
    background: blue;
    border-radius: 20px;
    margin: 10px;
    padding: 5px;
}
#slider1 {
    width: 80px;
}
#slider2 {
    width: 200px;
}
#slider3 {
    width: 500px;
}
.ball {
    height: 30px;
    width: 30px;
    border-radius: 30px;
    background: red;
}
<div id="slider1" class="slider">
    <div class="ball"></div>
</div>
<div id="slider2" class="slider">
    <div class="ball"></div>
</div>
<div id="slider3" class="slider">
    <div class="ball"></div>
</div>

Yeah, it's a bit verbose and annoying, especially because calculating distances travelled when you've got a bunch of margins and paddings and borders and such involved may sometimes get a little... intricate. But CSS currently doesn't offer you any better tool to use, so you're stuck with approaches like this.