Posts Tagged ‘pastrykit’

Using mobile-specific HTML, CSS, and JavaScript (Mobile web part 5)

Tuesday, June 29th, 2010

(updated June 27, 2011)

Mobile-specific HTML

Viewport tag

Use the viewport tag to properly fit the content to the screen:

<meta name="viewport" content="width=device-width, initial-scale=1.0"/>

Tel scheme (to initiate phone calls)

<a href="tel:18005555555">Call us at 1-800-555-5555</a>

Sms scheme (to initiate text messages)

<a href="sms:18005555555">
<a href="sms:18005555555,18005555556">              <!-- multiple recipients -->
<a href="sms:18005555555?body=Text%20goes%20here">  <!-- predefined message body -->

Disable automatic telephone number linking

<meta name="format-detection" content="telephone=no">

iOS-specific HTML (some work on Android as well)

You also have access to several Apple-specific tags to use in your iOS applications (iPhone, iPad, and don’t forget the iPod Touch!).



<link rel="apple-touch-icon" href="icon.png"/>


<link rel="apple-touch-icon-precomposed" href="icon.png"/>


<link rel="apple-touch-icon" sizes="72x72" href="touch-icon-ipad.png" />
<link rel="apple-touch-icon" sizes="114x114" href="touch-icon-iphone4.png" />


<link rel="apple-touch-startup-image" href="startup.png">


<meta name="apple-mobile-web-app-capable" content="yes" />


<meta name="apple-mobile-web-app-status-bar-style" content="black" />

Turn off autocorrect, autocomplete, and autocapitalize

And also some handy attributes to turn off annoying autocorrect features:

<input autocorrect="off" autocomplete="off" autocapitalize="off">

Mobile-specific CSS

position:fixed and overflow:scroll

Mobile browsers are now starting to support these basic CSS properties better. Position:fixed will work on Android 2.2+ and iOS 5+. Overflow:scroll works with one finger on iOS 5+.

Also, iOS 5 has additional CSS to give the native scrollbar and momentum/intertia to elements with overflow:scroll: -webkit-overflow-scrolling: touch;

Media queries

Media queries enable you to target specific features (screen width, orientation, resolution) within CSS itself. Media queries themselves are actually quite old and are not mobile specific (they used to be popular for making a print-friendly version of webpages).

You can use them two ways: 1) inline in a CSS stylesheet or 2) as the “media” attribute in the link tag, which loads an external stylesheet. The following is an example of inline CSS that’s applied only when the device is in portrait mode:

@media all and (orientation: portrait) {
	body { }
	div { }
}

Here’s the same media query using the other method, which points to an external stylesheet (not recommended):

<link rel="stylesheet" media="all and (orientation: portrait)" href="portrait.css" />

This is not recommended because it creates an additional HTTP request (bad for performance). Also, in the case of screen orientation, the separate CSS stylesheet is NOT downloaded when the screen is rotated.

Here’s a few examples of using inline CSS:

// target small screens (mobile devices or small desktop windows)
@media only screen and (max-width: 480px) {
  /* CSS goes here */
}

/* high resolution screens */
@media (-webkit-min-device-pixel-ratio: 2),
             (min--moz-device-pixel-ratio: 2),
             (min-resolution: 300dpi) {
  header { background-image: url(header-highres.png); }
}

/* low resolution screens */
@media (-webkit-max-device-pixel-ratio: 1.5),
             (max--moz-device-pixel-ratio: 1.5),
             (max-resolution: 299dpi) {
  header { background-image: url(header-lowres.png); }
}

Read more: Media queries (Mozilla Developer Center)

Miscellaneous CSS

-webkit-tap-highlight-color (iOS): override the semitransparent color overlay when a user clicks a link or clickable element. To completely disable it, set the value to ‘transparent’ or ‘rgba(0,0,0,0)’

-webkit-user-select: none; – prevent the user from selecting text (also works on desktop WebKit)

-webkit-touch-callout: none; – prevent the callout toolbar from appearing when a user touches and holds an element such as an anchor tag.

Mobile-specific JavaScript

window.scrollTo(0,0);

This hides the address bar and takes advantage of the entire device screen. You’ll have to set this in a timeout and make sure to get the timing right. See Remy Sharp’s post for more details.

window.matchMedia()

(iOS 5+) Again, just as CSS media queries aren’t specific to mobile, they do come in especially useful for mobile, so it’s worth mentioning their JavaScript counterpart. window.matchMedia() is a JavaScript-based version of media queries. You can use respond.js as a polyfill for devices that don’t support this functionality natively.

navigator.connection

(Android 2.2+) Determine if the phone is running on WiFi, 3G, etc. Example:

if (navigator.connection.type==navigator.connection.WIFI) {
  // code for WiFi connections (high-bandwidth)
}

window.devicePixelRatio

Determine screen resolution (analogue to the CSS media query). (iPhone 4 has the value 2, while Nexus One has the value 1.5).

window.navigator.onLine

Not strictly mobile, but helpful for apps to determine if they’re being run offline.

window.navigator.standalone

(iOS 2.1+): determine if it’s running in full-screen mode

Touch and gesture events

touch events (iOS, Android 2.2+): touchstart, touchmove, touchend, touchcancel

gesture events (Apple only, iOS 2+): gesturestart, gesturechange, gesturend give access to predefined gestures (rotation, scale, position)

Screen orientation (every 90 degrees)

orientationchange event: triggered every 90 degrees of rotation (portrait and landscape modes). The current orientation is available through window.orientation

Device orientation (more fine-grained)

The deviceorientation event will fire very frequently, and gives more fine-grained information about the device’s orientation in three dimensions.
MozOrientation (or onmozorientation?) (Fennec/Firefox Mobile, Firefox 3.5+): also not strictly mobile. Gives access to the device’s accelerometer (x-y-z orientation data), updated periodically. Works on Android phones running Mobile Firefox. On the desktop this works with laptops such as Thinkpads and MacBooks.

devicemotion (shake gestures, etc.)

devicemotion fires when the user shakes or moves their device. Devicemotion taps into the accelerometer, which is fires off when the device accelerates. Contrast this with the deviceorientation event, which taps into the device’s gyroscope (if it has one), which only measures the 3D angle orientation, even when the device is at rest.

Media capture API

While iOS is still lacking basic file inputs, Android is forging ahead, giving developers fine-grained control over content users can upload.

<!-- regular file upload (Android 2.2+, NO iOS) -->
<input type="file"></input>

<!-- opens directly to the camera (Android 3.0+) -->
<input type="file" accept="image/*;capture=camera"></input>

<!-- opens directly to the camera in video mode (Android 3.0+) -->
<input type="file" accept="video/*;capture=camcorder"></input>

<!-- opens directly to the audio recorder (Android 3.0+) -->
<input type="file" accept="audio/*;capture=microphone"></input>

BlackBerry specific

If you’re developing for a BlackBerry Widget, you have access to proprietary information through the blackberry object (which gives access to useful information such as blackberry.network [returns values such as CDMA and Wi-Fi] and blackberry.system).

You also have the option to use PhoneGap, which augments JavaScript and gives you access to more phone features that native apps would have access to.

Use a mobile-optimized JavaScript library

I’ve created a separate entry for the available mobile libraries and frameworks.

Because smartphone browsers are standards-based, the aim of a JavaScript library on mobile is less towards API normalization and more towards providing an actual UI framework, usually to emulate the feel of native apps (and to provide easier workarounds to lack of access to position:fixed). We’ve seen a few libraries released that emulate the iPhone UI, and in the future we might see libraries emulating the Android UI, as well as entirely new UIs.

There’s also a bit to be said about simply loading full desktop JavaScript libraries into mobile clients. In my opinion this doesn’t particularly make sense, especially in a world where latency and bandwidth are so much more of a concern. It doesn’t make sense to force the user wait longer and download code that’s ultimately useless to them (hacks for desktop browsers such as IE 6, etc).

Take advantage of new stuff!

While not specific to mobile, there’s a lot of new stuff in general that you can use. If you limit yourself to the top smartphones (iPhone, Android, and maybe webOS), compared to the desktop you immediately have access to an even wider array of new stuff, especially many Webkit proprietary features, since most of these top smartphones have browsers based on Webkit.

-HTML: new tags (HTML5 (I’m sure you’ve heard of it by now…))
-CSS: 2d transforms, 3d transforms, animation, border radius, custom fonts with @font-face, etc.
-JavaScript: strict mode, constants, block scope, Date.now(), etc.

Slides

More from the Mobile Web series:

Part 1: The viewport metatag
Part 2: The mobile developer’s toolkit
Part 3: Designing buttons that don’t suck
Part 4: On designing a mobile webpage
Part 5: Using mobile-specific HTML, CSS, and JavaScript
Part 6: Dealing with device orientation
Part 7: Mobile JavaScript libraries and frameworks

PastryKit: digging into an Apple Pie

Wednesday, December 16th, 2009

Yesterday John Gruber wrote about Apple’s PastryKit, iPhone’s JavaScript framework that’s been discovered “in the wild” on the iPhone user guide at http://help.apple.com/iphone/3/mobile/. There’s a few ways to access the page:

  • with an actual iPhone or iTouch
  • by browsing with an iPhone/iTouch user agent. If you’re using Safari, enable the Developer menu in Safari>Preferences>Advanced and switching user agents by clicking on Develope>User Agent

What’s all the big fuss?

John was particularly interested in the responsiveness and native-like interaction of flinging through long lists, the fact the address bar is completely hidden, and the possibility of having a toolbar fixed to the top of the page. PastryKit makes all of these things possible and implements them better than anything else. And the result is nearly indistinguishable from a native app. Here’s a video I made of the iPhone user guide in action, powered by PastryKit. This is running on Safari – it’s not a native app!

PastryKit has been here for a while

As John Gruber points out, the code for PastryKit has been there for quite a while now. Stack Overflow has a question about it that was asked way back in July, and there are several more recent references to it by jQTouch developer David Kaneda on Twitter. Of course, since John’s post there’s been an explosion of interest in the form of even more tweets!

Hopefully with all of this increased attention, we’ll see Apple take notice and address it. Here’s hoping, anyway.

Some interesting features

There’s even more interesting takeaways from the PastryKit code, and I’m sure I’ve just barely scratched the surface:

  • implements its own form of Object-Oriented programming (obj.inherits and obj.synthetizes properties). When modules are declared, they’re registered as a PK Class (i.e. PKClass(PKBarButtonItem) registers PKBarButtonItem as a PK Class)
  • CSS3 wrapper functions (PKUtils.t() is a wrapper for translate3d, etc.)
  • no single library namespace (surprisingly) – which means there are many many global variables. This however is somewhat acceptable, as all variables are prefixed with “PK” and are declared to be constant (const PKStartEvent, const PKEndEvent) and cannot be overwritten.

There’s also some interesting takeaways not from PastryKit itself, but from the way the iPhone user guide is implemented. Most of the data on the page – including each menu icon (base64 encoded) – is located in a single 650kb JSON-encoded file called content.json. This means the initial loading of the page is quite slower than the user would normally expect, but once the initial payload has been delivered, it’s a relatively smooth browsing experience thereafter.

And as John Gruber already pointed out, this data is stored locally with the help of HTML5, allowing the user to continue reading even while offline!

iPhone user guide in Safari

iPhone user guide in Safari

PastryKit unminified and explained (sorta)

What I’m excited to show you now is a result of a bit of effort to make PastryKit more intelligible. Though there’s a minified version of the code on Apple’s website, it’s not obfuscated (and rendered unintelligible), so not all hope is lost! With the help of jsbeautifier.org we can now see the slightly unminified version of the code: PastryKit.js unminified.

The next thing I did was separate each module into its own file. I was able to separate the code into 27 numbered files, with the original ordering preserved (to prevent issues with dependencies). Viewing the code in this way definitely helps make sense of it all. You can download these separate files as part of a little unofficial SDK I made, which also includes a copy of the iPhone user guide with the JS iPhone-only redirect removed: PastryKit unofficial SDK.

PastryKit modules

The following is an explanation of each module I found. The descriptions are definitely incomplete and possibly inaccurate, so any comments or help is appreciated. But this should hopefully shed some light on the matter!

  • PKUtils – general helper functions (PKUtils.t() is a wrapper for CSS translate3d, PKUtils.degreesToRadians(), etc, etc.)
  • PKEventTriage – general event handler
  • PKPropertyTriage – handlePropertyChange() method – ?
  • Element – helper functions added to HTML Element prototype
  • Node – adds getNearestView() method to HTML Node prototype
  • PKClass – custom-rolled class with with “inherits” and “synthetizes” properties
  • PKObject – custom-rolled object with observer pattern. Most modules extend from this.
  • PKPoint – wrapper for WebKitPoint – used for touch events?
  • PKSize – wrapper for width/height properties
  • PKImage (inherits PKObject) – helper for creating Image elements and knowing when it’s finished loading (but doesn’t add the image to the DOM)
  • PKAnimator – basic animation tweens
  • PKTransition – helper for proprietary Webkit CSS transitions
  • PKTransaction – interacts with PKTransition – ?
  • PKView (extends PKObject) – manages a view, such as handling events that occur within that view – ?
  • PKContentView (extends PKView) – ?
  • PKRootView (extends PKContentView) – ?
  • PKScrollIndicator (extends PKView) – custom scrollbar
  • PKScrollView (extends PKView) – handles dynamically positioning the page when it’s scrolled
  • PKTableView (extends PKScrollView) – handles more touch/scroll events?
  • PKCellPath – ?
  • PKTableViewCell (extends PKView) – ?
  • PKToolbar (extends PKView) – manages the top toolbar
  • PKNavigationView (extends PKView) – manages bottom navigation bar
  • PKNavigationItem (extends PKObject) – manages bottom navigation buttons
  • PKControl (extends PKView) – manages generic controls
  • PKBarButtonItem (extends PKControl) – manages button controls
  • PKSearchBar.js (extends PKView) – manages the search bar

Conclusion after a first glance

As far as I can tell, this is no full-fledged JavaScript library. At least not for now.

On first glance PastryKit seems to be at most a nice development framework for making web apps with the same look-and-feel of native iPhone apps. And this framework in many ways does this better than anything out there (at the moment).

I echo the sentiments of Gruber – I do hope we hear more about this from Apple!