..............................................................Interface Design & Development
Alternatively, you can download the iUI 0.30 release:
http://iui.googlecode.com/files/iui-0.30.tar.gz
The link I previously gave is work in progress for the 0.40 release
which will have iui.animOn = true by default and is currently in an
inconsistent state.
-- Sean
Hi,
I've modified my old, hyper-forked copy of iui.js to use transitions
using the "left" property just to find out that it works fine in the
desktiop Safaris but not at all on the iPhones. I wrote this little
code snippet in order to be able to tell at runtime whether "left" is
"transitionable" or not :
var hayCSSAnimado= (function () {
var e= document.body.appendChild(document.createElement('div'));
var es= e.style;
function callback () {
hayCSSAnimado= (e.offsetLeft === 10);
//console.log("Callback: hayCSSAnimado: "+ hayCSSAnimado);
e.removeEventListener( 'webkitTransitionEnd', callback, false);
}
es.position= "absolute";
es.left= "0px";
//fuerza posicion OK
var kk= e.offsetLeft;
es["-webkit-transition"]= "left 100ms";
e.addEventListener( 'webkitTransitionEnd', callback, false);
es.left= "10px";
setTimeout(function () {
e.parentNode.removeChild(e);
//console.log("Timeout: hayCSSAnimado: "+ hayCSSAnimado);
}, 333 /* plenty of time as the transition should take ~100ms */ );
return false;
})();
I've seen that your code infers it from the presence of (typeof
WebKitCSSMatrix == "object"), but that won't tell you about the
"transitionability" of a certain property in particular.
Where's a doc telling exactly what properties can be animated on the
iPhone ?
Thanks,
--Jorge
> I've modified my old, hyper-forked copy of iui.js to use transitions
> using the "left" property just to find out that it works fine in the
> desktiop Safaris but not at all on the iPhones. I wrote this little
> code snippet in order to be able to tell at runtime whether "left" is
> "transitionable" or not :
>
> var hayCSSAnimado= (function () {
> var e= document.body.appendChild(document.createElement('div'));
> var es= e.style;
>
> function callback () {
> hayCSSAnimado= (e.offsetLeft === 10);
> //console.log("Callback: hayCSSAnimado: "+ hayCSSAnimado);
> e.removeEventListener( 'webkitTransitionEnd', callback, false);
> }
>
> es.position= "absolute";
> es.left= "0px";
> //fuerza posicion OK
> var kk= e.offsetLeft;
> es["-webkit-transition"]= "left 100ms";
> e.addEventListener( 'webkitTransitionEnd', callback, false);
> es.left= "10px";
Code like this won't trigger transitions for any property. The reason
for this is that
the browser batches style changes made in the same JavaScript cycle,
so the
es.left = "10px" simply overrides the earlier es.left = "0px".
To make a transition happen here, you need to assign the final style
in a setTimeout:
style.left = "0px"
style.webkitTransition = "left 100ms";
window.setTimeout(function() {
style.left = "100px";
}, 0);
Simon
>
>> Where's a doc telling exactly what properties can be animated on the
>> iPhone ?
>
> Jorge, here is a link to the SafariCSSRef.pdf
>
> http://developer.apple.com/mac/library/documentation/AppleApplications/Reference/SafariCSSRef/SafariCSSRef.pdf
>
> It tells what can be animated and what is supported on the iPhone. I
Linda,
Thanks, I've got this one already :-) the problem is that it does tell
that -webkit-transition is available on the iPhones with OS >= 2.0 but
does not specify which -webkit-transition-property(s) are animable :-
( and e.g. "left" seems to be non-animable (or I'm doing it wrong ?)
> just am not a CSS/JavaScript guru but I am intrigued by the new
> animations that are possible. Something like making it look like you
> are turning a page or sliding one page on top of another or the
> "normal" for the iPhone of sliding panels. Rather than having a
> library like jQuery or even iUI (I know that it is small), I want to
> actually LEARN what is going on and experiment myself with the
> possibilities.
>
> Same with Dashcode on an earlier post of mine. I want to learn how to
> use the tool and to interact with others that are using the same
> tool. Sure, I may decide as others have to use something else. So,
> rather than an recommendation to use something else, I wanted to
> converse with someone else that might be using the same tool.
>
> So, I am going to start some experiments today with CSS3 on the iPhone
> and see what I can come up with.
>
> Thanks.
> Linda
"me too": I've been playing a bit with 3d-rotations, see:
http://jorgechamorro.com/cljs/079/
They're lovely :-)
Cheers,
--
Jorge.
Simon,
My intention was that var kk= e.offsetLeft; would force the initial
non-animated move to left=0px. Note that that code does work fine, at
least in desktop Safari. May be the things are a bit different on the
iPhone, I'll give it a try, for sure. Thanks !
--
Jorge.
Another hyper-forked copy of iui.js, eh? One of the major goals of
version 0.40 is to reduce the need to fork your iui.js.
> to use transitions
> using the "left" property just to find out that it works fine in the
> desktiop Safaris but not at all on the iPhones.
I wish I had $1 for every hour that I and other developers have spent
trying to make transitions work with the left property. :(
> I wrote this little
> code snippet in order to be able to tell at runtime whether "left" is
> "transitionable" or not :
>
>
>
A duck test! Cool!
> I've seen that your code infers it from the presence of (typeof
> WebKitCSSMatrix == "object"), but that won't tell you about the
> "transitionability" of a certain property in particular.
>
True. This test isn't ideal, but it is lightweight and results in the
correct behavior.
> Where's a doc telling exactly what properties can be animated on the
> iPhone ?
>
I think that answer's been provided on this thread. If not, I'll look
for a link after reading the rest of the thread.
-- Sean
> FWIW: You'll want to use -webkit-transform: translate() — or even
> translate3d() — instead of left. It'll come out smoother-
>
> Best,
>
> Dave
I saw Sean is using translateX(%) in iui.js., I'll give it a try.
Thanks !
But, btw, any guess about why is it smoother than "left" ?
--
Jorge.
iUI is a great way to LEARN! iui.js is small and it directly uses the
native JavaScript of the iPhone (i.e. no intermediate libraries) so it
is a great way to learn.
-- Sean
Been there, done that, and it works. Thanks Simon !
Now let's see if translate-X is smoother indeed... :-)
--
Jorge.
Thanks, Simon. I wish I had a dollar for every hour I spent figuring
this out. ;) (I might be able to buy myself a hamburger.)
You can see this behavior in iui.js version 0.30 in the slide2()
function, the line:
setTimeout(startTrans, 0);
was necessary to allow the browser to apply the previous changes
necessary to setup the transition.
iui.js would be an even better learning tool if it had comments :(
(Release 0.50?)
Is this documented somewhere? It would be cool if there were a way to
"flush' these operations without using setTimeout.
-- Sean
> Not sure explicit reason it's smoother, but Apple has noted (forget
> the link) that a certain bug makes also makes translate3d faster and
> more reliable than translate() or translateX() — just pass 0s for
> the other options:
> translate3d(newx, 0,0);
>
> Best,
>
> Dave
Now that I've got it working with "left", it's still a bit clunky.
I'll give it a try with translate3d. Thanks !
--
Jorge.
Actually you are right. The 'offsetLeft' forces the browser to do a
layout
pass, and so ends the style change batch.
This code should work. One reason you might not be seeing an transition
is that animating 'left' forces the browser to do a layout, and
painting,
for every frame, and this can be slow. As someone else suggested,
animating
-webkit-transform should be a lot smoother.
Simon
which can be
Because we did an enormous amount of work inside WebKit to be able
to map certain animations to the underlying compositing engine,
which means they are hardware-accelerated. We could do that for
"-webkit-transform", but not "left".
Here's the recommendation for what kinds of transforms to use:
If you using -webkit-transition with -webkit-transform, then go
ahead and use whatever transform makes the most sense (e.g.
translateX(), scale(), rotate() etc). If a transition or animation
on -webkit-transform is running, that gets hardware accelerated.
If you're changing -webkit-transition "by hand" from JavaScript and
want to achieve good performance (e.g. maybe you're responding to
touch events from the user, moving things around), then use one
of the 3d transform types: translate3d(), rotate3d() etc. Those
will be faster in this case.
Simon
> Simon, thanks so much for the direct input. Since you seem pretty
> authoritative on the subject, I'm also curious... Is there any
> performance or stability gain/loss in using animations vs transitions?
Transitions and keyframe animations use the same
code under the hood. Which you use depends on whether
you need the additional control that keyframe animations
give you (repeating behavior, alternating etc).
Simon
Is there a reason why the 3d types are faster in this case?
-- Sean
p.s. Your participation on this list is greatly appreciated!
>
> This code should work. One reason you might not be seeing an
> transition
> is that animating 'left' forces the browser to do a layout, and
> painting,
> for every frame, and this can be slow. As someone else suggested,
> animating
> -webkit-transform should be a lot smoother.
Ok, thanks. Let's see if I got it right :-)
I have 2 absolutely-positioned divs side-by-side, one falls off-
screen, either to the left of the screen or to the right, and the
other one fills the screen, and I want to slide them in the x
direction so that the one that was off-screen replaces the one that
was filling the screen.
If I do a transition of the "left" property I trigger multiple
redraws, but, instead, if I do an [ please your answer here ] it won't
so the sliding effect will be smoother.
I guess that, after the animation, I'll need still a last redraw to
"undo" the [ effect ] and move the things to the right, proper
"left"s, isn't it ?
:-)
Thanks (in advance) !
--
Jorge.
Here's a link to something official:
It says: "iPhone OS Note: In iPhone OS, transitions and animations of
the -webkit-transform and opacity properties are performance-enhanced."
-- Sean
There's a webkitAnimationEnd event. Wayne Pan posted some nice sample
code on this:
http://waynepan.com/2008/08/08/iphone-css-animations-thoughts-and-issues/
It helped me get animations working in TBS Backyard Mini Golf (a hybrid app)
http://itunes.com/app/tbsBackyardMiniGolf
-- Sean
>
> Found an even more interesting article just now. Have not read it all
> yet.
>
> http://developer.apple.com/safari/library/documentation/AppleApplications/Reference/SafariJSRef/WebKitTransitionEvent/WebKitTransitionEvent.html
>
> Linda
You're so "Linda", thanks !
:-)
http://rae.es/linda
--
Jorge.
> Ok, thanks. Let's see if I got it right :-)
Blank filled in here:
if I YOU do an [ -webkit-transform: translate3d() ] the sliding effect
will be smoother.
> I guess that, after the animation, I'll need still a last redraw to
> "undo" the [ effect ] and move the things to the right, proper
> "left"s, isn't it ?
>
iUI leaves the pages "off screen" after the transition, and instead
does the setup before each transition.
Here's the code:
function slide2(fromPage, toPage, backwards, cb)
{
toPage.style.webkitTransitionDuration = '0ms'; // Turn off
transitions to set toPage start offset
// fromStart is always 0% and toEnd is always 0%
// iPhone won't take % width on toPage
var toStart = 'translateX(' + (backwards ? '-' : '') +
window.innerWidth + 'px)';
var fromEnd = 'translateX(' + (backwards ? '100%' : '-100%') + ')';
toPage.style.webkitTransform = toStart;
toPage.setAttribute("selected", "true"); // "selected" is an
attribute used by iUI CSS for 'page' (i.e. block) visibility.
toPage.style.webkitTransitionDuration = ''; // Turn transitions
back on
function startTrans()
{
fromPage.style.webkitTransform = fromEnd;
toPage.style.webkitTransform = 'translateX(0%)'; //toEnd
}
fromPage.addEventListener('webkitTransitionEnd', cb, false);
setTimeout(startTrans, 0);
}
I wanted to use % rather than px for toStart, but for some reason that
wouldn't work, thus the use of window.innerWidth.
Although I believe it sounds like it should use translate3d instead of
translateX for performance reasons. (We'll try it that way in 0.40)
It sounds like it may be possible to use read of offsetLeft to force
the setup of the toPage to be rendered and remove the setTimeout()...
-- Sean
Did you file a bug? https://bugreporter.apple.com.
This should work, though.
> Although I believe it sounds like it should use translate3d instead
> of
> translateX for performance reasons. (We'll try it that way in 0.40)
In an earlier message I said that if you are using transitions
on -webkit-transform, then you can use any of the transform
functions just fine.
You only need to stick to the 3d variants if you are animating
something by hand, in JavaScript.
> It sounds like it may be possible to use read of offsetLeft to
> force
> the setup of the toPage to be rendered and remove the setTimeout()...
Be aware that calling offsetLeft can be very expensive. It forces the
browser to do an entire layout pass. The setTimeout() trick is more
efficient.
Simon
> Simon Fraser wrote:
>> If you're changing -webkit-transition "by hand" from JavaScript and
>> want to achieve good performance (e.g. maybe you're responding to
>> touch events from the user, moving things around), then use one
>> of the 3d transform types: translate3d(), rotate3d() etc. Those
>> will be faster in this case.
>>
>
> Is there a reason why the 3d types are faster in this case?
Yes.
In iPhone 2.0, whenever you set -webkit-transform: to something,
the browser would go and render that element to a texture, so
animating it was then much more efficient. It would also use
textures for animations/transitions of opacity.
However, that wasted texture memory when the -webkit-transform
was just for a static visual effect, and never animated. So, in
iPhone 3.0, the rule was changed to only render something into
a texture in two situations:
1. The transform includes a 3d transform function (like translate3d())
2. The element is animating -webkit-transform or opacity.
In any other situations, the element is rendered in software, and thus
animates in software, just like 'left'. This typically gives poor
framerates
on the phone.
So you can consider the 3d transform functions to be a hint that
you are going to be moving something around a lot in JS, and
to thus keep that element in a texture.
Simon
Thanks for your kind words. I didn't take your comments as criticism,
I just wanted to point out that iUI has been a great way to learn this
stuff. When I started using iUI a little over two years ago I knew very
little about JavaScript/Ajax or CSS and I have learned a great deal from
those ~500 lines of JS and ~400 lines of CSS. Richard Wagner's book,
iPhone and iPod touch Programming, was a big help as it explains how
(an early version of) iui.js works function-by-function.
Of course, there is nothing that beats learning by doing. And, of
course (here comes another plug) a great way to do this is by
contributing to iUI. An alpha release of iUI 0.40 is coming soon and
0.40 has some nice hooks for extensions - so hopefully this will make it
easier for others to contribute to and/or learn from iUI.
-- Sean
I didn't file a bug, I wasn't sure whether it was a bug or a feature.
The transitions proved to be very sensitive to the CSS used. I can't
remember the details now, but the overall CSS has to be sufficient for
WebKit to actually calculate the width. ( Some of the techniques I
used for debugging are here
http://code.google.com/p/iui/wiki/SlideCSSTransitionsNotes )
> In an earlier message I said that if you are using transitions
> on -webkit-transform, then you can use any of the transform
> functions just fine.
>
> You only need to stick to the 3d variants if you are animating
> something by hand, in JavaScript.
>
I misunderstood and thought you meant *starting* the animation from
JavaScript. Sorry for the misunderstanding.
> Be aware that calling offsetLeft can be very expensive. It forces the
> browser to do an entire layout pass. The setTimeout() trick is more
> efficient.
>
I'll leave it, then. Thanks!
-- Sean
A few suggestions, below...
> <html>
> <head>
> <script type="text/javascript">
> function shrink() {
> box = document.getElementById( "box" );
> var old_width = box.offsetWidth;
> box.style.width = old_width * .000001;
> }
> </script>
>
> <style type="text/css">
> div#box
> {
> background-color: blue;
> display: block;
> position: absolute;
> width: 320;
> height: 480;
> -webkit-transition-property: ease;
> -webkit-transition-duration: 0.5s;
> -webkit-transition-timing-function: default;
> }
> </style>
> </head>
> <body>
> <div id="box" onclick="shrink();"></div>
> </body>
> </html>
>
1) Add units of 'px' after width and height (including where you set it)
2) Avoid floating point numbers for width
3) -webkit-transition-property should be set to 'width' (the property
you want to animate)
4) animating 'width' should work, but if you use a 'scale'
transformation it may get HW acceleration on iPhone
-- Sean
>
> Jorge Chamorro wrote:
>
>> Ok, thanks. Let's see if I got it right :-)
>
> Blank filled in here:
>
> if I YOU do an [ -webkit-transform: translate3d() ] the sliding effect
> will be smoother.
Is there a way to attach a callback for -webkit-transform: translate3d
() without creating an animation?
I've tried it with both addEventListener("webkitAnimationEnd",
callback, false); and "webkitTransitionEnd", but nothing !
Also, I see a small glitch on the screen (but only once), when the on-
screen "ul" gets (for the first time) the .style.webkitTransform=
"translate3d("+ distancia+ "px, 0px, 0px)";.
Thanks,
--
Jorge
However, only certain things will be "performance-enhanced" on the iPhone:
See slidePages (lines 358-381) and slide2 (lines 426-443) Note that the
same callback used by CSS Transitions is also used by the fallback
timer-based animation.
> Also, I see a small glitch on the screen (but only once), when the on-
> screen "ul" gets (for the first time) the .style.webkitTransform=
> "translate3d("+ distancia+ "px, 0px, 0px)";.
>
Making sure glitches don't happen is tricky as the behavior is timing
dependent and can be different in different places (Desktop Safari,
Simulator, actual iPhone) and may also be dependent upon software versions.
In the slide2 function you'll see that I'm turning off transitions
before setting up some of the parameters. Also be aware that unless the
"selected" attribute is set to "true" the div/ul will be set to
"display: none" by iui.css.
To get everything perfect takes time and testing in different places.
I hope this helps,
Sean
>
> Jorge Chamorro wrote:
>> Is there a way to attach a callback for -webkit-transform:
>> translate3d
>> () without creating an animation?
>>
>> I've tried it with both addEventListener("webkitAnimationEnd",
>> callback, false); and "webkitTransitionEnd", but nothing !
>>
> There is. iUI does it:
> http://code.google.com/p/iui/source/browse/iui/iui.js?r=REL-0.30
( Why don't you use soft-tabs ! )
Well done, but... isn't "cb" the wrong callback in line 441: ("cb "
instead of "slideDone") ?
fromPage.addEventListener('webkitTransitionEnd', cb, false);
And, why doesn't translate3d(x, 0, 0) generate an end-of-whatever
event ?
Sliding should really be an animation, with a bit of bounce at the
end :-)
> See slidePages (lines 358-381) and slide2 (lines 426-443) Note that
> the
> same callback used by CSS Transitions is also used by the fallback
> timer-based animation.
>
>> Also, I see a small glitch on the screen (but only once), when the
>> on-
>> screen "ul" gets (for the first time) the .style.webkitTransform=
>> "translate3d("+ distancia+ "px, 0px, 0px)";.
>>
>
> Making sure glitches don't happen is tricky as the behavior is timing
> dependent and can be different in different places (Desktop Safari,
> Simulator, actual iPhone) and may also be dependent upon software
> versions.
I've found that the glitch happens only once at the exact moment when
the .style.webkitTransform= "translateX(npx)"; is applied to a "ul"
*for the first time*. So I do a fake .style.webkitTransform=
"translateX(0px)" asap, regardless of the slide()s.
> In the slide2 function you'll see that I'm turning off transitions
> before setting up some of the parameters. Also be aware that unless
> the
> "selected" attribute is set to "true" the div/ul will be set to
> "display: none" by iui.css.
>
> To get everything perfect takes time and testing in different places.
Sure, I know... :-)
In my (hyper-forked) iui.js the "ul" "pages" are childs of a
relatively-positioned wrapper div. That wrapper div sits centered on-
screen with equal margins (left=right="auto") at each side, and has a
max-width of "650px". As such, I can't rely on window.innerWidth and I
need to know the margins in order to add them. Here's what I've done:
var distancia= fromPage.offsetWidth+ parseInt(window.getComputedStyle($
('wrapper'),null).getPropertyValue('margin-left'), 10);
if (backwards) {
distancia= -distancia;
}
if (iui.hayCSSAnimado) {
console.log("Sliding con CSSAnimado");
var fromS= fromPage.style;
var toS= toPage.style;
var tiempo= 266;
var fromSInicial= "translateX(0px)";
var toSFinal= fromSInicial;
var fromSFinal= "translateX("+ (-distancia)+ "px)";
var toSInicial= "translateX("+ distancia+ "px)";
fromS.webkitTransitionDuration= "0ms";
fromS.webkitTransform= fromSInicial;
toPage.setAttribute("selected","true");
toS.webkitTransitionDuration= "0ms";
toS.webkitTransform= toSInicial;
toPage.removeEventListener("webkitTransitionEnd", cleanUp, false);
fromPage.removeEventListener("webkitTransitionEnd", cleanUp, false);
//the first timeout should trigger the 0ms animation to the start
positions
setTimeout(function () {
//the second timeout triggers the final animation
setTimeout(function () {
fromS.webkitTransitionDuration= tiempo+ "ms";
toS.webkitTransitionDuration= tiempo+ "ms";
fromS.webkitTransform= fromSFinal;
toS.webkitTransform= toSFinal;
toPage.addEventListener("webkitTransitionEnd", cleanUp, false);
}, 0);
}, 0);
return;
}
--
Jorge.