Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SVG in img tag sizing inconsistent, movement seems like dancing

Background

I am developing a PhoneGap/Cordova app that should run on iOS and Android devices, and uses SVG images embedded as <img/> tags, using HTML attributes width="" and height="" to set their dimensions, and style="left: ...px; top: ...px; zoom: ...;" to set their relative position, with a zoom coefficient that is uniform between multiple image objects.

My problem is that when zooming in and out, the images are rendered with different sizes, both in Safari and in Chrome. This can also be seen in the desktop versions of these browsers, and I think I can narrow it down to a rounding issue with respect to the left and top CSS property. The problem is aggravated when using fractional values for the zoom CSS property, and the width and height HTML attributes.

I have created a demo here and a downloadable version here. In this demo, I have used two SVG images, identical except for their fill color, which I use for color contrast. There are three pairs in the demo: the top-most uses a fractional zoom value, the middle uses fractional width and height values, and the last uses round multiples of the width and height values. There is a button that starts an animations that simply moves all images to the right, by a single pixel in each step. It'll be easy to notice in Chrome that the middle images jiggle substantially, while a little harder to notice changes in the other two - but they are also there. I'm using Windows 10 and Chrome 65.0 -- though I can see variations of the problem in Firefox and Edge as well (though -- they are rendered differently).

Here is an animation of the demo. Note that all I am changing between frames is the left position of all images - and doing so in a uniform manner.

dancing SVGs demo

Actual question

For my application, the images must have consistent rendering across zoom levels and in different positions on the page. When changing the zoom, left and top properties smoothly, the images should change dimensions and position smoothly, respectfully. They should not change dimensions when changing the left and top properties. Is there a method that ensures that when multiple images use the same (possibly fractional) width and height values, but varying left and top positions, they will be rendered identically? Is there a way to ensure that smooth transition of the zoom property results in smooth rendering?

Guidelines for an answer

A proper answer would either explain why this is not possible using current browsers, pointing to a confirmed bug report that describes this problem and shows that it affects popular devices in either platform; or present an alternative way to size and position the images, while retaining the possibility to use fractional values, and that obtains uniformity and smooth zoom transitions when all images use the same dimensions.

Thanks for any help you may offer!

like image 366
Yuval Avatar asked Apr 16 '18 07:04

Yuval


1 Answers

I think it's because the zoom property support is not quite consistent between the browsers (as you can see here https://caniuse.com/#feat=css-zoom). Try rather the transform: scale() property:

function budgeRight() {
   var imgs = document.querySelectorAll('img');
   imgs = Array.prototype.slice.apply(imgs);
   imgs.forEach(function(img) { 
      var left = parseInt(img.style.left);
      
      img.style.left = (left + 1).toString() + "px"; 
    });
}

var interval = null;
var button = document.getElementById('button-click-me');

button.addEventListener('click', function() {
  if (interval) {
    clearInterval(interval);
    interval = null;
  }
  else {
    interval = setInterval(budgeRight, 500);
  }
});
img { position: absolute; }
body { background-color: #000; }
<img style="-webkit-transform: scale(2.3); -moz-transform: scale(2.3); -ms-transform: scale(2.3); -o-transform: scale(2.3); transform: scale(2.3); -webkit-transform-origin: top left; -moz-transform-origin: top left; -ms-transform-origin: top left; -o-transform-origin: top left; transform-origin: top left; left: 41px; top: 25px;" src="https://gist.githubusercontent.com/kwikwag/74b991206c5fd197c70a6ec2c02fd238/raw/3f4070dbb97c69f716ad6b32ca5f6abd1f4fd702/rect_white.svg?sanitize=true">
<img style="-webkit-transform: scale(2.3); -moz-transform: scale(2.3); -ms-transform: scale(2.3); -o-transform: scale(2.3); transform: scale(2.3); -webkit-transform-origin: top left; -moz-transform-origin: top left; -ms-transform-origin: top left; -o-transform-origin: top left; transform-origin: top left; left: 40px; top: 25px;" src="https://gist.githubusercontent.com/kwikwag/74b991206c5fd197c70a6ec2c02fd238/raw/3f4070dbb97c69f716ad6b32ca5f6abd1f4fd702/rect_red.svg?sanitize=true">
<img style="-webkit-transform: scale(2.3); -moz-transform: scale(2.3); -ms-transform: scale(2.3); -o-transform: scale(2.3); transform: scale(2.3); -webkit-transform-origin: top left; -moz-transform-origin: top left; -ms-transform-origin: top left; -o-transform-origin: top left; transform-origin: top left; left: 31px; top: 35px;" width="9.35" height="23.35" src="https://gist.githubusercontent.com/kwikwag/74b991206c5fd197c70a6ec2c02fd238/raw/3f4070dbb97c69f716ad6b32ca5f6abd1f4fd702/rect_red.svg?sanitize=true">
<img style="-webkit-transform: scale(2.3); -moz-transform: scale(2.3); -ms-transform: scale(2.3); -o-transform: scale(2.3); transform: scale(2.3); -webkit-transform-origin: top left; -moz-transform-origin: top left; -ms-transform-origin: top left; -o-transform-origin: top left; transform-origin: top left; left: 32px; top: 35px;" width="9.35" height="23.35" src="https://gist.githubusercontent.com/kwikwag/74b991206c5fd197c70a6ec2c02fd238/raw/3f4070dbb97c69f716ad6b32ca5f6abd1f4fd702/rect_white.svg?sanitize=true">
<img style="left: 91px; top: 130px;" width="18" height="42" src="https://gist.githubusercontent.com/kwikwag/74b991206c5fd197c70a6ec2c02fd238/raw/3f4070dbb97c69f716ad6b32ca5f6abd1f4fd702/rect_red.svg?sanitize=true">
<img style="left: 94px; top: 130px;" width="18" height="42" src="https://gist.githubusercontent.com/kwikwag/74b991206c5fd197c70a6ec2c02fd238/raw/3f4070dbb97c69f716ad6b32ca5f6abd1f4fd702/rect_white.svg?sanitize=true">
<button id="button-click-me">Click me</button>

Notice I added transform-origin: top left, to scale each image from its top left corner. And I also used all the vendor-prefixes -webkit-, -moz-, etc. to have a maximum compatibility on these 2 properties...

like image 78
Valentin Avatar answered Nov 15 '22 04:11

Valentin