FunctionSource, Your Source for Developer News

A day in the life of Android WebKit dealings

Posted by Dion Almaer about a year ago on android

Android WebKit is the closest thing to being the IE6 of mobile development for me. Even though Android WebKit is getting better, so many people are on old fragmented versions of Android, so you still have to support the old stuff which is ripe with issues that raise their nasty head at every turn.

I was hacking on something simple last night that I think explains the situation.

I was working on a native+web application and was having fun with the fools errand that is “mimic native-land”. I wanted to take the same native button that was defined in Android via a 9 patch drawable. I was able to mimic the same button via a simple linear gradient:

border: 1px solid rgba(121,83,62,0.5);
color: #fff;
background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, rgb(246,171,89)), color-stop(0.5, rgb(242,117,54)), color-stop(0.51, rgb(242,104,31)), color-stop(1, rgb(242,131,73)));

NOTE: That sample is old school format. I am actually using stylus which kindly outputs various formats, but for the sample I am just sharing raw CSS.

The button also has rounded corners, which can easily be fixed with:

-webkit-border-radius: 5px;

So easy, as long as you squint. Android WebKit seems to do a pretty poor job and drawing the corners and the aliasing is very jagged. Oh well, what can you do (use an image :().

When you tap on the button, the default action in Android WebKit is to show a large highlight (often orange, but depends on the theme / version / device) around around the element. You can clean that up, along with making sure the user can’t select text within the button:


-webkit-tap-highlight-color: rgba(0,0,0,0);
-webkit-user-select: none;

That code makes it look like you can use any color you want. In Mobile Safari you can:

-webkit-tap-highlight-color: color;

Overrides the highlight color shown when the user taps a link or a JavaScript clickable element in Safari on iOS.

Not with Android. Now, since we have taken away the user feedback, we need to put in what we were showing on the native side, which is a darkening of the button.

First up, you need a way to tag the fact that the button is activated. A perfect job for the CSS :active right? Nope. That doesn’t work. :hover will actually do something, which seems funny for a touch device….. there is no hover!

This all means that you need to resort to JavaScript. For example, watch for touch start and end on the button:

$("#button").bind("touchstart", function(e) {
  $(this).addClass("active");
});
$("#button").bind("touchend", function(e) {
  $(this).removeClass("active");
});

What does the active CSS class do? At first it used a box-shadow, inset, with rgba(0,0,0,0.2) to give the shadow effect. Unfortunately there is another bug where box-shadow and border-radius blow up when used together. No border-radius and things work fine.

No problem though, I changed the active class to just use a darker linear gradient.

Finally, we got there, through a Web of bugs and “huh, really?”‘s. At least I hope so…. does anyone have a bunch of Android devices to help me test? :)

Once again, I can’t wait for Chrome for Android.

(below is a full example)

<!DOCTYPE html>
<html>
<head>
  <title>Android Style</title>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
</head>
<body>
<style type="text/css">
input[type=radio] {
  -webkit-tap-highlight-color: rgba(0,0,0,0);
}
input[type=button] {
  display: inline-block;
  padding: 9px 30px;
  font-family: "Droid Sans",Helvetica,Verdana;
  background-color: #f2681f;
  border: 1px solid rgba(121,83,62,0.5);
  color: #fff;
  background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, rgb(246,171,89)), color-stop(0.5, rgb(242,117,54)), color-stop(0.51, rgb(242,104,31)), color-stop(1, rgb(242,131,73)));
  -webkit-tap-highlight-color: rgba(0,0,0,0);
  -webkit-user-select: none;
  -webkit-border-radius: 5px;
}
#b.active {
  background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, rgb(181,139,89)), color-stop(0.5, rgb(217,104,48)), color-stop(0.51, rgb(217,94,28)), color-stop(1, rgb(217,118,64)));
}
</style>
<form>
  <input type="radio" name="r" value="whee">
  <input type="button" value="Continue" id="b">
</form>
<script>
$("#b").bind("touchstart", function(e) {
  $(this).addClass("active");
});
$("#b").bind("touchend", function(e) {
  $(this).removeClass("active");
});
</script>
</body>
</html>