Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CSS animation scale transform starts blurry in Firefox

(Note: This was asked [exactly] 1½ years ago and had [exactly] zero activity... I'm apparently having the same issue so hopefully OP @Jaffa won't mind me piggybacking in it, and slapping a bounty on it to [hopefully] generate some interest!)

The OP's original question is below, and my added issue & examples is below that.


 
[Original Question:]
I am trying to animate a zoom out effect on an SVG. I have gotten it working, but the first frame, which is scaled to 30, is blurry/pixelated in Firefox.

Firefox: Chrome:

I do not see the same issue in Chrome or Edge. The initial frame is crisp as I would expect being an SVG.

html,
body {
  margin: 0px;
  padding: 0px;
}
.wrapper {
  padding: 50px 50px;
  max-width: 1200px;
  margin-left: auto;
  margin-right: auto;
  margin-top: 80px;
}
.img_zoom {
  width: 400px;
  height: 500px;
  margin: 2em auto 2em auto;
  overflow: hidden;
}
.zoom {
  width: 100%;
  height: 100%;
  background-position: center;
  background-size: cover;
  animation: zoom 5s ease-in-out 4s 1 normal forwards;
  transform: translate(3400px, -3600px) scale(30);
}
@keyframes zoom {
  to {
    margin-left: 0;
    transform: translate(0px, 0px) scale(0.7);
  }
}
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <div class="wrapper">
    <div class="img_zoom">
      <div class="zoom"><img src="https://flexion.tech/images/box-con.svg"></div>
    </div>
  </div>
</body>
</html>

Code pen is here for review:

https://codepen.io/jaffa80/pen/KKpxgeQ

Any ideas how I can fix the blurry issue in Firefox?

Another problem i am having is if I remove margin-left:0 from the @keyframe to, things stop working. Any pointers on this would be appreciated also.

 


EDIT:

I have a rounded div container containing several elements to position text within the circle. I need the circle to "grow" when the user gets to it, so I figured I'd use transform:scale() with a transition or animation.

However, only in Firefox, the text is blurry until the transition (or animation) is complete. Oddly, the border of the circle remains perfectly sharp (I think?).

Thinking maybe it needed a moment to pre-render, I've tried delaying with setTimeout alone, as well as combining with events (open & DOMContentLoaded) and with requestAnimationFrame. I also tried using css animation instead of transition.

Nothing seems to make a difference in Firefox, yet Chrome and Edge seem fine. Is there a prefix that I don't know about, or is this maybe a rendering bug in Firefox?

My MCSE is the snippet below:

setTimeout(function(){ 
  circ.classList.remove('shrunk');
},500);
body{ font-family:'fira code'; font-size:20px; }
#circ{ position:relative; border:3px solid blue; border-radius:50%; text-align:center; white-space: nowrap; transition:transform 1000ms; }
#circ span{ position:absolute; left:50%; top:50%; transform:translate(-50%,-50%); }
.shrunk{ transform:scale(0.1); }
<div class='shrunk' id='circ' style='width:336px; height:336px;'>
  <span>Lorem<br>Ipsum is simply<br>dummy text of the<br>printing and typesetting<br>industry. Lorem Ipsum has<br>been the industry's<br>standard dummy text ever<br>since the 1500s, when an<br>unknown printer took a<br>galley of type and<br>scrambled it to make<br>a type specimen<br>book.</span>
</div>

Any suggestions or workarounds?

like image 909
jaffa Avatar asked Mar 22 '20 05:03

jaffa


People also ask

Why is my image blurry when I resize it using CSS?

The issue happens when you resize images using CSS. Here are 3 methods with CSS Code to Fix blurry image that display image quality in a better way: By default, browsers try to apply aliasing to this scaled image so that there is no distortion, but it makes picture blurry sometimes.

What are CSS transformations?

1. Introducing CSS Transformations The effect of a CSS Transform is to modify the appearance of an element in the browser by translation, rotation or other means. When defined in a style sheet, transformations are applied as the page is rendered, so you don't actually see any animations taking place.

How do I know if an animation has transitions in CSS?

If the animation used CSS transitions, there is one bar for each property transitioned, and it is labeled with the name of the property being transitioned. If the animation used CSS @keyframes, there is one bar for each animation, labeled with its name.

How do I know if an animation has delay in CSS?

If the animation used CSS @keyframes, there is one bar for each animation, labeled with its name. If the animation or transition had a delay, this is shown as a cross-hatched portion of the bar. delay and endDelay are both represented.


2 Answers

I can only guess why this happens. Firefox is taking a snapshot before starting the animation / transition (by adding the class to the tag) and then when the transition ends. Maybe Firefox is taking more than two snapshots. But as you can see in the snippet below, the animation label is still blurred and waiting for when the animation is finished; the blur then disappears immediately. I think Firefox does this optimization for better performance.

The CSS property will-change also does not solve this problem if reset to initial .

setTimeout(function() {
  circ.classList.add('shrunk');
}, 2000);
body {
  display: flex;
  flex-flow: column;
  font-family: 'fira code';
  gap: 2rem;
}

.circles,
.titles {
  width: 100%;
  display: flex;
  gap: 2rem;
}

h4 {
  width: 105px;
  font-size: 0.8rem;
}

#circ,
#circ2,
#circ3,
#circ4 {
  width: 100px;
  height: 100px;
  position: relative;
  border: 3px solid blue;
  border-radius: 50%;
  text-align: center;
  word-break: break-all;
}

#circ {
  transition: transform 1000ms;
  transform: scale(0.1);
}

#circ2 {
  animation: forwardAnim 5s linear forwards;
}

#circ3 {
  animation: forwardAnim 5s linear forwards;
  backface-visibility: hidden;
}

#circ4 {
  animation: forwardAnim 5s linear forwards;
  transform-style: preserve-3d;
}

#circ span,
#circ2 span,
#circ3 span,
#circ4 span {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}

#circ.shrunk {
  transform: scale(1);
}

@keyframes forwardAnim {
  0% {
    transform: scale(0.1);
  }
  45% {
    transform: scale(0.1);
  }
  50% {
    transform: scale(1);
  }
  100% {
    transform: scale(1);
  }
}
<div class="circles">
  <div id="circ">
    <span>This is my text!</span>
  </div>
  <div id="circ2">
    <span>This is my text!</span>
  </div>

  <div id="circ3">
    <span>This is my text!</span>
  </div>
  <div id="circ4">
    <span>This is my text!</span>
  </div>
</div>
<div class="titles">
  <h4>Add class with transition</h4>
  <h4>Animation</h4>
  <h4>Animation with backface-visibility: hidden</h4>
  <h4>Animation with transform-style: preserve-3d</h4>
</div>

To avoid this you could use backface-visibility: hidden;as @nullptr mentions above, or transform-style: preserve-3d;* for a smoother transition.

setTimeout(function() {
  circ.classList.remove('shrunk');
}, 500);
setTimeout(function() {
  circ2.classList.remove('shrunk');
}, 500);
body {
  display: flex;
  flex-flow: column;
  font-family: 'fira code';
  gap: 2rem;
  font-size: 0.9rem;
}

.circles,
.titles {
  width: 100%;
  display: flex;
  gap: 2rem;
}

h4 {
  width: 255px;
  font-size: 0.8rem;
  text-align: center;
}

#circ,
#circ2 {
  width: 250px;
  height: 250px;
  position: relative;
  border: 3px solid blue;
  border-radius: 50%;
  text-align: center;
  white-space: nowrap;
  transition: transform 1000ms;
}

#circ {
  backface-visibility: hidden;
}

#circ2 {
  transform-style: preserve-3d;
}

#circ span,
#circ2 span {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}

.shrunk {
  transform: scale(0.1);
}
<div class="circles">
  <div class="shrunk" id="circ">
    <span>Lorem<br />Ipsum is simply<br />dummy text of the<br />printing and
          typesetting<br />industry. Lorem Ipsum has<br />been the industry's<br />standard
          dummy text ever<br />since the 1500s, when an<br />unknown printer
          took a<br />galley of type and<br />scrambled it to make<br />a type
          specimen<br />book.</span
        >
      </div>
      <div class="shrunk" id="circ2">
        <span
          >Lorem<br />Ipsum is simply<br />dummy text of the<br />printing and
          typesetting<br />industry. Lorem Ipsum has<br />been the industry's<br />standard
          dummy text ever<br />since the 1500s, when an<br />unknown printer
          took a<br />galley of type and<br />scrambled it to make<br />a type
          specimen<br />book.</span
        >
      </div>
    </div>
    <div class="titles">
      <h4>backface-visibility: hidden;</h4>
      <h4>transform-style: preserve-3d;</h4>
    </div>

Another way to avoid blurred content inside the circle is to remove position: absolute if it's not critical, and instead align content with display: flex on the parent element.

setTimeout(function() {
  circ.classList.remove('shrunk');
}, 500);
body {
  font-family: 'fira code';
  font-size: 20px;
}

#circ {
  display: flex;
  justify-content: center;
  align-items: center;
  position: relative;
  border: 3px solid blue;
  border-radius: 50%;
  text-align: center;
  white-space: nowrap;
  transition: transform 1000ms;
}

.shrunk {
  transform: scale(0.1);
}
<div class="shrunk" id="circ" style="width: 336px; height: 336px">
  <span>Lorem<br />Ipsum is simply<br />dummy text of the<br />printing and
        typesetting<br />industry. Lorem Ipsum has<br />been the industry's<br />standard
        dummy text ever<br />since the 1500s, when an<br />unknown printer took
        a<br />galley of type and<br />scrambled it to make<br />a type
        specimen<br />book.</span
      >
    </div>
like image 91
Anton Avatar answered Oct 23 '22 03:10

Anton


I ran into this issue a few years back, although I think I had it on chrome and not Firefox. But this seems to solve the issue in Firefox too.

Add backface-visibility: hidden to your transforming component. This will make it so that only the front face of the element is animated, instead of both the front and the back faces.

setTimeout(function(){ 
  circ.classList.remove('shrunk');
},500);
body{ font-family:'fira code'; font-size:20px; }
#circ{ position:relative; border:3px solid blue; border-radius:50%; text-align:center; white-space: nowrap; transition:transform 1000ms; backface-visibility: hidden; }
#circ span{ position:absolute; left:50%; top:50%; transform:translate(-50%,-50%); }
.shrunk{ transform:scale(0.1); }
<div class='shrunk' id='circ' style='width:336px; height:336px;'>
  <span>Lorem<br>Ipsum is simply<br>dummy text of the<br>printing and typesetting<br>industry. Lorem Ipsum has<br>been the industry's<br>standard dummy text ever<br>since the 1500s, when an<br>unknown printer took a<br>galley of type and<br>scrambled it to make<br>a type specimen<br>book.</span>
</div>

As to why it works, I really have no idea. But do try it and let me know it if works for you.

like image 39
nullptr Avatar answered Oct 23 '22 03:10

nullptr