Let’s say you were gonna bounce an element all around a screen, sorta like an old school screensaver or Pong or something.
You’d probably be tracking the X location of the element, increasing or decreasing it in a time loop and — when the element reached the maximum or minimum value — it would reverse direction. Then do that same thing with the Y location and you’ve got the effect we’re after. Simple enough with some JavaScript and math.
Here’s The Coding Train explaining it clearly:
Here’s a canvas implementation. It’s Pong so it factors in paddles and is slightly more complicated, but the basic math is still there:
See the Pen
Pong by Joseph Gutierrez (@DerBaumeister)
on CodePen.
But what if we wanted to do this purely in CSS? We could write @keyframes
that move the transform
or left
/top
properties… but what values would we use? If we’re trying to bounce around the entire screen (viewport), we’d need to know the dimensions of the screen and then use those values. But we never know that exact size in CSS.
Or do we?
CSS has viewport units, which are based on the size of the entire viewport. Plus, we’ve got calc()
and we presumably know the size of our own element.
That’s the clever root of Scott Kellum’s demo:
See the Pen
Codepen screensaver by Scott Kellum (@scottkellum)
on CodePen.
The extra tricky part is breaking the X animation and the Y animation apart into two separate animations (one on a parent and one on a child) so that, when the direction reverses, it can happen independently and it looks more screensaver-like.
<div class="el-wrap x">
<div class="el y"></div>
</div>
:root {
--width: 300px;
--x-speed: 13s;
--y-speed: 7s;
--transition-speed: 2.2s;
}
.el {
width: var(--width);
height: var(--width);
}
.x {
animation: x var(--x-speed) linear infinite alternate;
}
.y {
animation: y var(--y-speed) linear infinite alternate;
}
@keyframes x {
100% {
transform: translateX(calc(100vw - var(--width)));
}
}
@keyframes y {
100% {
transform: translateY(calc(100vh - var(--width)));
}
}
I stole that idea, and added some blobbiness and an extra element for this little demo:
See the Pen
Morphing Blogs with `border-radius` by Chris Coyier (@chriscoyier)
on CodePen.
I just recently used this CSS technique to make an old style CRT Monitor: https://codepen.io/tystrong/pen/ewByaG
Do you have any ideas how could I apply Scott Kellum’s solution to positioned elements (position: absolute, top: 0, left: 30% etc.)? I am working on an animation, where the elements are positioned in the middle of the screen, then expand to the edge of the screen with transition and jQuery CSS. Then I want the elements to bounce around viewport randomly. The problem is that positioning interferes with the @keyframes animation and elements exit screen, it slips apart. I tried to change the “top”, “left” etc. values of the elements in jQuery with setTimeout, but then all the elements moved to the upper left corner of the screen right after the expansion. So I want them to start bouncin around from a fixed position after expanding. Is there a way to solve this? Thank you in advance, if you can help.