Awhile ago, I explored the innovative world of hybrid app development using Steroids.js. If you haven't read it, basically, they enable native UI elements in PhoneGap applications.
Since then, I've collaborated with Kevin Tunc and successfully released an app on the App Store, earning AppGyver's "App of the Month" title! It wasn't a walk in the park to create a high-quality hybrid app, so I decided to share my experiences and pitfalls. As any developer knows, learning from mistakes is often the best way to grow.
In this article, I'll focus on iOS development, but many of these tips apply to Android phones as well. Keep in mind that some parts of this article are universal for hybrid app development using PhoneGap or other frameworks.
Getting The Device To Leave You Alone
When working with a webview trying to mimic native views, a reset.css file isn't enough. You need to address specific issues like:
300ms Tap Delay
Mobile browsers implement a delay on tap to check if you're attempting to double-tap or not. This results in a sluggish experience when navigating your app.
To fix this, specify a viewport for some browsers, and use FastClick for others that don't respond to the first solution.
Disable Selection/Copy When Long Tapping
You know... this thing:
Fixing this issue is relatively easy. For webkit, add the following CSS:
Disable Double Tap
If you don't like double tapping and use jQuery, try this Stack Overflow answer. Just in case this answer disappears, here's what it looks like:
Disable Overscroll
I think you want the "bounce" effect when scrolling out of a webview. However, in some cases, you might need to disable this behavior. There are many ways to do this; I personally used this one from Stack Overflow:
Higcharts
If you use Highcharts, you might encounter scrolling troubles when users touch the graphs. This Gist might help: https://gist.github.com/skarface/2994906
Allow Text Selection For Input
This is an iOS issue. In some cases, you won't be able to select and edit text in your inputs as you'd like. You can fix this using user-select:
Better Looking Text
I noticed that changing the text-rendering option gets things looking better. The trade-off is performance, but if you don't have huge chunks of text, you'll be fine.
Remove Glossy Looking Buttons in Safari
How to go from a glossy stylized button (left) to a cleaner, flatter, easier-to-update button (right)?
Easy!
You can read more about this here. I also found that changing box sizing could help in the "undesign" process. Smarter people than me explained how it works; you can read about it or try it out like this:
Removing Gray Highlight When Tapping Links
On mobile Safari, tapped links will get quickly highlighted, which doesn't look very "native" once embedded in a Steroids JS webview. This is especially true for images. Change this using:
I found that changing the color feels better than removing it.
Overflow Scrolling
If you have some elements set to scroll when overflowing, you might feel that the scrolling itself doesn't "feel right". I suggest looking into this direction:
On Fluid Layouts
Using percentages for size can be a good option to handle different screen sizes. Just know that there is a known issue where Safari rounds up percentages, which can cause weird behaviors when using fluid layouts.
Retina
If you build for iOS, you have to take retina into account. Spoiler: it's a pain.
The short version of how to deal with it is pretty straightforward: create images twice as big, call them my_image@2x.jpg and resize them in CSS.
Don't bother with normal size if all your images are in your build and not on a remote server. I would recommend always loading the @2x version. The rule of thumb is that if it looks fine in retina, it will look fine in 1x and embedding the 1x image will only increase your build's size and complicate the way you manage your assets.
Background Position
Be careful when using background positions with background sizes as they sometimes don't play well together.
1px Border
If you specify a 1px border in your CSS, a 2px border will be displayed on retina displays. Yeah, this is pretty unintuitive and a major pain. There are many ways to try to get this to work. This might not be the best solution for everyone, but for my use case, I found Stephan Bönnemann's solution simpler; I ended up adding a DOM element and styling it like this:
This is not ideal, but I wasn't a fan of the alternatives either. Check them out and make an opinion for yourself:
Performances
Avoid HTTP Calls
This seems obvious, but embed as many images and JavaScript libraries as possible in your build. It will run on mobile, and connectivity is an issue there. Yes, it increases build size, but it's totally worth it.
jQuery ?
I used jQuery. There, I said it.
I knew it would degrade performances, but I benchmarked it a bit versus Vanilla JS and the difference wasn't really noticeable for my use cases, so I kept it because I'm used to the syntax and it gets the job done.
Of course, I followed the usual performance tips: not too much DOM manipulation, don't reselect the same element over and over...