Wednesday, February 9, 2011

Code: Using JavaScript and CSS to Switch to and from a Mobile Site

There are many ways to detect an iPhone or other mobile browser on your website.  I chose JavaScript for my professional website because my webhost restricts the use of PHP.  (I'm not going to link to my website here because it needs some work.)

There are only a couple ways to set up a mobile version of a website.  Using two CSS files is the best method for small sites that don't have a lot of images to resize.  Alternatively, you can build a different site just for mobile browsers and redirect mobile users to that site.  Right now, I have one website with two CSS files, but eventually I will build a separate mobile site.

This guide is for users that have one version of a website, but two CSS files: one for the full site and one for the mobile site.  It shows you how to create dynamic links to the full site from the mobile site and vice versa.  I think it's really important for mobile users to have the choice to view a website's full site and the option to go back to the mobile site, but full browser users shouldn't be bothered with a link to the mobile site.  Surprisingly few websites do this.


Detecting Mobile Browsers Using JavaScript

This JavaScript code detects mobile browsers by checking the user agent string for the words "iPhone" or "iPod".

// Are we using iPhone or iPod to browse this site?
var mobileDetected = ( (navigator.userAgent.match(/iPhone/i) != null) || (navigator.userAgent.match(/iPod/i) != null) );



Selecting the CSS File

This code writes the code to select either the full site CSS file or the mobile CSS file based on whether or not a mobile browser was detected.  It also involves checking cookies, and I'll explain that later.

// If not on mobile or full site was selected, use full site css
if(!mobileDetected || getCookie("occSkipMobile") == "true") {
  document.write("<link rel='stylesheet' href='css.css'>");
} else { // else use mobile css
  document.write("<link rel='stylesheet' href='iphone.css'>");
}



Allowing Mobile Browsers Access to the Full Website

Now that we can detect mobile browsers and get them to use the mobile CSS file, we need a way to prevent our site from always doing this so that the mobile browser can also access the full site.  The way I do this is with cookies.  This HTML code displays the link to the full website:

<div class="mobileOnly"><br>
<br>
<a href="index.html" onClick="skipMobileSite()">go to full site</a>
</div>


Notice that this code is wrapped in a class called mobileOnly.  I ensure that only mobile browsers can see this text by making mobileOnly invisible in my full site CSS file:

/* Always hide this on normal site */
div.mobileOnly {
  display: none;
}


But in my mobile CSS file, mobileOnly is visible:

div.mobileOnly {
  display: inline;
  font-size: 25pt;
  font-style: italic;
  margin-bottom: 30px;
}


You'll notice that in the link to the full site, a JavaScript function skipMobileSite is called.  This sets the actual cookie:

function skipMobileSite() {
  // Skip mobile site with a cookie setting, no expiration date
  document.cookie = 'occSkipMobile=true; path=/';
}


Cookies with no expiration date expire when the user closes his browser.

So this link sets a cookie that tells us that the mobile user prefers to view the full website.  This means we need to check for this cookie every time this page is loaded.  That's what the getCookie function does in the "Selecting the CSS File" section.  When a cookie is found that states a user's preference for the full website, the full website CSS file is selected.  Here's an implementation of getCookie from quirksmode.org (paraphrased):

function getCookie(name) {
  var nameEQ = name + "=";
  var ca = document.cookie.split(';');
  for(var i=0; i < ca.length; i++) {
    var c = ca[i];
    while (c.charAt(0)==' ') { c = c.substring(1,c.length); }
    if (c.indexOf(nameEQ) == 0) { return c.substring(nameEQ.length,c.length); }
  }
  return null;
}


Let's look at that line for selecting the full CSS file again:

if(!mobileDetected || getCookie("occSkipMobile") == "true") {

So, if a mobile browser isn't detected, the full CSS file is selected.  Or if the full website cookie is set to "true", the full CSS file is selected.  Otherwise, we select the mobile CSS file.

Notice that the link to the full site links to "index.html", which is the page all this code is on.  It's just an easy way to refresh the page.  Alternatively, I could have linked to "#" and written a page refresh in the skipMobileSite function.


Allowing Mobile Browsers Access Back to the Mobile Website

Now we have two versions of one website where mobile users are automatically sent to the mobile version, but they can click a link that only they can see that will take them to the full website from that point on.  We just need to link back to the mobile site.

<script language="JavaScript">
<!--
  // only write this if we're on a mobile and deliberately selected full site
  if(mobileDetected && getCookie("occSkipMobile") == "true") {
    document.write("<a href='index.html' class='fullSiteOnly' onClick='allowMobileSite()'>go to mobile site</a>");
  }
//-->
</script>


document.write is only called when a mobile browser is detected and the full website cookie is set.  Just to be sure, the class is fullSiteOnly, which is invisible in the mobile CSS file:

/* Always hide this on mobile site */
div.fullSiteOnly {
  display: none;
}


but is visible in the full website CSS (there's no code in the full site CSS for this).  So this link is only visible to mobile browsers that have clicked "go to full site" and it calls a function called allowMobileSite before refreshing the page.  What does allowMobileSite do?  It simply removes the full website cookie by setting the cookie to an expired date:

function allowMobileSite() {
  // Just delete cookie by setting it to past date
  document.cookie = 'occSkipMobile=true; expires=Fri, 3 Aug 2001 20:47:11 UTC; path=/';
}



Result (click to enlarge pictures)



This is my website on a regular desktop computer. There are no links to a mobile or full website.
This is my website on an iPhone (two images have been combined to show the entire page).  By default, the mobile edition is showing.  Mobile-friendly CSS code allows for easy navigation on mobile browsers.  It contains a link to the full website at the bottom.
This is my website on an iPhone after clicking "go to full site".  It looks just like the website on a desktop computer, except for the link to the mobile site at the bottom.  If a user clicks that link, he will go back to the "mobile edition" of the site.

All the Code Together

Let's review the whole thing.  First the full website CSS file, css.css:

/* Always hide this on normal site */
div.mobileOnly {
  display: none;
}


Then the mobile CSS file, iphone.css:

div.mobileOnly {
  display: inline;
  font-size: 25pt;
  font-style: italic;
  margin-bottom: 30px;
}

/* Always hide this on mobile site */
div.fullSiteOnly {
  display: none;
}


And finally, the webpage, index.html.  First we define the JavaScript functions, then we detect mobile browsers, then we check the cookie and select a CSS file, and finally we dynamically create links to the full site and mobile site:

<script language="JavaScript">
<!--
function getCookie(name) {
  var nameEQ = name + "=";
  var ca = document.cookie.split(';');
  for(var i=0; i < ca.length; i++) {
    var c = ca[i];
    while (c.charAt(0)==' ') { c = c.substring(1,c.length); }
    if (c.indexOf(nameEQ) == 0) { return c.substring(nameEQ.length,c.length); }
  }
  return null;
}

function skipMobileSite() {
  // Skip mobile site with a cookie setting, no expiration date
  document.cookie = 'occSkipMobile=true; path=/';
}

function allowMobileSite() {
  // Just delete cookie by setting it to past date
  document.cookie = 'occSkipMobile=true; expires=Fri, 3 Aug 2001 20:47:11 UTC; path=/';
}

// Are we using iPhone or iPod to browse this site?
var mobileDetected = ( (navigator.userAgent.match(/iPhone/i) != null) || (navigator.userAgent.match(/iPod/i) != null) );

// If not on mobile or full site was selected, use full site css
if(!mobileDetected || getCookie("occSkipMobile") == "true") {
  document.write("<link rel='stylesheet' href='css.css'>");
} else { // else use mobile css
  document.write("<link rel='stylesheet' href='iphone.css'>");
}
//-->
</script>

<div class="mobileOnly"><br>
<br>
<a href="index.html" onClick="skipMobileSite()">go to full site</a>
</div>

<script language="JavaScript">
<!--
  // only write this if we're on a mobile and deliberately selected full site
  if(mobileDetected && getCookie("occSkipMobile") == "true") {
    document.write("<a href='index.html' class='fullSiteOnly' onClick='allowMobileSite()'>go to mobile site</a>");
  }
//-->
</script>



Just embed those code snippets in your respective CSS and HTML files, and mobile users visiting your website will be able to switch back and forth between the mobile and full websites with ease.

Although this article as a whole and the code on my professional website are protected by copyright, feel free to use and tweak any of the code examples written in this article.

6 comments:

  1. Up to the wee-hours I see. Great post. I've been curious as to how I might be able to do this without some wordpress plugin, and I wasn't sure how to do it with a hand-coded site. Nice. Thanks for the resource buddy!

    ReplyDelete
  2. This is awesome. Im going to try and incorporate this into an asp site im working on. ASP only site, with a redirect in place to the mobile site on a different server. I'll let you know how it goes. Thanks for this!

    ReplyDelete
  3. You're welcome. Hope it works for you!

    ReplyDelete
  4. hmm. Mines a little different, can you advise me on how to do it with these specs: Asp that wont let me run php on one server that has a "forward.js" file that it calls on for the existing mobile detect/redirect. that works fine, but i want to use this javascript to give them an option to view full site from the php server that holds the mobile site. Would i simply add the cookie as shown above, and remove the css options, replacing them with links to either full or mobile site?

    ReplyDelete
  5. You have two different servers, a PHP one and an ASP one? Sounds difficult already. But, from what I can tell, one javascript for both sites might work, if they both link to it. If not, don't use a javascript file, just embed the javascript in the page with <script> tags, like I do.

    If you're using two sites, you won't need all that CSS code. But you still will want to use some CSS on the Full Website (and some cookie action) for the "go to mobile site" link.

    ReplyDelete