You can’t just wrap old websites in bootstrap and call it a day

Just because you wrapped an existing website in bootstrap doesn’t necessarily mean it’s ready for use on mobile devices. This is especially true if the website was originally designed for desktop browsers. Yes, bootstrap can significantly improve the user interface and make it flexible across multiple screen sizes. But it’s also up to you to roll up your sleeves and make sure the code behind the scenes is also worthy of being mobile-ready.

So, here are a three challenges to consider that will help keep your smartphone using visitors happy.

Challenge 1 – The internet connection on mobile devices is not as reliable as your home or office wired network. That’s a fact. Download speeds can and will vary significantly. The larger the website in MBs, the more links it has to download, the more non-optimized images then the longer it will take to render and become ready for use, especially on a mobile device. And mobile users are a very impatient bunch when it comes to sluggishness.

Size does matter with web sites. Smaller sized files download faster. The fewer number of files that make up a website also means faster downloads. Optimize, optimize and optimize some more. Minify files. Combine multiple files into one. Optimize images for web display.

Challenge 2 – Site navigation needs to be rethought and resized with mobile users in mind. Modern mobile devices use finger-based navigation, as opposed to high-precision mouse pointers. Teeny, tiny buttons or links that look cool on an ultra-high resolution MacBook retina screen positively suck when you are trying multiple times to click on them with your fingertip. On some websites using desktop navigational elements on your phone becomes like a macabre video game as you repeatedly play hit-or-miss with your fingertips.

Mobile websites should be finger lickin’ good. Okay, maybe you don’t really have to lick your fingers, but at least right size your navigational elements while keeping people’s fingers in mind. And fingers come in all shapes, sizes and levels of dexterity. Bootstrap can help with this.

Furthermore, your design and testing should work equally well in both portrait and landscape modes (phone right side up or phone on its side), and you should be able to switch back and forth seamless between the two modes in the same browser session.

Challenge 3 – Mobile devices are significantly more sensitive to browser memory leaks and bloated web pages. The mobile operating system will simply kill of any app that it deems to be using too much memory. And most of us are simply not good stewards at keeping our mobile browsers tuned up and happy. Browser caches grow huge and don’t get cleaned out regularly; we keep too many tabs open and probably have more information in our browser history than the library of congress. To further add to our woes, many of us let our phones run for weeks without a restart which can allow memory leakage to grow over time.

Tweak as many aspects of web page performance that your time will allow. Optimize old code by re-writing and striving to add new efficiencies. I know it may sound crazy, but if your site is particularly large and complex then consider creating focused, mobile-only sites that have scaled down content, rather than trying the one-size fits all approach. Smaller sites not only load faster but they are easier to navigate, take up less memory and typically perform better.

Tips for loading jQuery in mobile apps

Whether you are using jQuery by itself or with Bootstrap there are a few things to remember if you don’t want to see the following error: “Uncaught ReferenceError: $ is not defined”.  This error happens because you are trying to access jQuery before the library has finished loading. There are several ways to fix the error.

Encapsulate jQuery functionality inside a function. This keeps the parser from attempting to execute any jQuery until the function is explicitly called and it allows us to place the script tag at the bottom of the app. This approach can get tricky if jQuery is slow to load. It’s possible that the button can be visible and clickable before jQuery has finished loading. If this happens your app will throw an error. You can try it out in jsfiddle here.


<!DOCTYPE html>
<head lang="en">
    <title>jQuery Test</title>
</head>
<body>

<button id="button1">Click me</button>
<div id="div1" style="background:blue;height:100px;width:100px;position:absolute;"></div>
<script>

    // Test if jQuery is available
    if(typeof jQuery !== 'undefined'){
        console.log("jQuery has been loaded");
    }
    else{
        console.log("jQuery has not been loaded");
    }

    document.getElementById("button1").onclick = function(){
        $( "#div1" ).animate({
            left: "250px",
            height:'150px',
            width:'150px'
        });
    };

</script>
<!-- Everything above this will load first! -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js" ></script>
</body>
</html>

Use the script tag onload event to initialize jQuery functionality. This follows the guidelines of the first suggestion above and then waits to fire off any functionality until after the jQuery library has completed loading. This insures jQuery is loaded before it can be used. You can try it out in jsfiddle here.

<!DOCTYPE html>
<head lang="en">
    <title>jQuery Test</title>
</head>
<body>
<div id="div1" style="background:blue;height:100px;width:100px;position:absolute;"></div>
<script>

    // Test if jQuery is available
    if(typeof jQuery !== 'undefined'){
        console.log("jQuery has been loaded");
    }
    else{
        console.log("jQuery has not been loaded");
    }

    // Run this function as soon as jQuery loads
    function ready(){
        $( "#div1" ).animate({
            left: "250px",
            height:'150px',
            width:'150px'
        });
    }

</script>
<!-- Everything above this will load first! -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js" onload="ready()" ></script>
</body>
</html>

Place script tag in head. Sometimes lifecycle issues in mobile web apps will require us to simply load jQuery from the head of the web app. Because this forces jQuery to load synchronously before any user interface elements we pretty much guarantee that jQuery will be available when we run JavaScript within the body of the application. Try it out in jsfiddle here.


<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>jQuery Test</title>
    <!-- Block DOM loading until jQuery is loaded -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
</head>
<body>
    <button id="button1">Click me</button>
    <script>

        // Test if jQuery is available
        if(typeof jQuery !== 'undefined'){
            console.log("jQuery has been loaded");
        }
        else{
            console.log("jQuery has not been loaded");
        }

        // Page is fully loaded including any graphics
        $(window).load(function() {
            console.log("window.load worked!");
        });

        // According to jQuery docs this is equivalent
        // to the generic anonymous function below
        $(document).ready(function() {
            console.log("document.ready worked!");
        });

        // The DOM has been loaded and can be accessed
        $(function() {
            console.log("DOM loaded worked!");
        });

        $( "#button1" ).click(function() {
            alert( "Handler for .click() called." );
        });

    </script>
</body>
</html>

Offline JavaScript Part 2 – Overview of Interfaces and APIs

In Part 1 we looked at the differences between partial and fully offline use cases. Part 2 provides an overview of the HTML5 Interfaces and JavaScript APIs that make it possible to go offline with web applications. Going offline involves working with multiple pieces and coding for specific patterns. I’ve tried my best to stick to technology that is widely available across the largest variety of browsers.

Offline dependencies

Offline web applications are dependent on three things.  It doesn’t matter if your application is partially or fully offline, you’ll still need to address these in your code.

  • Caching HTML, CSS and JavaScript
  • Data Storage
  • Offline/Online detection

Caching

Application Cache. The Application Cache, or AppCache, interface lets you specify and store HTML and CSS files as well as JavaScript libraries so that they are available from the browser’s native cache. Once an item is in the cache the browser will use it regardless of whether it’s online or offline. It’s almost like you never went offline!

The AppCache is an essential part of your application strategy for allowing offline browser reloads or restarts. Without this an application will simply fail to re-load while offline.

Data Storage

Browsers have a variety built-in JavaScript APIs for storing data. The data can be for maintaining the applications state such as for storing bookmarks and form data. Or, it can be used for storing information such as maps, address and phone lists, TO-DOs or points of interest for a vacation.

LocalStorage. The LocalStorage API is super-easy to use. It stores Strings in simple key/value pairs. It’s limited to about 5MBs on most browsers. The two main challenges you’ll run into with LocalStorage are hitting the storage limit and performance hits when serializing and deserializing data.

IndexedDB. IndexedDB is essentially an asynchronous noSQL database that lets you store a wide variety of datatypes so that you don’t have to deal with serialization/deserialization.  Datatypes include String, Object, Array, Blob, ArrayBuffer, Uint8Array and File. While many online sources will tell you that there isn’t a size limit, I’ll tell you that in general you should limit your storage on a mobile device around 50 – 100MBs to help prevent the browser from crashing.

WebSql. It’s widely recommended that you not build applications directly on WebSql. The World Wide Web Consortium (W3C) is letting this standard die off in favor of IndexedDB and LocalStorage. I’m really only including this here for reasons such as Safari 7 and and the Android native browsers before 4.4 only support WebSql. For more information on how to get around this read down to the section on IndexedDBShim.

3rd Party Browser Storage

If the built-in browser storage capabilities aren’t meeting your needs you still have other options.

IndexedDBShim. IndexedDBshim is a Polyfill for WebSQL-based browsers. Because IndexedDB isn’t natively supported on older versions Safari 7 and Opera you can use this 3rd party shim to transparently translate your IndexedDB code to work across Android and iOS.

PouchDB. PouchDB is an Open Source experimental library that is an attempt to smooth some of IndexedDB’s rough edges as well as provide additional functionality, such as the ability to sync with remote stores.

LocalForage (Mozilla).  LocalForage is also an attempt to bridge the gap between LocalStorage and IndexedDB. It gives you an interface that provides much wider browser coverage than IndexedDB by itself.  One of the downsides is the amount of storage you can use. If a user is on an older browser such as IE8 that’s limited to LocalStorage then that user will be limited to storing about 5MBs of data. If you requirements call for using more than that, such as downloading large address lists, then the app won’t work on that browser or you’ll have to build in some sort of paging mechanism that deletes the old data and brings in the new.

Offline/Online Detection

There are a number of ways to detect if the browser is online or offline as well as when the internet status changes.

NavigatorOnline.online.  Some browsers have a built-in detection mechanism. However, it is not always reliable and false positives are a distinct possibility. For that reason, you will have to build additional detection capabilities or lean towards a 3rd party library.

Offline.js. Offline.js is a small Open Source library (~3KB) that detects when you lose an internet connection and when it comes back up. While not perfect, it does handle a lot of cross-browser compatibility issues for you. And, if you find bugs you can always create a fix and submit pull requests.

References

Caniseuse – IndexedDB

Caniuse – LocalStorage

Caniuse – WebSQL

Let’s Take This Offline