Why does my Transform snap back?
Solution 1:
Cause and Solution:
CSS Transforms generally cannot be applied to elements that have display: inline
setting. While it is strange that the transform
does seem to happen initially before snapping back, the solution would be to change the setting to display: inline-block
like in the below snippet.
.blockquote {
font-family: "Open Sans", Verdana, Arial, sans-serif;
font-size: 30px;
line-height: 60px;
width: 100%;
background-color: rgba(0, 0, 0, 0.16);
/*rgba(192, 241, 247, 0.15);*/
height: 100px;
text-align: center;
padding-top: 40px;
color: white;
font-weight: 300;
font-style: italic;
transition: all 250ms ease-in-out;
}
.blockquote .blockquote2 {
transition: all 250ms ease-in-out;
font-size: 25px;
line-height: 35px;
width: 90%;
}
.blockquote .author {
display: inline-block;
margin-left: -150px;
transition: all 250ms ease-in-out;
font-family: "Roboto", sans-serif;
color: #838eca;
text-transform: uppercase;
font-size: 20px;
letter-spacing: 2px;
line-height: 35px;
opacity: 0;
}
.blockquote:hover .blockquote2 {
transform: translateX(-20px);
transition: all 250ms ease-in-out;
}
.blockquote:hover .author {
opacity: 1;
font-weight: 900;
color: rgb(25, 137, 228);
transform: translateX(200px);
transition: all 250ms ease-in-out;
}
<div class="blockquote">
<div class="blockquote2"> <b>雕刻</b>自己的路
<p class="author">- Jason Zhang</p>
</div>
</div>
Why does the element get translated initially if it is not transformable?
The behavior of browsers (atleast Chrome) seems to be strange and I can only think it is a bug but it is very likely that this behavior is due to accelerated rendering in browsers and the way layers are created and moved around to provide higher performance.
In modern browsers, a compositing layer is created whenever a certain criteria is matched by the render objects (the DOM nodes) and having an animated/transitioned transform is one of them (refer the article mentioned in references). Now when this happens, the GPU applies the transformation only to the compositing layer by changing its composited attributes. This (for some reason unknown to me) doesn't seem to take the display
setting on the element into consideration and so the element/layer gets translated.
However at the beginning and the end of the transition
, browser repaints the entire page because there is no need of an extra compositing layer once the transition
is complete and this repaint seems to put the element back into its original place.
Below is a very simple snippet that I have created with transforms on span
tag to illustrate my point above. Run the snippet after enabling "Show paint rectangles" and "Show composited layer borders" options from Chrome Dev tools (check reference item 3 for how to enable these settings). You will note that initially when you hover
anywhere on body
and the transition
is about to start, a paint happens (green or red blink on screen) to create the compositing layers. Once this process is done, you will note an orange border getting applied to the span
tag. This is the compositing layer and you will see how only this layer moves when the transition
happens. At the end another repaint happens to remove the layers (as it is no longer required) and this puts the element back into its correct place based on specifications.
body:hover span {
transition: all 1s 1s;
transform: translateX(200px);
}
<span>abcd</span>
As mentioned earlier, I cannot provide an authoritative answer on why the compositing layer behaves this way but based on the sample snippet and the reference articles, you can see that my assertion holds good.
References:
- W3C Spec - Transformable elements
- Chromium Projects - GPU Accelerated Rendering in Chrome
- HTML5 Rocks - Accelerated Rendering in Chrome