Doing it right: skipping the iPhone url bar

Important: As of iOS7, this technique no longer works (because Apple “fixed” it).

With some mobile web sites when visited on the iPhone, you may want to skip past the url bar (something I’m not sure if it’s possible, or even worth doing on other mobiles). There’s a simple solution to doing this, but doing it right is the real trick.

Below are two screenshots from the mobile view of Full Frontal, my JavaScript conference:

Full Frontal with the url barFull Frontal without the url bar

Making the iPhone hide the url bar is fairly simple, you need run the following JavaScript:

window.scrollTo(0, 1);

However there’s the question of when? You have to do this once the height is correct so that the iPhone can scroll to the first pixel of the document, otherwise it will try, then the height will load forcing the url bar back in to view.

You could wait until the images have loaded and the window.onload event fires, but this doesn’t always work, if everything is cached, the event fires too early and the scrollTo never has a chance to jump. Here’s an example using window.onload: http://jsbin.com/edifu4/4/

I personally use a timer for 1 second – which is enough time on a mobile device while you wait to render, but long enough that it doesn’t fire too early:

setTimeout(function () {
  window.scrollTo(0, 1);
}, 1000);

However, you only want this to setup if it’s an iPhone (or just mobile) browser, so a sneaky sniff (I don’t generally encourage this, but I’m comfortable with this to prevent “normal” desktop browsers from jumping one pixel):

/mobile/i.test(navigator.userAgent) && setTimeout(function () {
  window.scrollTo(0, 1);
}, 1000);

The very last part of this, and this is the part that seems to be missing from some examples I’ve seen around the web is this: if the user specifically linked to a url fragment, i.e. the url has a hash on it, you don’t want to jump. So if I navigate to http://full-frontal.org/tickets#dayconf – I want the browser to scroll naturally to the element whose id is dayconf, and not jump to the top using scrollTo(0, 1):

/mobi/i.test(navigator.userAgent) && !location.hash && setTimeout(function () {
  if (!pageYOffset) window.scrollTo(0, 1);
}, 1000);
Updated 24-July-2012 added Daniel’s Davis’ suggestion so this doesn’t match Opera Mobile. In fact it’s worth noting this only works on an iPhone Safari browser (and Android Browser – but not Chrome for Android?) – so perhaps we could tighten the nasty browser sniffing further?

Try this out on an iPhone (or simulator) http://jsbin.com/edifu4/10 and you’ll see it will only scroll when you’ve landed on the page without a url fragment.

18 Responses to “Doing it right: skipping the iPhone url bar”

  1. You also don’t want to scroll if the user has manually scrolled the page before onload. I add another check ( && document.documentElement.scrollTop === 0 ) to prevent this.

  2. You probably don’t want to jump if they’ve scrolled anywhere in that 1 second either!

    /mobile/i.test(navigator.userAgent) && !pageYOffset && !location.hash && setTimeout(function () {
      window.scrollTo(0, 1);
    }, 1000);​
    
  3. Is there any way, how to hide the bottom navigation bar on iPhone?

    We are redesigning our mobile web gallery and would love to display biggest photo size possible.

    thanks

  4. If you don’t want to lose that 1 pixel at the top use

    window.scrollTo(0,0)

    ;)

    Also, window.onload waits for all images to load before firing so the 1sec shouldn’t be necessary.

  5. I’ve implemented this code exactly as it reads below:

    /mobile/i.test(navigator.userAgent) && setTimeout(function () {
      window.scrollTo(0, 0);
    }, 1000);

    …in a mobile html site that calls a linked js file for all it’s javascript needs, and it doesn’t seem to do much of anything at all. Nav bar is still at the top, I’ve cleared the cache about 5 times already and reloaded. I’m using Safari on iPhone OS 4.0.1

  6. I believe this version is better. It waits until *after* the 1 second to test if the user has already begun scrolling.

    
    /iPhone/.test(MBP.ua) && !location.hash && setTimeout(function () {
      if (!pageYOffset) window.scrollTo(0, 1);
    }, 1000);
    
  7. @Simon East – good point and spot on – I’m updating the post to reflect that.

  8. off-topic entirely but curious why use you this pattern (condition) && action() as well as if (condition) action()? cool kids go for consistency. [edit] guess it’s a copy paste thing, carry on.

  9. +1 to Jesse’s comment – it should be changed to window.scrollTo(0, 0) so it’s doesn’t cut off the top 1 pixel. I think it’s not so noticeable on most designs, but it’s actually noticeable on designs with an image at the top with no padding/margin.

  10. @Kirvin Make sure that you actually have content to scroll. I was testing a page who’s elements were probably around 100px in height total; nothing to scroll. It won’t appear to work if there is nothing to scroll to.

  11. I’m using iScroll4 to scroll the content so my total body height is not large enough to do the scrollTo. I can trick it by adding an extra 64px (iphone navbar height) to the body using javascript, but that’s not crossbrowser.

    Have any ideas for this?

  12. I notice this technique does not work with iPads, even on 2011.full-frontal.org. Should it?

  13. @George – IIRC it did work on pre-iOS5 – but now they’ve got tabs, no, it doesn’t.

  14. Handy script. Unfortunately the browser-sniffing regex fails for Opera Mobile (which has “Opera Mobi” in the user agent). Could it be changed to /mobi/i please?
    Alternatively, as the script is designed primarily for screens with reduced height, maybe window.innerHeight <= 480 (or similar) would be better?

  15. The user scroll test has a side effect that when iphone is turned from portrait to landscape the pageYOffset wil no longer be 0 or false and so the function won’t run after view mode has changed to update the position of page. You can see the problem on this page that first heading gets partially hidden after changing to landscape mode. The problem wouldn’t occur if we don’t use pageYOffset.
    http://sandbox.saeidmohadjer.com/mobile/retina_display_support.html

    To detect user scrolling, I decided to rely on touchmove event instead of pageYOffset like this:

    
    var userHasNotScrolled = true;
    $(window).on('touchmove', function(e) {
    	userHasNotScrolled = false;
    });
    
  16. This seems like a great idea, but when I tested it on my site I found that once the scrollTo has executed, the URL bar is still visible for 3-4 seconds. During those 3-4 seconds the top of the page is hidden by the URL bar, which might lead the user to think the page is broken, or prompt them to scroll down to see what the URL bar is hiding!

    I’ve tested it using Safari on an iPod touch 2 and an iPhone 5. I don’t suppose there’s a way to speed up the disappearance of the URL bar…?

  17. Just f.y.i. – I upgraded to iOS7 this morning, and was trying this technique out, and with the new url bar that sort of fades and shrinks as you scroll down – it doesn’t work. The 1 pixel is not enough here, and so I figured out that the url bar is “minimized” fully at about 48px – but simply setting
    window.scrollTo(0, 48)
    is no good either – one because then anyone not using iOS7 has a big jump for no reason, and also because this paralaxy url bar minimizing seems to be triggered specifically by the page scroll, because loading the page and offsetting it by 48 pixels still doesn’t start you off with the url bar minimized.

  18. Hi – for anyone reading there’s now a meta-tag for iOS 7.1 ‘minimal-ui’ – check out http://www.mobilexweb.com/blog/ios-7-1-safari-minimal-ui-bugs

Leave a Reply
Not required

CODE: Please escape code and wrap in <pre><code>, doing so will automatically syntax highlight