#Conditional DOM Insertion#
HTML and the web embraces a principle known as device-agnosticism - protocols and markup should (ideally) form interfaces that hide implementation details of clients from servers and vice-versa. Device-agnosticism (and by extension, interfaces in general are very important concepts to any computer system, as they allow systems to expand (and entire sections to be replaced) while limiting the changes to the module or section concerned, and without increasing the complexity of the overall system. One can only imagine how slowly the web would have been developed (if at all!) if we'd all had to upgrade our browsers every time a new server came out, or upgrade our servers every time a new browser hit the market.
Following this principle of device-agnosticism, and recognising HTML and an interface between servers and clients (ie, no server-side browser-sniffing), as a web developer the "most correct" way to handle various client devices with varying capabilities accessing a site is to generate/serve the same HTML to them all, then style the site using CSS media types or media queries.
A hover-activated drop-down navigation menu which works fine on a desktop device with a mouse, but which becomes effectively unusable on a touchscreen device (where there is no "hover" event).
A rich, complex UI widget that works well and improves usability on a desktop machine with plenty of CPU power, memory and screen-space, but which over-taxes a small-screened, limited-CPU, limited-memory mobile device.
Large, drag-based UIs like Google Maps, which use the same touch-and-drag gesture to scroll the map as mobile devices typically use to scroll the web page the map is embedded in. Anyone who's found themselves "stranded" in the middle of an embedded Google Map that's larger than their mobile browser's screen, fruitlessly scrolling the map up and down rather than the page it's embedded in will understand the frustration here.
There are a variety of existing solutions to the problem of serving different behaviour or styling to different clients:
###Serve different HTML to different devices###
This has the advantage that each device received only the markup, styling, behaviour and other resources it requires. However, it also requires server-side browser-sniffing, or even a completely different codebase and a client-side redirect to push appropriate devices to this new site, completely violating the principle of device-agnosticism. This solution (at best) significantly increase the complexity of server-side code and necessitates re-writing parts it every time a new class of devices comes out, and at worst involves completely forking your theme, templates or entire codebase, and then maintaining two different versions in synchronicity.
###Use CSS media types and hide conditional content with CSS (
display:none! Although this solution is extremely fast to retrofit to existing sites, that convenience only comes at the cost of a potential waste of bandwidth, parsing and rendering time on the client.
###Load conditional content via AJAX###
On the negative side, however, each piece of content requires an additional round-trip to the server in addition to any other resource-requests caused by dynamically adding scripts, stylesheets or images to the page. While additional requests for linked resources like images, stylesheets and scripts might be unavoidable, in the modern world of mobile devices and bandwidth limitations a server round-trip potentially for each piece of conditional content seems somewhat profligate.
Even worse, depending on your server-side architecture changing your CMS to load most or all conditional content through AJAX may require significant redesign and redevelopment of both your front-end and back-end to allow it, to the point it's simply unrealistic for many legacy sites.
##So what's the new idea?##
###In a nutshell###
###So how does it work?###
<head> </head> <body> <p>Non-conditional content</p> <p>Conditional content</p> <p>Non-conditional content</p> </body>
If the expression evaluates to true then as soon as the document is loaded the content is extracted from the comment and added to the DOM in the same position as the comment occupied.
So, for example:
You can even use user-interactive triggers:
As you can no doubt imagine, this level of control over markup insertion and external-resource loading is potentially very powerful indeed.
###What's the benefit?###
This technique has many of the benefits of AJAX-loading - the same basic HTML is served to all devices, elements are not parsed/added to the DOM/rendered unnecessarily, linked resources are not downloaded until needed, etc - but avoids additional unnecessary round-trips to the server to do so.
Conditional content inside HTML comments is still downloaded, but compared to images, video and the rest of the resources needed to render modern web pages, the unnecessary markup is usually only a tiny fraction of the total weight of a page, and the fact that the same HTML is served to every client makes caching no more difficult or ineffective than with a normal (static) page. Moreover, linked resources in HTML comments are not downloaded until the content is inserted into the DOM, making this a highly efficient technique to defer loading of scripts, stylesheets, images, videos, etc compared to older techniques like hiding undesired markup with CSS.
Script tags may also be loaded and executed conditionally in this way; scripts will only be loaded, parsed and executed when and if they are added to the DOM, never unnecessarily. Finally, retrofitting existing sites with this technique is as simple as commenting out conditional content and elements with minimally-formatted comments, making it vastly faster and simpler than either implementing AJAX callbacks on the server, or forking/modifying the server-side codebase to offer a "mobile version" for sites initially designed without progressive enhancement in mind.
Validation does not appear to be a problem, as long as one avoids HTML-comment-closing double-dashes in the conditional content (see
What are the drawbacks?, below).
However, perhaps most importantly of all, this technique is orders of magnitude more easily retrofitted to existing sites than AJAX. It literally only requires loading an external script and editing your templates to slap comment tags around any conditional content, as opposed to duplication of functionality or even a complete re-engineering of the back-end infrastructure. As someone increasingly tasked with producing "mobile friendly" versions of legacy sites that were never designed with mobile devices in mind and which typically lack the budget for a complete re-engineering, this seems like a big win.
###What are the drawbacks?###
In the spirit of full disclosure, I'm not totally sure yet. This is a new technique and I've only been playing with it for a few days. However, there will no doubt be a few.
Deferring external resources until they're included in the DOM could sometimes lead to Flash Of Unstyled Content (FOUC) issues if used incorrectly. However, this can be easily worked around by making conditional content invisible/
display:nonein (non-conditional) CSS, then enabling it in the conditionally-loaded CSS or JS.
Others to come?
##Demo / Examples##
A demo/testing page is included in this repository - host
codomins-demo.php on your server and hit its URL in your web browser. It will display a page which attempts to conditionally load various types of resources (in-line elemtns, block-level elements, inline/external scripts and CSS, external images, etc), in your browser.
Using the form at the bottom you can also instruct the page to reload itself with a variety of content-types and DOCTYPEs - very useful for testing, as the same browser will often behave wildly differently depending on the content-type and DOCTYPE selected, and it's important to check every combination for bugs/omissions.
New: there's now an on-line version of the demo/testing page at http://www.shaper-labs.com/projects/codomins/codomins-demo.php for the curious to play with.
There is no "magic bullet" to making sites (even legacy ones) more mobile-friendly. However, this technique seems to be a very useful addition to existing techniques like AJAX and hiding elements with CSS. In particular the ease with which it may be retrofitted to existing sites is potentially extremely useful for making sites more mobile-friendly without incurring huge redevelopment effort.
Work-in-progress codomins source code is available on github.