{"id":265831,"date":"2018-03-07T06:15:45","date_gmt":"2018-03-07T13:15:45","guid":{"rendered":"http:\/\/css-tricks.com\/?p=265831"},"modified":"2019-03-15T01:40:58","modified_gmt":"2019-03-15T08:40:58","slug":"what-houdini-means-for-animating-transforms","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/what-houdini-means-for-animating-transforms\/","title":{"rendered":"What Houdini Means for Animating Transforms"},"content":{"rendered":"
I’ve been playing with CSS transforms for over five years and one thing that has always bugged me was that I couldn’t animate the components of a <\/p>\n In order to better understand the issue at hand, let’s consider the example of a box we move horizontally across the screen. This means one The CSS is also pretty straightforward. We give this box dimensions, a See the Pen<\/a> by thebabydino (@thebabydino<\/a>) on CodePen<\/a>.<\/p>\n Next, with the help of a translation along the x<\/var> axis, we move it by half a viewport ( See the Pen<\/a> by thebabydino (@thebabydino<\/a>) on CodePen<\/a>.<\/p>\n Now the left half of the box is outside the screen. Decreasing the absolute amount of translation by half its edge length puts it fully within the viewport while decreasing it by anything more, let’s say a full edge length (which is See the Pen<\/a> by thebabydino (@thebabydino<\/a>) on CodePen<\/a>.<\/p>\n This is going to be our initial animation position.<\/p>\n We then create a set of This all works as expected, giving us a box that moves from left to right and back:<\/p>\n See the Pen<\/a> by thebabydino (@thebabydino<\/a>) on CodePen<\/a>.<\/p>\n But this is a pretty boring animation, so let’s make it more interesting. Let’s say we want the box to be scaled down to a factor of The box now also scales (demo<\/a>), but, since we’ve added an extra keyframe, the timing function is not applied for the whole animation anymore—just for the portions in between keyframes. This makes our translation slow in the middle (at See the Pen<\/a> by thebabydino (@thebabydino<\/a>) on CodePen<\/a>.<\/p>\n Now all works fine, but what if we wanted different timing functions for the translation and scaling? The timing functions we’ve set mean the transform<\/code> chain individually. This article is going to explain the problem, the old workaround, the new magic Houdini<\/a> solution<\/a> and, finally, will offer you a feast of eye candy through better looking examples than those used to illustrate concepts.<\/p>\n
The Problem<\/h3>\n
div<\/code> as far as the HTML goes:<\/p>\n
<div class=\"box\"><\/div><\/code><\/pre>\n
background<\/code> and position it in the middle horizontally with a
margin<\/code>.<\/p>\n
$d: 4em;\r\n\r\n.box {\r\n margin: .25*$d auto;\r\n width: $d; height: $d;\r\n background: #f90;\r\n}<\/code><\/pre>\n
50vw<\/code>) to the left (in the negative direction of the x<\/var> axis, the positive one being towards the right):<\/p>\n
transform: translate(-50vw);<\/code><\/pre>\n
$d<\/code> or
100%<\/code>—remember that
%<\/code> values in
translate()<\/code> functions are relative to the dimensions of the element being translated<\/a>), makes it not even touch the left edge of the viewport anymore.<\/p>\n
transform: translate(calc(-1*(50vw - 100%)));<\/code><\/pre>\n
@keyframes<\/code> to move the box to the symmetrical position with respect to the initial one with no translation and reference them when setting the
animation<\/code>:<\/p>\n
$t: 1.5s;\r\n\r\n.box {\r\n \/* same styles as before *\/\r\n animation: move $t ease-in-out infinite alternate;\r\n}\r\n\r\n@keyframes move {\r\n to { transform: translate(calc(50vw - 100%)); }\r\n}<\/code><\/pre>\n
.1<\/code> when it’s in the middle and have its normal size at the two ends. We could add one more keyframe:<\/p>\n
50% { transform: scale(.1); }<\/code><\/pre>\n
50%<\/code>) as we now also have a keyframe there. So we need to tweak the timing function, both in the
animation<\/code> value and in the
@keyframes<\/code>. In our case, since we want to have an
ease-in-out<\/code> overall, we can split it into one
ease-in<\/code> and one
ease-out<\/code>.<\/p>\n
.box {\r\n animation: move $t ease-in infinite alternate;\r\n}\r\n\r\n@keyframes move {\r\n 50% {\r\n transform: scale(.1);\r\n animation-timing-function: ease-out;\r\n }\r\n to { transform: translate(calc(50vw - 100%)); }\r\n}<\/code><\/pre>\n
animation<\/code> is slower at the beginning, faster in the middle and then slower again at the end. What if we wanted this to apply just to the translation, but not to the scale? What if we wanted the scaling to happen fast at the beginning, when it goes from
1<\/code> towards
.1<\/code>, slow in the middle when it’s around
.1<\/code> and then fast again at the end when it goes back to
1<\/code>?<\/p>\n