Wednesday, November 9, 2011

Hide the URL Bar in Mobile Safari - Fast!

Damn you, 60 pixel URL bar.
As a web developer who's recently made the transition to working more on mobile, one of the APIs that I *really* wish mobile browser vendors would provide is one to hide the URL bar. At the moment I'm most concerned with our iOS users and reclaiming that 60 pixels at the top:



There are a lot of exhaustive and good posts about the hack to hide the navigation bar - using window.scrollTo(0, 0).

One thing that kept tripping me up in my own app was the fact that it's an absolutely positioned, full-screen web app - in other words, content did not naturally flow past the bottom of the viewport, so scrollTo wouldn't hide the bar unless I made the app the size of the screen minus the url bar and I didn't really want to set the body height in script after loading like some of the other examples I saw and which I found to be pretty brittle - client.innerHeight eat your heart out.

The other hassle I found was that event though I could get text on the screen and was deferring all scripts to the bottom of the page, there was no way to get the stupid bar to hide until the arbitrary body onload event finally hit.

Make BODY onload fire ASAP.
Ultimately my fix involved removing all the SCRIPT or IMG tags from the DOM initially, in other words anything that might prevent body onload from firing immediately. Now there's a single body onload listener which fires super fast and hides the navigation bar and *then* it uses LABjs to load/run any scripts. The following bit of CSS + SCRIPT ensures that the navigation bar goes away like lightning:

CSS:

/* Portrait mode */
@media screen and (max-width: 320px) {
  .container {
    min-height: 416px;  /* viewport 356px + 60px navigation bar */
  }
}
/* Landscape mode */
@media screen and (min-width: 321px) {
  .container {
    min-height: 268;  /* viewport 208px + 60px navigation bar */
  }
}
SCRIPT:
body.onload = function() {
  window.setTimeout(function() {
    window.scrollTo(0, 0);
  }, 0);
  window.setTimeout(function() {
    $LAB.setGlobalDefaults({
      'AlwaysPreserveOrder': true
    });
    $LAB.runQueue();
    {% if is_production %}
      $LAB.script('https://ssl.google-analytics.com/ga.js');
    {% endif %}
  }, 0);
}; 

My house, my rules, I win.
There are lots of good reasons to use a script loader if you have multiple scripts, but for my production app I have only one. Maybe the 5k hit of LABjs is unnecessary in production, but this seems an acceptable tradeoff at the moment - I really like the queueScript and queueWait API in LABjs.

Fortunately the loading spinner image in our CSS file doesn't hold up body onload, so the overall net effect is really lovely - URL bar gone, spinner spinning, code loading then running - ideal. This approach seems to get rid of the URL bar faster than any other app I've seen which does so (gmail, Financial Times, Twitter).

Monday, October 17, 2011

iOS5 in Private Browsing Mode

I love feature detection. Sometimes it fails you in a really unfortanate way.
Two examples of late


> window.localStorage
 ▶ StorageConstructor

> window.localStorage.setItem('foo', 'bar')
> Error: QUOTA_EXCEEDED_ERR: DOM Exception 22



Q: Guess what most libraries do to detect support?

A: if ('localStorage' in window)


Well, nothing a try catch can't fix.

/facepalm

Sunday, October 16, 2011

Hide the Mother Effing URL Bar

The should be an API for mobile browsers to do this. Can I get an amen?

Thursday, September 29, 2011

JavaScript testing with closure jsunit and Webdriver

I recently set about looking into JavaScript testing frameworks.

In the end it came down to comparing Pivotal Labs' Jasmine framework to Closure's JSUnit wrapper. I really wanted to use Jasmine, but had peculiar problems that may be due to my own code or my assumptions about how to use it. Stack traces were sometimes less than useful (except on Safari) in Jasmine and then I got stuck trying to load fixtures from files and having race conditions. Jasmine seemed to load and execute extremely fast, almost too fast, but anyhow, I couldn't get things working so I went back to the tried and true.

I should also maybe mention that I'm using Sinon.js as much as possible and *really* enjoying how it works.

One particularly nice thing about closure's test runner is that it's instrumented for Webdriver integration. I'm not a Java nut, so I wrote my webdriver test in python and wanted to share the code here because I had some trouble finding references online to working code.

Worth noting that I downloaded the chromedriver binary and actually checked it in next to my test but also have this code working with the Firefox driver as well as the iphone simulator, using iWebDriver (which is totally freakin cool).

Just sharing below in case anyone finds it interesting or useful.


#!/usr/bin/python2.5


__author__ = 'Lindsey Simon'


import os
import time


from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.common.keys import Keys


"""
The chromedriver binary (mac) will be able to run the tests.
For targeting an iphone simulator, one needs to follow the instructions
http://code.google.com/p/selenium/wiki/IPhoneDriver (we used iOS Latest).
Then you can start the simulator outside of XCode and leave the iWebTest
app running, targeting localhost in the webdriver.Remote below.
"""


TEST_PATH = os.path.dirname(os.path.abspath(__file__))




drivers = (
    # webdriver.Remote(command_executor='http://localhost:3001/hub',
    #                  desired_capabilities={'browserName': 'iphone'}),
    # webdriver.Firefox(),
    webdriver.Chrome(TEST_PATH + '/external/chromedriver')
    )


for driver in drivers:
    # These are test pages which include closure + jsunit to drive them.
    test_pages = ('test1.html', 'test2.html')
    test_results = []


    for test_page in test_pages:
        url = 'file://%s/%s' % (TEST_PATH, test_page)
        driver.get(url)
        
        # Freakin cool.
        while not driver.execute_script('return G_testRunner.isFinished()'):
            time.sleep(1)


        print '%s' % driver.execute_script(
            'return G_testRunner.getReport()')


        test_results.append(
            driver.execute_script('return G_testRunner.isSuccess()'))


    for test_result in test_results:
        assert test_result


    driver.quit()

Thursday, July 28, 2011

IE Results for Free & New Table Browsing Features

If you've made a UserTest on Browserscope, you know that one of the first things you want after doing the work of getting your test right is to see some real data! So you fire up a couple of browsers and boom, you've got a few rows. But that's not very likely to give you the spread that you're looking for. More often than not, because of its market share, I really want IE results. Yeah, I have 4 VMs I can fire up, but all in all that takes too damn long.

Enter today's WebPagetest.org integration! Now, from your settings page on Browserscope, there's a blue button you can use to trigger an IE 6, 7, 8, & 9 to automatically visit your test URL. We append a URL parameter (autorun=1) to your test URL so that you can be sure your test is being run under this context. Otherwise, it's generally better/nicer to use a button and prompt your user to run your test. ;)

Additionally, there's now a control in the results table that allows you to navigate through the browser lists as well as compare results for particular UAs and filter sparse results (results with some test count < X).

Hopefully these changes and improvements will help you to gather and navigate your data more easily.

Thursday, July 21, 2011

New Browserscope Visualizations

From the beginning of the Browserscope.org project we've wanted to come up with some visualizations that are more exciting than the compatibility tables. This week we've enabled two new ways to look at the data based on comparing browser releases over time.

The timeline visualization uses Highcharts JS which lets us plot splines with irregular intervals, a feature that several other timeline visualization libraries I looked at didn't offer. As you browse the categories on the site, you'll now get timelines above the results tables. Here's a timeline graph of Collin Jackson and Adam Barth's Security test results:



In general, things are looking up and to the right, which is a really good sign for the web. =)

You can get timeline visualization for any of browserscope's tests by hitting www.browserscope.org/timeline?category=[summary|security|richtext2|selectors|network|acid3|jskb].

This visualization also works for User Tests, which makes for some pretty cool graphs - check out the Modernizr timeline and their full compatibility table with automatic scoring and cell highlighting.

Additionally, I've been working with a really awesome developer named Nihar Kabinittal on a different visualization of this data - sometimes the timeline isn't enough fun. Our primary goals were to make a graphic that would be flexible to allow comparison of multiple browsers and versions and that would be instantly grokkable by both geeks and non-geeks. So here it is - this is Modernizr's data for top desktop browsers on Nihar's evolution visualization:



Want to build your own Browserscope test or create a visualization with the data? Learn more by reading the HOWTO.

Tuesday, May 31, 2011

DerrickSky Chocolates are Impeccable

When I first started working at Google, I was amazed by the variety of the cafes on campus. Some are clearly more mainstream than others, but they all serve impeccable food. Anyway, my favorite while I was actually living in Mountain View for two months was Slice Cafe - which serves primarily vegan and raw food. I'd never really had the opportunity to easily taste carefully prepared, fresh food in this style and wow - it really can be awesome. Sure it can sometimes seem reachy, as in trying to emulate things it's not, but you either are excited by this or irritated. As a major admirer of the art of magick and deception in food prep (think Chinese mock duck), I love it.

So I totally stalk the chefs. If I respect their dishes, I want to get to know them. After all, I used to be a cook, and these chefs have a lot of passions in common with me. Nowadays I mostly sling code, but I can't do it without great fuel - and you are what you eat. That's how I met Derrick Jones. Here's this mighty looking dude, serving up raw-violis with his partner in crime, Patrick. These gyus are like the dynamic duo, and they seem like really interesting peeps - so anyhow, I say hi, and chat when I'm in the cafe and live vicariously through their learning (by enjoying their work!)

Fast forward a couple of years, and Derrick's coming over to hang out and get me to try these chocolates he's been making. Me and my wife are floored. They're incredible - they're rich - they're nutritious. The chocolate has snap, it's not too sweet, and the flavor combinations are nothing short of gifted.

I'm going to highlight a few of my loves:

Chocolate Midnight Sky - soft, almost brownie-like, and fulfilling.

Mocha Vruffle - my first love, these are the most amazing blend of nibness with luscious chocolate.

Chocolate Graham Flax - slightly and magnificently crunchy, the name says it all


And the thing is, Derrick's *still* trying new combos. He dropped me off some "Cocoa Mocha Squared" bites and I'm just stunned - the man's got energy for life and passion for wholesome deliciousness coming from every pore in his body - and sincerely, easily.

I'm inspired. I'm delighted, and I'm honored to share with you the beauty that is Derrick Sky chocolates.

Friday, March 4, 2011

Black Trumpets in Mendocino
Yep, it's that time of year again, and it's amazing to live in California. These photos were taken with Angela's Nexus One and make me wish we'd brought our real camera along, but you get the idea. We were knee deep in trumpets - it took like 3 days to dry them all.

It's hard to beat the idyllic feeling of wandering around semi-aimlessly in a forest. There's this awesome quiet in the tall trees with the wind whistles through tanoak leaves and branches. Thank goodness Dr. Ryane Snow knows his way around so well in there, I could get lost for hours.