Ticket #2529799 (accepted defect)

Reporter


Richard Jones
Opened: 01/8/11
Last modified: 09/19/12
Status: accepted
Type: defect

Owner


Matt Sweeney
Target Release: BACKLOG
Priority: P3 (normal)
Summary: workaround webkit computedStyle left/top for percent units
Description:

When trying to animate :
var anim = new Y.Anim({
node: '#box',
to: { left:"15%", top:"15%" }
});

The %'s are incorrectly converted to pixels and then back to percentages so when "#box" is inside a 300px square container and starts at left:50%,
top:50% the start position (from) of the animation is started at left:150% top:150%, leading to the animated entity to jump dramatically to the bottom right at the start of the animation. This
incorrect conversion only occurs on Firefox (tested only on 3.6 Mac) and latest Opera, it does not happen on Webkit based browsers.

Bug tested in both 3.2.0 and 3.3.0pr3.

Type: defect Observed in Version: 3.2.0
Component: Dom Severity: S2 (high)
Assigned To: Matt Sweeney Target Release: BACKLOG
Location: Library Code Priority: P3 (normal)
Tags: animation, percentages, relative positioning Relates To:
Browsers: Firefox 3.x - Mac,Opera
URL:
Test Information:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>Animation bug with left/top animations</title>

<link type="text/css" rel="stylesheet" href="http://yui.yahooapis.com/3.2.0/build/cssfonts/fonts-min.css" />
<script type="text/javascript" src="http://yui.yahooapis.com/3.2.0/build/yui/yui-min.js"></script>

</head>

<body class="yui3-skin-sam yui-skin-sam">

<h1>Animation bug with left/top animations</h1>

<div class="exampleIntro">

<p> Click on start anim button under firefox on the mac (only platform tested on) to see aniation fly in from
outside the containing box. It appears the percentage start position in percentage is used to find the pixel
start position which is then converted back to a percentage incorrectly i.e. 50% of 300px is 150px which
is then converted to 150% as the start position for the animation. The same code under Safari and Chrome
works fine.
</p>

</div>

<!--BEGIN SOURCE CODE FOR EXAMPLE =============================== -->

<button id="startAnim">Start Anim</button>
<div id="container" style="border:1px solid black;position:relative;width:300px;height:300px;">
<div id="box" style="border:1px solid black;position:absolute;width:12.5%;left:50%;top:50%">TEST</div>
</div>

<script type="text/javascript">

YUI().use("anim","console", function(Y) {

new Y.Console().render();

var anim = new Y.Anim({
node: '#box',
to: { left:"15%", top:"15%" }
});

anim.on('tween',function(e)
{

Y.log("box left:"+Y.one("#box").getStyle("left")+" top:"+Y.one("#box").getStyle("top"));
});

var onClick = function(e) {

e.preventDefault();
anim.run();
};

Y.one('#startAnim').on('click', onClick);

});

</script>
</body>
</html>

Change History

Matt Sweeney

YUI Developer

Posted: 01/10/11
  • priority changed to P3 (normal)
  • resolution changed to wontfix
  • status changed from new to closed

You will have to provide "from" values for units other than pixels due to the native getComputedStyle always normalizing to pixels.

Richard Jones

  • Username: jonesr
Posted: 01/10/11
  • resolution changed from wontfix
  • status changed from closed to reopened

The bug here seems to be that you are coercing the from values into percentages even though you know they come out of a getComputedStyle call and are going to be be pixels (n some browsers). It seems wekbit is non-standard here and is returning 'computed values' instead of 'used values' as defined by CSS 2.1 (CSS 2.0 defined this to return computed values as discussed here:
https://developer.mozilla.org/en/CSS/used_value
)

Shouldn't this be something developers using the library are protected against? It would seem that when a from is not provided and the to is provided in percentages that the return value of getComputedStyle used to set the from values should avoid adding a "%" on browsers that implement getComputedStyle as per CSS 2.1. The bug here seems to be the animation code that is incorrectly putting a % on the end of a value it should know is a pixel value, at least on some platforms.

The code in question appears to be this (from anim.js inside the _initAnimAttr function):
unit = mTo ? mTo[2] : mFrom ? mFrom[2] : ''; // one might be zero TODO: mixed units

if (!unit && Y.Anim.RE_DEFAULT_UNIT.test(name)) {
unit = Y.Anim.DEFAULT_UNIT;
}

if (!begin || !end) {
Y.error('invalid "from" or "to" for "' + name + '"', 'Anim');
return;
}

attr[name] = {
from: begin,
to: end,
unit: unit
};

You have a TODO comment next to the unit mentioning mixed units, and in fact not doing so is what is breaking this code as the unit is getting set to percentage, and lacking a fromUnit and toUnit the code processing the final attr doesn't have much choice but to assume that the from should be interpreted in percentages , as that is the unit you end up placing here even though you know the code just before this:
begin = from[name];
if (begin === undefined) {
begin = (name in customAttr && 'get' in customAttr[name]) ?
customAttr[name].get(this, name) : Y.Anim.DEFAULT_GETTER(this, name);
} else if (typeof begin === 'function') {
begin = begin.call(this, node);
}

is going to return a value in pixels on properly CSS 2.1 compliant browsers.

It seems to me this IS fixable, although it might require implementing the TODO in that comment and supporting mixed units in this particular code path (although you could also convert the from back into a percentage on browsers you know are returning pixels here).

Matt Sweeney

YUI Developer

Posted: 01/11/11
  • component changed from Animation to Dom
  • location changed to Library Code
  • milestone changed to 3.4.0
  • owner changed from Matt Sweeney to Matt Sweeney
  • status changed from accepted to assigned
  • summary changed from Animation incorrectly normalises left and top start positions in animations using percentages on left and top, but only on Firefox and Opera. to workaround webkit computedStyle left/top for percent units

You are correct, webkit is returning the wrong value from getComputedStyle for top/left offset values:
https://bugs.webkit.org/show_bug.cgi?id=29084

Unfortunately, supporting mixed units is a non-starter, as this requires the ability to convert any (EM, EX, %, CM, etc.) unit to/from pixels. This means that the "from" value needs to be given in the same units as the "to" when animating to other than the computed unit.

I agree that we should workaround the webkit percent computedStyle bug and always return pixel values.

Richard Jones

  • Username: jonesr
Posted: 01/11/11

Hi Matt,

I can see allowing mixed units would be a problem given that some conversions are non-trivial. The percentage case in this situation could be handled without explicit mixed units support by converting (when 'to' is in % and from is undefned) the 'from' attribute back to a percentage instead of using the pixels returned by getComputedStyle instead of pretending the pixels are actually percentages, as is being done now, but I could understand if you see this as a little too ad-hoc to support, although it does remove what is likely to be a highly surprising failure case to developers when they first come across it. Rounding might be a counter argument to % conversions, but from positions in an animation probably don't have to pixel perfect in any case.

If you're not planning to make such a change (which I guess is justifiable given the difficulty in solving the general case), could I suggest updating this documentation:
http://developer.yahoo.com/yui/3/anim/

from :
"Setting a From Value

Use the optional from attribute to start the animation from a specific value. When from is omitted, the current value is used.",

to something which mentions some warning about from attributes not actually being optional when you are using a non-pixel unit in your 'to' attribute.

Normalising getComputedStyle for webkit so it returns pixels like the other CSS 2.1 compliant browsers will at least make the bug consistent and therefore more obvious across browsers :-)

It is a pity W3C hasn't provided a version of getComputedStyle that can do unit conversion which would make this type of thing a non-issue.

Richard Jones

  • Username: jonesr
Posted: 01/11/11

Just a follow up , I notice this library for jquery (fx 2.0) does support multi-units by using a hack which converts all non-pixel units:

http://ryanmorr.com/archives/fx-2-0-the-full-featured-animation-framework

(multi unit support described under "CSS Multi-Unit Support" heading).

They seem to use a hack where they normalise all non pixel values with this code (at least I assume that is what it is doing):

start = parseFloat(DOM.getStyle(this.el, attr)) || 0;
if(units != "px" && document.defaultView){
DOM.setStyle(this.el, attr, (end || 1) + units);
start = ((end || 1) / parseFloat(DOM.getStyle(this.el, attr))) * start;
DOM.setStyle(this.el, attr, start + units);
}

I'm not sure if you'd find this preferable over completely not working when the 'from' attribute is not provided on non-pixel values, which is what happens now, but again this does look a bit kludgy and setting the animation to the final position at the start, even if briefly might have annoying side effects, so I could also understand if you also found this type of thing unacceptable.

Matt Sweeney

YUI Developer

Posted: 01/11/11
  • status changed from assigned to accepted

Thanks for the followup. Yes, actually applying the style is the only reliable way to get the actual used value, however this can have unanticipated side-effects, so I've been hesitant to go down this path.

Richard Jones

  • Username: jonesr
Posted: 01/11/11

Yes, its definitely a kludge, but perhaps you could justify it if it was only applied when a non "px" unit is used with an undefined 'from' attribute, which you know is always going to break (except on webkit, where the fact that is succeeds is actually a bug anyway :-) ). But perhaps it is as you say, and people should just learn that they need to use 'from' attributes in non-'px' cases, which isn't too onerous once you realise it has to be done.

Matt Sweeney

YUI Developer

Posted: 04/28/11
  • milestone changed from 3.4.0 to 3.NEXT

Jenny Donnelly

YUI Developer

  • Username: jenny
  • GitHub: jenny
Posted: 09/19/12
  • milestone changed from 3.NEXT to BACKLOG

Moving from 3.NEXT to BACKLOG.