Beta 3: Landing in about a week
We’re hard at work on the last big changes we want to get in before moving onto the first RC for 1.0. We just landed pushState (see below). The other items on deck are finishing our move to transitions for page animations, adding a bit more extensibility for JS-driven apps, and bringing really slick transitons and fixed headers for iOS5. We’ll keep you updated as we get closer. We are targeting 1.0 for the end of September.
pushState landed: Now, clean URLs with Ajax-based navigation
We’ve been working very hard to add pushSate to jQuery Mobile. After many months and at least 6 complete attempts and the hard work of everyone on the team to get this right, we’ve finally landed this feature. Since we use Ajax-based navigation extensively throughout a jQuery Mobile experience, we need to track each page with a hash change which can make for some pretty long and unwieldy URLs, but it was a small price to pay to supporting the Back button and deep linking to pages.
Now with the addition of pushState, we’re able to update the URL to the clean, standard path in browsers that support this feature. Technically, we use
history.replaceState() because this allows us to layer pushState support and an enhancement to our existing, and widely supported, hashchange-based navigation model. We essentially let the hash change happen, then replace the URL with the clean, full path of the page in browsers that support this capability. This works in later versions of desktop Safari, Chrome, Firefox and Opera as well as Android (2.2+ and Honeycomb) and the soon-to-be-released iOS5. In browsers that don’t support this feature, the hash-based URLs will continue to work as the did before to preserve the ability to share and bookmark URLs.
The pushState feature is implemented as an extension to the the navigation code so it can be easily pulled out of the build if it’s not needed on a project. It’s also possible to turn this feature off by setting the
pushStateEnabledglobal option to
false, like this:
$.mobile.pushStateEnabled = false;
Pro tip: How to view the source of a jQuery Mobile page
Since we use Ajax to pull multiple pages into the DOM, if you view the source you will see the code for the first page you visited unless you use a web inspector tool like Firebug to view the current DOM. Now with pushState in place, to view the source, simple refresh the page and view source. In browsers that don’t support pushState, you need to edit the URL to remove the redundant part of the hash to get full page path, then reload to view the source. Hopefully, this will make exploring the docs a bit easier for people.
Page animations: Moving from keyframe to transitions
One of the things we hear a lot of people asking for is smoother page transitions, and we couldn’t agree more. In the current system, we use keyframe-based animated page transitions (originally borrowed and tweaked from jQTouch). Keyframe animation tends to be more verbose, and its support is mostly limited to Webkit browsers (with Firefox 5 as a recent exception), we’ve been working to change over to using CSS transitions for our page animations.
The advantage of moving to CSS3 transitions is that they are already supported by recent versions of both Firefox and Opera in addition to Webkit so this paves the way much broader support for page animations over time on mobile and desktop browsers. Transitions are also a bit more concise syntactically than keyframes for our use case, which tends to be a 1-step transition from point A to point B.
We were also hoping that transitions would behave more smoothly on certain platforms, as the keyframe-based animations tend to drop frames on several of the Android devices we’ve tested. In testing, however, this switch isn’t the panacea we’d hoped. In extensive testing in our lab, we’ve found that there is little difference in the smoothness of animations between keyframe and transitions on the browsers that already supported animations — iOS, Android and BB6/PlayBook.
In Firefox, the latest versions of the desktop browser support transitions but the most up-to-date version of Firefox Mobile (beta 5) we tested on Android didn’t seem support them, even though we heard reports that it did. So, the desktop experience will be improved with this upcoming change, but not mobile (yet).
Opera Mobile (not Mini) does currently support transitions, but the performance was so slow that we’ve decided to not add in the Opera-prefixed transition rules until they release an update. Opera desktop 10.5 and later do a good job with transitions, but we can’t flip the switch for desktop without harming the mobile browser since they both use the same vendor prefix so this will be added as soon as an update lands and has decent uptake.
Why transitions aren’t smooth: A complex set of factors
There are a few factors that contribute to the smoothness of page transitions.
If the animations are hardware accelerated so they are efficiently rendered by the GPU instead of through the CPU and software, they will be markedly smoother. On iOS, even older versions of the iPhone, the OS does a very good job with hardware accelerating with both keyframe and transitions so animations are quite smooth. On the other hand, Android 2.x devices may only show 1-2 frames during a page transition on some devices because of the lack of hardware acceleration. Rendering bugs/glitches in the transitions/keyframe implementations for the platform can also contribute to blinkiness. Ariya Hidayat from Sencha has a great article on the technical details of hardware acceleration. Because we support web standards for our transitions, all we can do on this front is try to use the most effective CSS we can and the rapid innovation in devices and mobile operating systems should move this part along quickly.
The size of the document and the amount of area being re-drawn can also cause flashes of blank screen zones or blinks. For example, webkit uses a 1024×1024 tile so if a transition or animation causes the canvas to shift by more than that, a blink may occur if the browser doesn’t paint that area fast enough.
Scrolling the page into position can also be a significant cause of the transition smoothness. Here’s why: When a new page is pulled in via Ajax to enable an animated page transition, it’s added to the DOM and positioned with CSS to queue up the animation. So if we’re moving with a slide transition, the new page will be placed to the right of the current page so we can slide to the right and animate the new page into view.
Since both pages share the same viewport, we position the top of the new page next to the top of the current page which means that if you’re scrolled down on a page and click a link, we need to first scroll up to the top of the current page, then begin the slide transition. This scroll to the top action produces a noticeable jump, especially in underpowered devices. Because of this, you’ll notice that if you start a page transition when already scrolled to the top of the page, it will not jump or blink at all in most cases (some platforms always blink). We also remember and restore the original scroll position of a page that you revisit, so if you are scrolled down on a page and hit Back, you will see the current page scroll up, the slide animation will occur, then you will see the page scroll down to your original position.
We’ve tried every trick in the book to minimize the scrolling artifacts, but we now realize that this can’t be completely mitigated while still supporting the wide range of platforms the jQuery Mobile wants to cover without taking a fresh approach to the problem.
The future: Overflow and fixed positioning, for real this time
Unfortunately, these scripted approaches tend to share a common flaw: they only work in a very narrow range of mobile browsers, usually just iOS and Android (with a lot of caveats and performance issues). Since scroller scripts need to intercept events to trigger the scrolling, they can prevent interaction with form elements and introduce a host of other serious usability issues if not applied with care and lots of testing. These scripts also need to be carefully targeted through support tests (and unfortunately UA detection), as they run the risk of making a page completely unusable on the mobile (and desktop) platforms they do not support. For web applications that are accessible on the public web, we don’t feel that this is an acceptable tradeoff for smoother transitions and fixed toolbars. In an installed native app, however, these scripts become a much more feasible option because the risk of usability problems is greatly reduced when only one browser needs to be supported.
For these reasons, we’ve tried our best to build on top of native browser scrolling, so we’re very excited by iOS5’s upcoming support for a touch-targeted version of
overflow:auto|scroll , and proper support for
position:fixed to allow for internal scrolling regions with the native momentum scrolling with CSS. This will enable us to bring both truly “fixed” toolbars and super smooth transitions, all by using web standards and very little additional code. We’re working now on landing this as an improvement for 1.0 so we’re ready when iOS5 is released.
Think of this as an enhancement to what we have now: if the overflow: and -webkit-overflow-scrolling:touch properties are supported, we can make sure toolbars stay fixed and eliminate the scrolling jumps between transitions. Coupled with iOS’s already-excellent hardware-accelerated transitions, we’ll be very close to native performance.
Don’t other mobile platforms already support overflow?
Yes, but there’s a catch. Both Android Honeycomb and the Blackberry PlayBook support overflow: properties, but that’s not quite enough. If we simply placed an overflow: auto CSS rule on the page body, other popular mobile platforms like older versions of Android and iOS would essentially just clip off the content and make it effectively inaccessible (yes, you can can do a two-finger scroll gesture in iOS but nobody knows that).
The smart thing about Apple’s implementation for iOS5 is that they added an additional CSS property
-webkit-overflow-scrolling:touch that allows us to test for this touch scrolling property and, if supported, add in the
overflow rules for just those browsers. This is the only safe way to target overflow without resorting to complex and unmaintainable user agent detection.
We will be working with device and browser makers to encourage support for both these CSS-based properties because we strongly believe that this a critical piece needed to build rich mobile web apps. So let’s all ask other mobile companies to follow Apple’s lead here and support both
overflow: properties ASAP.
The project will add any vendor-prefixed additions to touch scrolling property if, for example, Opera, Firefox or Microsoft added this support. Once people see how much better page transitions and fixed toolbars are on iOS5, we’re hoping this will be supported quickly by other browsers.
JS-based scroller scripts may still have a place in this new world as a polyfill for browsers that dont’ yet support these new CSS capabilities but we see this as a brief, interim tool in the evolution of the mobile web. Once implemented, it will likely be easier to add such a shim to your codebase as well.
The team has spent a ton of time working on trying to improve transitions because we know this is an incredibly important feature. We hope this helps to provide a bit of useful detail on the challenges we face and how we plan on moving forward.
Notable commits this week
Fix to check the domCache option before rebinding the page remove on select menu. When closing a fullpage select menu we need to check the domCache option before rebinding the page remove handler. If domCache is true the page remove wasn’t bound in the first place, so binding it on menu close will cause the removing of a page that mustn’t be removed. Thanks SamuelKC!
Ellipses too aggressive – truncating overflow early on lists, buttons, form elements (issue 779) – Adjusted padding on buttons
Sponsor thanks: Adobe
We’d like to thank Adobe Systems Inc. for both contributing a generous donation at the start of the jQuery Mobile project and for sponsoring the development time of Kin Blas (@kinblas) for the past year. To top it off, they also recently just hired another mobile team member, John Bender (@johnbender) to work on the project in a dedicated way. Kin and John are an important part of jQuery Mobile team and their amazing talent and drive has been critical to the success of this project. we wanted to acknowledge Adobe for their generous support as a premier sponsor of the project. Thanks Adobe!
As you probably know, Adobe is has been included jQuery Mobile in the new Dreamweaver CS 5.5 release and includes a lot of great tools to make it easy to build mobile-optimized sites and apps with jQuery Mobile.
If you are looking to support the jQuery Mobile project, we are actively looking for corporate sponsors to provide donations or commit to long-term developer involvement. To learn more, please contact Todd Parker, project lead to discuss opportunities for supporting the project and open source.
New jQuery Mobile pagination plugin
Team member Scott Jehl of Filament Group just posted a cool new pagination plugin that makes it super simple to allow for swiping between separate jQuery Mobile pages. Perfect for navigating through photo galleries, articles and more.
The Pagination plugin creates touch-drag navigation between separate HTML pages. Simply add this plugin to your page and link together documents via ordinary HTML anchors. The linked pages will pre-fetch, and in browsers that support touch events, you’ll be able to drag between the linked pages, while desktop users can navigate with mouse or keyboard. Like all navigation in jQuery Mobile, this plugin ties into your browser’s history, so bookmarking, and using the browser’s back and forward buttons work as expected!
The latest 2.0.2 version adds the ability to drag swipe between photos and adds a number of refinements.
For a nice example of jQuery Mobile, responsive design and Photoswipe, check out this portfolio site.
[contentblock id=1 img=gcb.png]