UPDATED: March 13, 2016
I like using "user agent sniffing" to deliver highly optimized versions of a website to different devices. Doing so allows me to really optimize and improve the user experience. What happens though when a device slips through my detection strategy? Let's say it's brand-new and for whatever reason does not register as mobile yet. The end user then inadvertently receives the desktop version of a website – not a great user experience on mobile.
Ethan Marcotte, who many consider the father of responsive web design, echoes this sentiment in his book Responsive Web Design (p.96):
That’s not to say that mobile websites are inherently flawed, or that there aren’t valid business cases for creating them. But I do think fragmenting our content across different "device-optimized" experiences is a losing proposition, or at least an unsustainable one. As the past few years have shown us, we simply can’t compete with the pace of technology.
On the other hand, a purely responsive web design might deliver too much bloat for smaller devices with lower connection speeds, higher latency, and smaller CPUs. The idea of context sensitivity also comes into play. Perhaps your user needs are different on mobile than they are on a desktop because of the context in which they are viewing and using your application. On top of that, smaller devices require a lot more tweaks for device capabilities (from dumb phones to smart phones), and require developers to contend with a greater amount of screen size increments.
Ultimately trying to cover all input types and all user postures in a single interface is a daunting challenge. It’s hard enough to cover all the screen sizes and resolutions out there. Couple that with the fact that an interface that tries to be all things to all devices might ultimately not do a good job for any situation.
- Luke Wroblewski, Responsive Web Design: Relying Too Much on Screen Size, p.96
A Hybrid Approach
In the final analysis of mobile versus desktop, i.e. small screens versus large screens, it might be best to keep code bases separate, not just in separate stylesheets, or in hidden and conditionally loaded elements, but as separate systems entirely – with elements of device detection and responsive web design in both systems.
This is how such a system would work.
Large-screen System: A PC or laptop request for a webpage is received. Using device detection, a page designed primarily for desktops and laptops is served, while simultaneously responsive to tablets and phones.
Small-screen System: A mobile or tablet device request for a webpage is received Using device detection a page designed specifically for mobile is served, and responsive to mobile screen sizes only, i.e. not to larger screen sizes.
Through this hybrid approach responsive web design is provided for larger screens, and a separate responsive web design for small screen devices – that register as mobile via our user agent detection scheme.
Consequently, smaller devices would not receive any of the bloat that may be associated with the desktop versions of a website, and could also use the information available in user agent strings for even greater levels of adaptation and tweaking.
If a small screen device somehow makes it past our device detection and is served large screen views, the large-screen system is able to handle it using responsive web design. Although not optimal, it is adaptable.
In Rails implementing this hybrid system is pretty easy, IMHO. Sure we could use rails as a API server and have distinct clients for different scenarios, but doing so requires more resources, perhaps someone who is proficient in Ember/Angular/React/etc. or iOS/Android/Windows, but right off the bat this seems like overkill. Rails right out of the box and within the framework can handle the job. And because of inheritance we can share common elements between both systems, but keep things separate where it matters.
Will it be too much work to maintain both systems? I personally don't think so, and have done so in many projects with little issue. If you choose to use a hybrid approach here is how you could do it:
Create a user agent detection scheme in your application that serves specific files depending on user agent ("Mobile Device Detection with Ruby on Rails").
Create a primary Responsive Web Design implementation, the Large-screen System from above ("Responsive Web Design in Rails with Susy").
Create a second Responsive Web Design implementation specifically for small devices, the Small-screen System from above – in the same application.
To create the second RWD implementation specifically for small devices you are literally going to take all of the techniques you would follow in creating a regular RWD site, and repeat them for mobile.
If you implemented "Mobile Device Detection with Ruby on Rails," you will find four files with a "_susy" file name in your project:
These correspond with four files with the same name minus the
_susy part, the original files. Replace the original files with the files listed above, delete the original files and then rename the files listed above: remove the
Let's explore where this second RWD implementation will belong and how the hybrid system will work by reviewing the following Rails application's file structure (based on this, this and this):
The first column holds all of our stylesheets, the second column our views.
The Heart of the System
In Rails, when a webpage is served
application.html.erb is at the heart of what it is served ("Rails Views and the Foundation Code Structure"). It is the master layout template. It dictates what assets are served – like stylesheets and scripts – and what the page header will contain.
This gives us a tremendous amount of control, because through our user agent detection scheme we can tell Rails whether or not to serve the default application layout or something else, and consequently which associated assets.
Notice in the file structure image above that there are two main stylesheets (1):
application.css.scss which organizes and pulls together all the partials under the
phone.css.scss which organizes and pulls together all the partials under the
phone.css.scss is called through the mobile version of
application.html+phone.haml (2) and served only when the user agent detection scheme detects that the device is a mobile device.
application.css.scss is served as a result of the default
application.html.haml in all other cases.
The two folders in the stylesheet column,
phone (3) each contain the partials pertaining to
phone.css.scss (respectively). Partials common to both are found on the same directory level (4).
When it comes to desktop and laptop views – the "Large-screen System" – files are named
some_name.html.haml, while mobile related views – the "Small-screen System" – are named
some_name.html+phone.haml (5), the difference being the Rails variant naming syntax
For example, a
_logo.html.haml partial might be common to both systems, so there is no reason repeat it, however, a footer might be unique for mobile devices, therefore
_footer.html+phone.haml (the mobile version) supersedes
_footer.html.haml (default version) when a mobile device is detected.
When mobile views are not available –
some_name.html+phone.haml – through template inheritance Rails will look for a view with the same name , but without the
+phone naming syntax.
How will this work?
It all starts with the question, "Is the request coming from a mobile device?"
views/layouts/application.html+phone.haml will be served and through its stylesheet call:
= stylesheet_link_tag "phone"
phone.css.scss – the mobile stylesheet – will be included.
views/layouts/application.html.haml will be served along with the desktop optimized stylesheet
= stylesheet_link_tag "application"
What's the difference?
On all levels where it matters, one is coded with mobile in mind only, the other is not.
Compare the desktop and mobile versions of
head.html.haml (here and here) and you will see that they are significantly different from one another. One draws from regular HTML5 Boilerplate and the other from Mobile Boilerplate.
The desktop specific layout is designed to take advantage of the greater capabilities of devices with > 700-ish pixels screen widths.
If a false-positive squeaks by,
application.css.scss, the desktop stylesheet, is coded to handle the < 700-ish cases as well. Keep in mind though that desktop assets and elements will also be received by the smaller device and therefore the experience is not optimized, precisely why we have two systems, or at least one of the reasons.
The bottom line is that when our user agent detection scheme detects that a request is coming from a mobile device, Rails will serve mobile "stuff".
Armed with this we can create a second implementation of RWD under the
phone.css.scss stylesheet and all its partials, and by doing so will not affect our default RWD implementation. We can also tailor what HTML and assets are served depending on the device making the request.
This gives us a lot of control.
Using a hybrid system is like employing two gatekeepers. The first gatekeeper decides which system to serve the requester, and the second gatekeeper of the chosen system tailors display characteristics to the device making the request.
The best part of this hybrid approach is that both systems can use common components without losing the ability to fine-tune what is served to the end-user. It's there when you need it, and out of the way when you don't.
Want to know when the next article is published? Subscribe here. Thanks for reading!