Sponsored by

  • Intel
  • HP

Web designHow to

Getting started with RESS

Getting started with RESS

This tutorial will teach you the basics of RESS (Responsive Design + Server Side Components) and how you can build a responsive page that works well on small screens with the help of server side technologies.

  • Knowledge needed: Basic PHP, basic responsive web design
  • Requires: PHP, Twitter Bootstrap, Modernizr, Swipe.js, WURFL
  • Project Time: 2-4 hours

I know that our industry doesn't need another acronym, but here is one more for you: RESS. RESS stands for "Responsive Design + Server Side components" and it is Luke Wroblewski that is guilty of making you learn yet another term. He didn't invent something new when he wrote an article about it back in September, but he put a name to something that many used to call a 'hybrid' solution before.

The idea behind it is that we combine responsive web design techniques and server side techniques to serve an optimal experience for each device. This means that we will serve slightly different requests to some devices for a given URL, but we still use responsive techniques for whatever ends up on those devices. The technique presented in this tutorial is a simple RESS solution that is meant to get you started in a short amount of time. We are going to build a single responsive page that includes some basic elements that are surprisingly complex to use on responsive sites: images, ads and social media widgets.

Advertisement

01. Responsive web design

Responsive web design needs no introduction, but you have probably noticed that most responsive techniques are only using client side code. And for a good reason. The code is based on web standards and if a new device or browser relates to these standards, our website will still work as intended. And this also means that we have one code base for all devices. And this part is both fantastic and a bit scary at the same time.

It works really well in many cases, but we also see some cases where the least capable browsers (often mobile) suffers from too much logic and content, poor usability and an overall slow experience.

02. Client, meet server

This is where the server can help out. The traditional way of building solutions for mobile or for a specific platform is to build either a separate mobile site or an app. Both methods are tailored for the specific device and it is also why they work so well for mobile (at least from an end users perspective). Both solutions also have drawbacks, as I am sure you are aware of, but they have a few things that many responsive websites don't have: optimisation for the device and speed.

It's not uncommon for a responsive website to be 2, 3 and even 4 megabytes and have hundreds of HTTP requests, and I can tell you right now that that is too much. The main idea about responsive web design is to not tailor for a specific device, but in some cases, it actually makes sense to do some opimisation on the server.

03. The setup

We'll create a simple PHP page (that looks a lot like a magazine frontpage ...). The site will have an image carousel, some advertising and some social media plug-ins. We will focus on making the site easy to set up and will use Twitter Bootstrap as a responsive framework. We'll use both feature and device detection. We'll also use Modernizer to help with feature detection and WURFL for device detection. We are going to detect the screen size of the device both server side and client side and are going to use this to make decisions about which images, ads and content we're going to serve to the user.

04. Feature detection and device detection

With this setup we have two sources of information about the browser. Modernizr is a feature detection framework that makes it easy to detect browser features. It simply runs a test in the browser to get a boolean answer as output: "does X work?" and the answer is mostly "true" or "false". The beauty of this is that it works on all browsers, also those that are not released yet. But it does not have much granularity, and the capabilities that are available is limited to what is possible to feature test. Examples of features that are possible to test include boxshadow, csstransitions, touch, rgba, geolocations and so on.

Device detection on the other hand, is something different. It all happens on the server and it's a framework that analyses the HTTP header of the device. It then looks up in a database of known devices and return a set of capabilities for that device. The beauty of this is that it's a database of information that is collected and maintained by humans and it can hold incredibly detailed information about capabilities that is currently impossible to feature test. Examples include device type (desktop, TV, mobile, tablet), device marketing name, video codec support and so on.

The downside is that User Agent analysis can go wrong some times and many devices tend to have a non unique UA string or to fake the UA string, but using a framework will minimise the rist of false detection. Device detection and feature detection cannot really be set up against each other as they are not two sides of the same coin.

05. The demo site

Let's start coding! I will show you how you can use RESS to solve three common problems: ads, images and social media plug-ins. The demo site we'll build is at andmag.se/ress/ and all the code is available in a Github repo.

We'll start by downloading and setting up the tools we are going to use. We won't focus too much on the responsive code in this tutorial and we'll use Twitter Bootstrap to help us out there.

You need to download the Bootstrap files and unzip the package. Bootstrap contains a JS, CSS and IMG folder and we will put this in a "bootstrap" folder in our empty project.

Next, we need to get the device detection up and going. We will use the ScientiaMobile WURFL Cloud offering for this. WURFL stands for Wireless Universal Resource File and WURFL is one of the most used device detection systems out there. You need to sign up with ScientiaMobile to get an API key and then you can download the cloud client. There are different versions depending on site traffic and the number of capabilities that you want. I'm using the standard version, but there's also a free version that you can use. After you have signed up, go to your account settings and download the PHP client code and put the code in a folder called "WURFL".

When that is done, we are ready to start adding code. We will focus on keeping things simple and will create a simple file structure. We'll also create our own CSS, JavaScript and image folders. We will only create a frontpage in this example and all the code goes in index.php. We'll use PHP's "include" method to include other files to avoid having all the code in the same file. index.php includes header.php and footer.php along with the fragments of the page. header.php also includes WURFL.php and RESS.php. Soon we'll see what these files will do.

06. WURFL.php

WURFL.php includes the code to initialise the WURFL client and will store the capabilities that you have access to in an PHP array.

  <?php
    // Include the WURFL Cloud Client
    require_once 'WURFL/Client/Client.php';
     
    // Create a configuration object
    $config = new WurflCloud_Client_Config();
     
    // Set your WURFL Cloud API Key - Change this to your own key
    $config->api_key = '12345:abcDEFabcDEFabcDEFabcDEF';
     
    // Create the WURFL Cloud Client
    $client = new WurflCloud_Client_Client($config);
     
    // Detect your device
    $client->detectDevice();
    ?>

After the client is initialised, we can start getting information about the device that is currently using the site anywhere in the code:

      <?php
    $client->getDeviceCapability('brand_name');
    ?>

07. RESS

We're now going to build a way to combine client and server detection. We'll use a cookie to share information from the client to the server. The most important capability for this test is the screen width, so we create a RESS.php file with some JavaScript that detects the screen size for us. We also create a RESS namespace and a writeCookie() helper method. We can then get the width and write the cookie to the client:

    <script type="text/javascript">
     
    RESS = {};
     
    RESS.writeCookie = function (name, value) { //cookie code }
     
    //Store width in a cookie
    RESS.storeSizes = function () {
        //Get screen width
        var width = window.innerWidth;
     
        // Set a cookie with the client side capabilities.
        RESS.writeCookie("RESS", "width." + width);
    }
     
    RESS.storeSizes();
    </script>

We also register an onresize event, so that we can write the cookie when the window has changed size or the device has changed orientation, not only on a new page load. The onresize event tends to be very trigger happy so we wait one second before we write the new value.

    RESS.isResizeActive = false;
     
    window.onresize = function (event) {
        if (!RESS.isResizeActive) {
            RESS.isResizeActive = true;
     
            //make sure we do not do this too often, wait 1 second...
            window.setTimeout(function () {
                RESS.storeSizes();
                RESS.isResizeActive = false;
            }, 1000);
        }
    }    
   

Next, we need some PHP code to read the cookie, so that we can make the screen width available client side as well.

    $RESSCookie = $_COOKIE['RESS'];
    if ($RESSCookie) {
        $RESSValues = explode('|', $RESSCookie);
        $featureCapabilities;
        foreach ($RESSValues as $RESSValue) {
            $capability = explode('.', $RESSValue);
            $featureCapabilities[$capability[0]] = $capability[1];
        }
    }       

We will also get the server side width as a fallback. This is important as it will be used when we don't have access to the cookie on the first page load or if cookies or JavaScript is disabled.

$WURFLWidth = $client->getDeviceCapability('max_image_width');
if ($client->getDeviceCapability('ux_full_desktop')) {
    $WURFLWidth = 1440;
}   

WURFL's default screen width for "desktop" is 600 so we make sure we default to a large size and let the responsive code handle the screen size if it is smaller. And based on this we can now get the screen width server side and with a fallback to the WURFL width:

 $defaultWidth = ($featureCapabilities["width"] ? $featureCapabilities["width"] : $WURFLWidth);

08. Images

Tired of hearing "responsive images" yet? Thought so. The discussion about how to handle images for different screen resolutions has been going on for some time now. Mat Marquis sums it all up nicely in his article The state of responsive images.

We're going to use our RESS screen width in order to serve different images to different screen sizes. We're using Flickr images for our carousel and we choose three of their default sizes: 320, 500, 640 and we create a new size: 770, which is the max of our carousel. There are some differences in how wide the carousel is going to be in different breakpoints and we try to consider that in the algorithm. Also note that we are going to serve an image that is slightly larger than what we are going to use. This is because we want the image to work well in landscape mode as well. If we have a 320 pixel screen width, the height or portrait width is 480 so the 500 image is the best match for such a device (based on the Flickr formats). There is room for optimisation here and you are welcome to change the code and serve smaller images if you would like that. Here is the code:

       //select correct image version
    if ($defaultWidth < 320) {
        //small screens get 320 image
        $imageVersion = "320";
    } else if ($defaultWidth < 500) {
        //320-499 screens get 500
        $imageVersion = "500";
    } else if ($defaultWidth <= 1024) {
        //screens between 500 and 1024 get 640
        $imageVersion = "640";
    } else {
        //anything >= 1024 get 770
        $imageVersion = "770";
    }

We will now expose our calculations in a global RESS variable:

    global $RESS;
    $RESS = array(
        "width" => $defaultWidth,
        "imageVersion" => $imageVersion);

And we can now easily get the values server side and use this in our code.

    <?php echo $RESS["width"] ?>
    <?php echo $RESS["imageVersion"] ?>

09. The carousel

Ok, we have everything set up now and are ready to start using it. In order to put a carousel up on the site we will use swipe.js and we also need Modernizr to know if we should enable CSS transitions or not. Also, we will try and pick the correct image version for the device. We use the four image version we decided upon and store them in our img folder:

    img1_320.jpg
    img1_500.jpg
    img1_640.jpg
    img1_770.jpg

Based on this, we can now use our RESS variable to pick the correct version:

 <img src="img/img1_<?php echo $RESS["imageVersion"]?>.jpg" alt="First Image">

After applying some styles, we now have a working carousel with variable image size! You can also have a different crop of the image for different screen sizes if you wish that. See full code for the carousel here.

10. Ads

One of the problems with ad networks is that most of them only provide fixed sized ads. We're going to include those fixed sized ads on our responsive site, but we use RESS to include different sizes depending on the screen size we are dealing with. We're going to use Google AdSense and we will place an ad in the header of the page next to the logo. We use the same technique as when we served different image versions. We will have a 320px ad above the logo on small screens, a larger 468px ad on the right side of the logo on medium screens and finally a large 728px ad on the right side of the logo for large screens. Here is the code:

       <?php
    if ($RESS["width"] >= 320 && $RESS["width"] <= 640) {
        ?>
        <div class="mobile-ad max-320">
        <?php include "fragments/ads/320.php"?>
        </div>
        <?php
    }?>
     
    <div id="site-logo">
        <a href="/ress/">RESS</a>
    </div>
     
    <div class="ad">
        <?php
        if ($RESS["width"] >= 980) {
            ?>
            <div class="max-980">
                <?php include "fragments/ads/728.php"?>
            </div>
            <?php
        } else if ($RESS["width"] >= 768) {
            ?>
            <div class="max-768">
                <?php include "fragments/ads/468.php"?>
            </div>
            <?php
        }
        ?>
    </div>

Note that we have a media query that will hide the ad if the ad gets below the specified width. The ad is visible by default and we hide it for screen sizes that are less than 980px, in other words, max 979 pixels. The ad is hidden if the device width decrease without a reload, but if you reload the page you will get a different ad size.

    @media screen and (max-width: 979px) {
        .max-980 {
            display: none !important;
        }
    }

Hiding content with display none is normally a big "no-no", but remember that it's only hidden if the screen size changes dramatically and it's only responsive web design developers that change their browser window on every website they see anyway ...

11. Conditional content inclusion

As you start to understand by now, we can easily write conditional code on the server and we can do a lot of dirty things ... One thing is to remove content for smaller screens. Some types of content are simply not worth the cost on mobile, such as social media widgets in this case. We can debate on removing them all together from our site (we probably should). Here are the code for the right column of our page:

    <?php include "fragments/archive.php"?>
    <?php if ($RESS["width"] >= 768) { ?>
        <div class="max-768">
            <h2>Social</h2>
            <?php include "fragments/twitter-search.php"?>
            <?php include "fragments/facebook.php"?>
        </div>
    <?php}?> 

So we only include these fragments if the screen is 768 pixels or greater. Having the logic set on such a rule means that we take a step out of the fully responsive world in order to acheive a performance gain on mobile. Devices such as the Kindle Fire that has a 600x1024px screen won't load the Twitter and Facebook fragments in portrait, but it will load them in landscape. Odd things like this will happen, but that is the price we have to pay. Luckily there is a solution and it's called progressive enhancement. It should be easy to load the missing content once the screen is made wider again. Again, you should think twice about this stuff as it will probably confuse your user, but read on and have a look at the performance gain of this technique.

We are currently using screen width for all our decisions, but we could just as well be using other capabilities such as the new Network Information API.

12. Performance

So how does our approach affect the performance of the site? Here are some tests from three different breakpoints let's call them, Large, Medium and Small. (Note that the code on the demo site is not minified to make it easier to read and debug):

  • Large: 84 requests, 696KB transferred | 2-6s (onload: 1-3s, DOMContentLoaded: 600ms-3s).
  • Medium: 84 requests, 685KB transferred | 2-6s (onload: 1-3s, DOMContentLoaded: 600ms-3s).
  • Small: 25 requests, 221KB transferred | 560ms (onload: 580ms, DOMContentLoaded: 320ms).

So the large site is three times the size of the small site, both in size and in number of requests! The difference in image size from the three 500px image to the larger 770px image is 60KB. So it's the social widgets that are actually making the site big, not the images. But size itself is not the only issue here, the amount of connections is also troublesome and they come only from the social widgets. The images are also heavily optimised from the original version by using Photoshop and ImageOptim.

13.Conclusion

We now have a basic RESS setup and it should be easy to include this in your current site or even in a PHP CMS such as Wordpress or Drupal. The technique may go against some of the things you have learned in your RWD class, but in many cases it is much more efficient (both for you and for the browser) to put the logic on the server. I've also found that this gives an increased flexibility since you can add or remove content for specific devices and you can use third party solutions that are not mobile friendly by serving alternative solutions on small screens.

Progressive Enhancement is a central part of responsive web design and can also be used together with RESS and a natuaral extension to our content inclusion demo is to include content with JavaScript when the screen size increases. You also need to be aware that we are now serving slightly different content on the same URL and that this can affect your cache. There are solutons for how to address this issue but that is out of scope for this tutorial.

14. Further reading

You also might want to check out other work on RESS: Detector by Dave Olssen and the presentation Adaptation: Why responsive design actually begins on the server by Yiibu as well as the original RESS article by Luke Wroblewski.

Anders M Andersen - andmag.se - lives, works and plays in Stockholm, Sweden. He has been doing mobile development since WML and is currently trying to get that "responsive thing" to work better for mobile devices. Catch up with Anders on Twitter as @andmag.

 

Liked this? Read these!

Log in to Creative Bloq with your preferred social network to comment

OR

Log in with your Creative Bloq account

site stat collection