Johann Ulbrich
Johann Ulbrich

Reputation: 634

Why CSS transition lags in mobile Chrome?

During my work on a CSS image zooming feature I encountered a performance problem in mobile Chrome.

Description: If I try to scale images by adding the CSS transform property directly to the image everything works well. The zooming transition is smooth like butter with 60fps (JSFiddle).

<img src="http://placehold.it/1000x1500" style="transform:matrix(2, 0, 0, 2, 0, 0);" />

The Problem: But if I wrap the image in a div container and try to transform the container the transition is very laggy (JSFiddle). The transition starts with a big delay and isn't smooth. It seems to be a mobile Chrome only problem because it doesn't happen in other browsers like Firefox on Android, just on my mobile device (Nexus 5) and some other Android devices.

<div style="transform:matrix(2, 0, 0, 2, 0, 0);">
    <img src="http://placehold.it/1000x1500" />
</div>

Does someone know whats wrong with the CSS or HTML structure?

Upvotes: 7

Views: 9774

Answers (4)

jacefarm
jacefarm

Reputation: 7461

Use JavaScript to set classnames, but let CSS completely handle the transitions and trigger GPU acceleration.

I would suggest using the onclick HTML event attribute, to set triggers for two functions, zoomIn and zoomOut.

HTML

    <div id="zoom-container">
      <img src="http://placehold.it/1000x1500" />
    </div>

    <div id="zoom-toolbar">
      <button id="zoom-in" onclick="zoomIn()">Zoom in</button>
      <button id="zoom-out" onclick="zoomOut()">Zoom out</button>
    </div>

You now have two functions, that set desired CSS classnames.

JavaScript

    function zoomIn() {
      var element = document.getElementById("zoom-container");
      element.className = 'zoomed-in';
    };

    function zoomOut() {
      var element = document.getElementById("zoom-container");
      element.className = 'zoomed-out';
    };

To achieve the desired animation, the CSS can now be much simpler as well.

CSS

    #zoom-toolbar {
      position: absolute;
      top: 0;
    }

    #zoom-container.zoomed-out {
      transition: transform 0.3s ease-in-out;
      transform: matrix(0.2, 0, 0, 0.2, 0, 0);
    }

    #zoom-container.zoomed-in {
      transition: transform 0.3s ease-in-out;
      transform: matrix(2, 0, 0, 2, 0, 0);
    }

From there, you can introduce additional CSS and test whether subsequent changes are breaking.

I've created a CodePen example to demonstrate.

A good article on smooth CSS transitions is here.

Upvotes: 1

Jordi Flores
Jordi Flores

Reputation: 2150

Greensock plugin is by far the best in terms of performance I've seen. Some time ago I make a deep study and some tests, and it's been by far, one of the best plugins to animate elements.

It's lightweight, fast and easy to use.

What about performance? Take a look on your own: https://www.greensock.com/js/speed.html

Here's your example using gsap library:

var content = document.getElementById('zoom-container').children[0];

document.getElementById('zoom-in').addEventListener('click',
  function zoomIn() {
  TweenLite.to(content, 1.5, {scale:1});
  }, false);

document.getElementById('zoom-out').addEventListener('click',
  function zoomOut() {
  	TweenLite.to(content, 1.5, {scale:0.2});
  }, false);
* {
  margin: 0;
  padding: 0;
}

img {
  display: inline-block;
}

html,
body {
  height: 100%;
  width: 100%;
}
#zoom-container div {
  position: relative;
  /*some prefix*/-transform-origin: 0 0;
  transform-origin: 0 0;
}
#zoom-toolbar {
  position: absolute;
  top: 0;
  left: 0;
  
}

.zommIn {
  
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.19.0/TweenMax.min.js"></script>

  <div id="zoom-container" style="height:100%; width:100%;">
    <div>
      <img src="http://placehold.it/1000x1500" />
    </div>
  </div>

  <div id="zoom-toolbar">
    <button id="zoom-in">Zoom in</button>
    <button id="zoom-out">Zoom out</button>
  </div>

Upvotes: 1

Red Mercury
Red Mercury

Reputation: 4330

You can

  • try to put will-change: transform on the container element.
  • Make the container element position: relative and the image position: absoulte and fill the container completely. Might involve less calculations each frame for the browser.

Upvotes: 0

NathanielSantley
NathanielSantley

Reputation: 293

I tried out your code in chrome and the transformations were definitely lagging. Yes there is a problem with your code and frankly it's pretty simple. Simply write the transition again after the first transition, but add the prefix -webkit- to the start of it.

Please note that -webkit- only works for Android, Google, and Safari.
-moz- works for Mozilla Firefox.
-o- works for Opera.
-ms- works for Internet Explorer

Upvotes: 0

Related Questions