Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does my Transform snap back?

Am trying to make my element stay in spot (after the transition). Right now, the translated location is where I want it but then my name snaps back onto the quote. Am I missing a piece of code or is there a piece of code that's making this snap back happen?

.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;
  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>
like image 892
Snorlax Avatar asked Aug 02 '15 03:08

Snorlax


1 Answers

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
like image 121
Harry Avatar answered Oct 02 '22 23:10

Harry