1

I am trying to achieve a zoom animation on elements with a border-radius but it ends with an aliased render on webkit.

HTML :

<ul>
    <li style="transform: rotate(0deg) translateY(-35vh);">
        <span></span>
    </li>
    <li style="transform: rotate(20deg) translateY(-35vh);">
        <span></span>
    </li>
<ul>

CSS :

li{
    position: absolute;
    top: 50%;
    left: 50%;
    width: 5px;
    height: 5px;
    list-style: none;
    border-radius: 50%;
    backgroud-color: red;
    -webkit-backface-visibility: hidden;
}

span{
    display: block;
    width: 100%;
    height: 100%;
    border-radius: 50%;
    background-color: black;
}

li span.scaleup{
    animation: scaleup 2s 1;
}

@keyframes scaleup{
    10%{
        transform: scale(12);
    }
    100%{ 
        transform: scale(1);
    }
}

Not sure if i'm doing this wrong or if it's a webkit bug.

Here is my code : http://codepen.io/pixelpirate/pen/gpqpQV

  • btw, are you using Chrome (i.e. Blink rather than Webkit)? Safari doesn't like the `style="transform...` attributes - autoprefixer is fixing it in the CSS, but not in the `style` attributes. Had me puzzled for a minute :) – CupawnTae Aug 04 '15 at 20:23
  • Yep I am using Chrome ! I was not aware that Chrome switched to the Blink engine. – pixelpirate Aug 04 '15 at 20:58

1 Answers1

0

What's happening is the browser is rendering at the very small size, and then handing it as a bitmap to hardware compositing to do the scaling. So you're scaling up the 5px version, and hence the effect you're seeing.

You can solve this by doing it the other way around - begin by rendering at the large size...

li{
    width: 60px;
    height: 60px;

and scaling down...

  <li style="transform: rotate(0deg) translateY(-35vh) scale(calc(1/12));">
    <span></span>
  </li>
  <li style="transform: rotate(20deg) translateY(-35vh) scale(calc(1/12));">
    <span></span>
  </li>

Here's the entire code - you can run it inline by clicking "Run code snippet" below. Updated codepen: http://codepen.io/anon/pen/bdzEEv

$('button').click(function(){
  
    $('span').addClass('scaleup').bind('animationend webkitAnimationEnd MSAnimationEnd oAnimationEnd', function (e){
     $(this).removeClass();
 });
});
body{
  background: white;
}
button{
  margin: 40px auto;
  display: block;
  width: 150px;
  height: 35px;
}
ul{
  position: relative;
  border-radius: 50%;
  width: 70vh;
  height: 70vh;
  margin-top: 15vh;
  margin-left: calc(50vw - (70vh)/2);
  padding: 0;
}

li{
    position: absolute;
    top: 50%;
    left: 50%;
    width: 60px;
    height: 60px;
    border-radius: 50%;
    background-color: red;
    list-style: none;
    -webkit-backface-visibility: hidden;
}
span{
    display: block;
    width: 100%;
    height: 100%;
    border-radius: 50%;
    background-color: black;
}
li span.scaleup{
 animation: scaleup 2s 1;
}

@keyframes scaleup{
  10%{
   transform: scale(12);
  }
  100%{ 
   transform: scale(1);
  }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>Toggle</button>
<ul>
  <li style="transform: rotate(0deg) translateY(-35vh) scale(calc(1/12));">
    <span></span>
  </li>
  <li style="transform: rotate(20deg) translateY(-35vh) scale(calc(1/12));">
    <span></span>
  </li>
<ul>
CupawnTae
  • 14,192
  • 3
  • 29
  • 60
  • Works like a charm but it looks quite resource-intensive on a larger scale. Do you know if there is a way to force Webkit to render it right ? I have tried to enable hardware acceleration by applying a 3D-transforms or box-shadows as suggested in this post : http://stackoverflow.com/a/17822836/5190999 but it doesn't seems to have any effect. – pixelpirate Aug 04 '15 at 20:47
  • you *are* using hardware acceleration - that's why you get the pixellated effect - it hands off to the hardware to do the scaling, but the hardware has no idea this set of 5x5 pixels is supposed to be a circle. If you turned off hardware acceleration and tried your original code, it might actually render correctly, but instead of using hardware to scale the image, it would have to redraw the "circle" every frame, which would be _far more_ CPU intensive. Bottom line is if you want a circle to look smooth at the largest size you're going to display it, you'll need to render it that size... – CupawnTae Aug 04 '15 at 21:30
  • ...at some point, so might as well do that from the start, and scale down the image when you want it small instead of the other way around. Out of curiosity, when you say it looks quite resource-intensive on a larger scale, how are you measuring that, and what are you observing? – CupawnTae Aug 04 '15 at 21:32
  • Thanks a lot for the explanations :) I mainly use firefox which is more capricious than Chrome regarding animations. The size of the elements seems to have an influence on my performance and causes slowdowns when displayed. I have a large number of them (~300) and the impact is even more important. – pixelpirate Aug 04 '15 at 23:47
  • I'm surprised 300 of these things would hurt performance much. The big hit usually comes if you cause a page reflow by changing the DOM or CSS in a way that the browser has to recalculate everything using the CPU. Or if you're not handing off to the 3d hardware - haven't looked at cross-browser behaviour in a while, but in the past on some browsers, using e.g. `translate3d(0,y,0)` instead of `translateY(y)` would make the difference. You could try that, and adding `translate3d(0,0,0)` to the scale-only transforms just in case - i.e. make sure every `transform` value has *some* `translate3d` – CupawnTae Aug 05 '15 at 08:44