/
fixing_the_mobile_web.txt
144 lines (88 loc) · 11.3 KB
/
fixing_the_mobile_web.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
Fixing the Mobile Web
tips and tricks that can save your sanity
Hello, my name is Kamen Bundev and I'm a Front End Developer, working on Kendo UI Mobile at Telerik. Today, I'm going to help you enter the dark forest of mobile browser bugs and keep your head on. You will need it later, when you delve deeper alone :).
Smartphones changed the Web landscape.
They introduced smaller screens and weak processors and with their exponential growth forced us, the developers, to provide special treatment for them.
We grew to love them and support them.
But its a love/hate relationship - we love them and they hate us.
Previous year, there were at least 3 major smartphone operating systems on the global mobile landscape, that roughly amount for 80% of the market. If we count Symbian, the number grows above 90%.
Worldwide smartphone market, by operating system, by 2011 global sales
according to Canalys
Operating System Shipments 2011 Market share 2011 Annual growth
(millions)
Android 237.7 48.8% 244%
iOS 93.1 19.1% 96%
Symbian 80.1 16.4% -29.1%
BlackBerry 51.4 10.5% 5%
Bada 13.2 2.7% 183.1%
Windows Phone 6.8 1.4% -43.3%
Others 5.4 1.1% 14.4%
Total 487.7 100% 62.7%
The good news is that all the major players are using the WebKit engine. The bad news - implementations vary a lot.
Feature,Android,iOS,BlackBerry OS
HTML5 Forms,X,5+,+
SVG,3+,+,+
Masks,mostly work,+,+ (except 7.0)
3D Transforms,4+ (broken in 3),+,PBOS 2+
WebGL,X,X (except ads),PBOS 2+
As you can see from the table above, features that are supposed to work everywhere, are actually not supported on some platforms. Every operating system vendor decides what to include in their WebKit distribution, thus leading to such inconsistencies. Only BlackBerry PlayBook OS 2 supports every feature from the listed above, but its market share is below 10%.
[slide]Escape route: if you can, test everything you create, on every device you can get your hands on![/slide]
The cold hard truth is far worse:
Even on supported mobile platforms one of these features can be close to unusable. How many of you created a web application and ran into strange or even impossible issues that forced you to abandon this approach? Issues like
* Slow performance
* Broken rendering
* Missing events
* Freezes and crashes
plague the mobile web development world and pray upon our time or rather money.
The most irritating ones are the performance issues. Without hardware acceleration custom scrolling and animations grind to a halt. Fortunately all that is needed to speed up the rendering is a carefully placed -webkit-transform: translatez(0) - 3D transforms trigger hardware acceleration and the element rendering gets offloaded to the mobile GPU. However translatez(0) is becoming damnation as much as salvation - welcome the new zoom: 1 for the mobile web.
* 3D transforms do not work in Android 2
* Transforming bigger elements can lead to bad performance.
* Transforms can break the rendering of masks, especially on Android.
* 3D transform is not enough to trigger hardware acceleration on some platforms.
* Transforms may lead to artifacts.
* Transforms break form elements on Android.
I'll now go over these one by one:
Performance degradation
Imagine this scenario: you have a rather large list of images on a page with a custom scroller. To speed up the scrolling, you apply a translatez(0) on the list. Instead of speeding up, the scrolling gets much worse and you can actually see parts of the page redrawing when you scroll by. The issue you've just ran into is called max texture size. All graphics chips have this texture size limit and when you reach it, your texture is split into several smaller textures which are rendered separately, resulting in more calculations and generally worse performance. This is especially visible on high resolutions as on iPad 3 as there the graphics chip has to move 4 times more pixels per texture than on previous models (even though the max texture size on iPad 3 is 4 times larger, it still covers only slightly more than the screen).
To avoid this, you need to use smaller elements that are sure to fit in the texture size - in this case, apply the transform on the list items, instead of on the whole list.
[slide]Escape route: Mind the size of your hardware accelerated elements.[/slide]
Fair and Square
We already saw that most native smartphone browsers are WebKit based. This fact may change in the future with IE10 and Firefox advancing, but now it drives the usage of some proprietary WebKit functionality - for instance mask images. WebKit masks are just images with alpha transparency which apply a non-rectangular clip mask on their element. They are supported in all mobile WebKit based browsers, with the exception of BlackBerry OS 7.0, in which they don't work at all. Fortunately they do work in 6.0 and 7.1.
However most issues with webkit masks you will probably face in Android - 3D transforms and masks just don't get together. An example - applying -webkit-backface-visibility on a masked element in Android 4 results in a plain colored square. On the other hand, applying -webkit-transform: translatez(0) on a single masked element breaks all the masks on the page... how cool is that. But wait, there's more - if you apply translatez(0) on a container, the masks inside it work, but the masks outside turn to squares. And the best part - all this may vary between Android versions.
[slide]Escape route: Take extra care where you apply WebKit masks and 3D transforms.[/slide]
The Forbidden fruit
You've done your job - you've tuned your web application to the max and you know that it runs like butter. You're confident that nothing can surprise you. And then, the horror, you receive a bug report that your app is crawling slower than the sunset on a Samsung Galaxy S III. What? How? Turns out transforms are not enough to trigger hardware acceleration there. You need a transition of the transform. And it should run at least a little - even for 1 millisecond.
[slide]Walkaround: Apply a 1ms or less transition on the transformed element, make sure you don't activate it accidentaly (use -webkit-transition-property to limit it).[/slide]
Shh, Working
Several times I've run on a hard to reproduce problem on Android 2.3. It happens usually when you have transforms applied in a WebView then you open a new Activity with a another WebView in it and close it. The transforms on the page afterwards are frozen - they don't update on the screen even though the page undeneath works okay and fires events.
So, if you run into this issue while testing your web application, better remove all transforms before opening the new Activity.
[slide]Walkaround: If you run into this issue, remove the transforms before opening the new Activity.[/slide]
DeFormed
Almost all modern mobile browsers included support for HTML5 form elements like date and time pickers. For instance in iOS HTML5 form elements were introduced in iOS 5.0 and BlackBerry OS 6.0, however the default Android browser didn't join the party. Google introduced Chrome as the default browser in Nexus 7, but most of the Jelly Bean phones out there are still using the old Android browser. Nexus 7 WebView is no exception.
So, if you really want to use HTML5 form elements, you will need to resort to external libraries or fall back to type text with some kind of validation.
[slide]Escape route: use external libraries if you really need the pickers, or alternatively fall back to text and validate your input.[/slide]
You may have noticed on Android's native browser, that when you place an HTML input on a page and focus it, you can't style the focused state. This happens because it is not actually a state - Android renders another input, this time native, on top of the one in the page. This fake native element processes your typing and sends it to the page. You can easily observe that if you know that the fake input doesn't position correctly when the original element is transformed. /Demo/
Hideous as this is, you can avoid this in Android 4.0, for a price - you can use the little known CSS property -webkit-user-modify to remove the fake input on focus:
[slide]Walkaround: Use this CSS, with a trade-off:
input[type=text], ...
{
-webkit-user-modify: read-write-plaintext-only;
}[/slide]
The workaround above has a trade-off - custom keyboards /like Swype/ stop working completely, so you must carefully weigh the pros and cons of using it. In Android 2 the solution gets uglier - the only thing you can do is translate the input container to get it out of the screen and return it back with absolute positioning, thus removing the fake element. The negative effects of such workaround are even worse, ranging from broken non-english keyboards, through most HTML inputs turning to type text, to the inability to type the number 9?!?
Fortunately all this mess is fixed in Android 4.1, both in the default browser and in WebView, and we'll just to wait a few years for everyone to upgrade.
History Lessens
If you're building a single page web application, you will surely need a way to navigate in it. However, the History API is not consistently supported by all WebKit browsers - for instance it doesn't work properly in iOS up and including 4.3, while it should work for newer versions. Interesting though, the History API works okay in Android 2. The good stops here - it is broken in Android 3 and 4, and additionally hashes are broken in Android 4+ (the addressbar doesn't get updated every time, while the location do update internally).
[slide]Escape route: Better resort to hashes for single page applications on mobile devices.[/slide]
Labeling Jars
iOS is no safe heaven from strange and obscure browser bugs. One example of that is the input label bug. On every other platform, if you click on a label which is associated with an input, the input gets focused. However in iOS, this is not true - nothing happens when you click on the label, unless it has an onclick event. Actually you can skip the event - an empty onclick="" attribute is all that it takes. Even better - if you have a container around all your inputs and labels, you can add the empty onclick="" attribute to it and all labels will suddenly start working.
[slide]Walkaround: Add empty onclick attribute to the label or its container to fix the issue.[/slide]
Redraw Alone
The next issue is not really an issue - it is part of how modern browsers work. When you change a CSS style on an element with Javascript, the browser doesn't hurry away to actually change it but instead wait some cycles for more such changes, then groups them and sets them in one go. And before the element actually changes, accessing element properties may return strange values. However, if you try to get the element's computed style for that property or check one of element's dimensions, like offsetWidth, the browser is forced to apply the changes immediately in order to return correct results. So, if you're using jQuery,
the [slide]Walkaround: with jQuery it boils down to this:
element.css("display", "block").css("display");
or without:
element.style.display = "block";
element.offsetWidth;
[/slide]
Then you can safely set transition styles for instance.
Closing words.