title: javascript max viewport height after orientation change Android & iOS
body: <h2>The Goal:</h2>
  
  <p>To find the max viewport height of a device including the space of the <code>address bar</code> so that we can dynamically resize the min-body and push our content up.</p>
  
  <h2>The Problem:</h2>
  
  <p>Mobile browsers handle orientation states differently and update DOM properties on orientation change differently.</p>
  
  <p><a href="https://stackoverflow.com/questions/1649086/detect-rotation-of-android-phone-in-the-browser-with-javascript">Detect rotation of Android phone in the browser with JavaScript</a></p>
  
  <p>With Android phones, <code>screen.width</code> or <code>screen.height</code> also updates as the device is rotated.</p>
  
  <pre><code>|==============================================================================|
  |     Device     | Events Fired      | orientation | innerWidth | screen.width |
  |==============================================================================|
  | iPad 2         | resize            | 0           | 1024       | 768          |
  | (to landscape) | orientationchange | 90          | 1024       | 768          |
  |----------------+-------------------+-------------+------------+--------------|
  | iPad 2         | resize            | 90          | 768        | 768          |
  | (to portrait)  | orientationchange | 0           | 768        | 768          |
  |----------------+-------------------+-------------+------------+--------------|
  | iPhone 4       | resize            | 0           | 480        | 320          |
  | (to landscape) | orientationchange | 90          | 480        | 320          |
  |----------------+-------------------+-------------+------------+--------------|
  | iPhone 4       | resize            | 90          | 320        | 320          |
  | (to portrait)  | orientationchange | 0           | 320        | 320          |
  |----------------+-------------------+-------------+------------+--------------|
  | Droid phone    | orientationchange | 90          | 320        | 320          |
  | (to landscape) | resize            | 90          | 569        | 569          |
  |----------------+-------------------+-------------+------------+--------------|
  | Droid phone    | orientationchange | 0           | 569        | 569          |
  | (to portrait)  | resize            | 0           | 320        | 320          |
  </code></pre>
  
  <p>Because of this it is clear that to find the max viewport height no matter what orientation, using a single function to return the max height of a device will never be constant over a range of devices.</p>
  
  <p><strong>Other problems I have discovered that don't make these two play nice:</strong></p>
  
  <ul>
  <li>The <code>window.devicePixelRatio</code> property can return inconsistent heights
  when dividing by <code>window.outerHeight</code>.</li>
  <li>Delay <code>window.setTimeout(function() {}, time)</code> needs to be used to give DOM elements a chance to update after orientation change.</li>
  <li><code>window.outerHeight</code> is not updated on orientation changes for iOS devices. Using <code>screen.availHeight</code> as a fallback includes the bottom nav bar as total height.</li>
  <li>Using a <code>#header</code>, <code>#content</code>, <code>#footer</code> structure forces you to dynamically recalculate the <code>#content{min-height}</code> to push the <code>#footer</code> down when the <code>body</code> is dyamically updated.</li>
  </ul>
  
  <h2>A Solution:</h2>
  
  <p><strong>First let's take a look at DIV structure:</strong></p>
  
  <pre><code>&lt;style&gt;
  #header,#content,#footer{width:100%;}
  &lt;/style&gt;
  
  &lt;body&gt;
  &lt;div id="header"&gt;&lt;/div&gt;
  &lt;div id="content"&gt;&lt;/div&gt;
  &lt;div id="footer"&gt;&lt;/div&gt;
  &lt;/body&gt;
  </code></pre>
  
  <p><strong>We want to prevent devices from scaling on their own:</strong></p>
  
  <pre><code>&lt;meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" /&gt;
  </code></pre>
  
  <p><strong>We need help to have the ability to return a max viewport height and hide address bar for iOS:</strong></p>
  
  <pre><code>&lt;script src="iOS.js" type="text/javascript"&gt;&lt;/script&gt;
  </code></pre>
  
  <p><a href="http://iosjs.com/" rel="nofollow noreferrer">http://iosjs.com/</a></p>
  
  <p><strong>Then detect if the device supports orientation change and use resize as a fallback:</strong></p>
  
  <pre><code>var iOS = (navigator.userAgent.match(/(iPad|iPhone|iPod)/i) ? true : false);
  var android = (navigator.userAgent.match(/Android/i) ? true : false);
  var supportsOrientationChange = "onorientationchange" in window;
  var orientationEvent = supportsOrientationChange ? "orientationchange" : "resize"; 
  </code></pre>
  
  <p><strong>The belly of the beast:</strong>   </p>
  
  <pre><code>function updateOrientation()
  {
      var orientation = (window.orientation);
  
      if(android)
      {
          window.setTimeout(function() {
              window.scrollTo(0,0);
              var size = window.outerHeight/window.devicePixelRatio;
              $('body').css('min-height', size + 'px');
              var headerHeight = $('#header').height();
              var footerHeight = $('#footer').height();
              var contentHeight = size - (headerHeight+footerHeight);
              $('#content').css('min-height', contentHeight + 'px');
              window.scrollTo(0,1);
          }, 200);
      }
  
      if(iOS)
      {
          window.setTimeout(function(){
              window.scrollTo(0,0);
              var size = iOS_getViewportSize();
              var headerHeight = $('#header').height();
              var footerHeight = $('#footer').height();
              var contentHeight = size.height - (headerHeight+footerHeight);
              $('#content').css('min-height', contentHeight + 'px');
              window.scrollTo(0,1);
          }, 0);
      }
  }
  </code></pre>
  
  <p><strong>Add event listeners for page load and orientation event:</strong></p>
  
  <pre><code>if(iOS)
  {
      iOS_addEventListener(window, "load", iOS_handleWindowLoad);
      iOS_addEventListener(window, "orientationchange", iOS_handleOrientationChange);
      iOS_addEventListener(window, "resize", iOS_handleReize);
  }
  addEventListener("load", function() 
  {
      updateOrientation();
  }, false);
  addEventListener(orientationEvent, function() {
      updateOrientation();
  }, false);
  </code></pre>
  
  <h2>Proof is in the pudding:</h2>
  
  <p><strong>iPhone 4 &amp; 4s Portrait &amp; Landscape</strong></p>
  
  <p><img src="https://i.stack.imgur.com/IiE8m.png" alt="iPhone 4 &amp; 4s Portrait">
  <img src="https://i.stack.imgur.com/VqeGG.png" alt="iPhone 4 &amp; 4s Landscape"></p>
  
  <hr>
  
  <p><strong>Android Portrait &amp; Landscape</strong></p>
  
  <p><img src="https://i.stack.imgur.com/3LdRh.jpg" alt="Android Portrait">
  <img src="https://i.stack.imgur.com/kJNQ3.jpg" alt="Android Landscape"></p>
  
  <hr>
  
  <h2>The goal here is to minify this solution or make it better.</h2>