RESS
RWD and Server Side Components
Sven Wolfermann | maddesigns
Sven Wolfermann | maddesigns
dividing pages
large site (feature rich) vs. small size (performant)
dividing more pages?
large site vs. tablet vs. small size
vs. car vs. fridge vs. watch vs. …
solves many things
ok, ok, Oakley does it better now:
JUST 14.2MB, 291 request (more than 70MB less)
with mobile user-agent? 6.7MB, 114 requests :/
has some issues
sites have nearly same weight on mobile as on desktop
Cutting the mustard
if('querySelector' in document && 'localStorage' in window && 'addEventListener' in window) { // bootstrap the javascript application }
if browser supports
'querySelector',
'localStorage'
and 'addEventListener'
do hot stuff
Client side feature detection
Modernizr is a JavaScript library that detects HTML5 & CSS3 features in the user's browser.
throw in <head>
<head> <script src="modernizr.js"></script> </head>
Modernizr features test: geolocation
Modernizr.geolocation // true or false
if (Modernizr.geolocation) { navigator.geolocation.getCurrentPosition(show_map); } else { // no native support; maybe try a fallback? }
Modernizr can load different files based on tests
Modernizr.load({ test: Modernizr.geolocation, yep : 'geo.js', nope: 'geo-polyfill.js' });
Modernizr.load is not part of the "development" version
<html class="js flexbox canvas canvastext webgl no-touch geolocation
postmessage hashchange history boxshadow cssanimations csscolumns
cssgradients csstransforms csstransforms3d csstransitions fontface
video audio localstorage svg inlinesvg">
Another Sample: datepicker
<script src="modernizr.js"></script> <script> Modernizr.load({ test: Modernizr.inputtypes.date, nope: ['jquery.datepicker.js', 'jquery.datepicker.css'], complete: function () { $('input[type=date]').datepicker({ dateFormat: 'yy-mm-dd' }); } }); </script>
load jQuery datepicker library for browsers that don't have native datepickers
Returns a new MediaQueryList object representing the parsed results of the specified media query string.
if (window.matchMedia("(min-width: 40em)").matches) { /* load secondary stuff */ }
Modernizr.load and Picturefill uses matchMedia for example
Modernizr loads scripts and CSS based on media queries
Modernizr.load([ { test: Modernizr.mq("only screen and (min-width: 1051px)"), yep: '/js/large.js' }, { test: Modernizr.mq("only screen and (min-width: 600px) and (max-width: 1050px)"), yep: '/js/medium.js' }, { test: Modernizr.mq("only screen and (min-width: 320px) and (max-width: 599px)"), yep: '/js/small.js' } ]);
you can use EM in media queries too ;)
holding CSS and JavaScript Breakpoints in sync
body:after { content: 'small'; display: none; } @media (min-width: 650px) { body:after { content: 'middle'; } } @media (min-width: 1200px) { body:after { content: 'large'; } }
holding CSS and JavaScript Breakpoints in sync
var size = window.getComputedStyle(document.body,':after') .getPropertyValue('content');
if (size == 'large') { // Load some more content. }
Replace:
<a href="..." data-replace="latest/fragment">Latest Articles</a>
Before:
<a href="..." data-before="latest/fragment">Latest Articles</a>
After:
<a href="..." data-after="latest/fragment">Latest Articles</a>
init with jQuery:
$("[data-replace],[data-before],[data-after]").ajaxInclude();
remember the old days? Not? You lucky guy!
UA-string history
is hard and unreliable
For example, Safari user agent string on an iOS7 iPhone:
Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X)
AppleWebKit/546.10 (KHTML, like Gecko) Version/6.0 Mobile/7E18WD
Safari/8536.25
often browsers aims other browsers
detecting the "right" user agent is complicated
if((navigator.userAgent.match(/iPhone/i)) || (navigator.userAgent.match(/iPod/i))) { if (document.cookie.indexOf("mobile_redirect=false") == -1) { window.location = "http://m.yoursite.com/"; } }
more like this
// Check if UA is mobile (from http://detectmobilebrowsers.com/) if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry |blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris |kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)? |phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian |treo|up\.(browser|link)|vodafone|wap|windows (ce|phone) |xda|xiino/i.test(agent) { isUAMobile = true; }
Problems
set browser width cookie with JS
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();
use cookie info in code
Setting a file path based on window.innerWidth
<?php // grab the cookie value $screenWidth = $_COOKIE['RESS']; // set the img path var if ($screenWidth <= 320) { $imgPath = "320"; } else if ($screenWidth < 960) { $imgPath = "640"; } else { $imgPath = "960"; } // print out our image link print "<img src='/rwd/images/".$imgPath."/car.jpg' alt='Car' />"; ?>
use cookie info in code
<?php if ($RESS["width"] >= 320 && $RESS["width"] <= 640) { ?> <div class="mobile-ad max-320"> <?php include "/ads/320.php"?> </div> <?php } ?>
Client features for the server
<?php include('modernizr-server.php'); print 'The server knows:'; foreach($modernizr as $feature=>$value) { print "
$feature: "; print_r($value); } ?> The server knows: canvas: 1 geolocation: 1 crosswindowmessaging: 1 indexeddb: 0 hashchange: 1 ...
In a nutshell, RESS combines adaptive layouts with server side component (not full page) optimization. So a single set of page templates define an entire Web site for all devices but key components within that site have device-class specific implementations that are rendered server side.
<head>
writes a session cookie, storing the visitor's screen size in pixels.<img>
tag and sends a request to the server for that image. It also sends the cookie, because that’s how browsers work..htaccess
file, to see if there are any special instructions for serving files..htaccess
says "Dear server, any request you get for a JPG, GIF, or PNG file please send to the adaptive-images.php
file instead."$resolution
sizes that were configured, and decides which matches best. In this case, an image maxing out at 480px wide./ai-cache/480/
folder to see if a rescaled image already exists./ai-cache/480/
folder ready for the next time it's needed, and sends it to the user.combines UA-parsing and feature testing
no need for commercial device detection libraries
add your own feature tests and store the results using Modernizr's addTest() API
The default install of Detector will categorize browsers into one of three families.
// families.json { "tablet": { "isTablet": true }, "mobile-advanced": { "isMobile": true, "features": ["cssanimations","localstorage","deviceorientation"] }, "mobile-basic": { "isMobile": true }, "desktop": { "isComputer": true } }
switch ads, basic sample
if ($ua->family == 'mobile-basic') { include "/ads/simple.php"; } elseif ($ua->family == 'mobile-advanced') { include "/ads/responsive-ads.php"; } else { include "/ads/desktop.php"; }
if ($ua->video->h264 || $ua->video->webm) { print $html5Embed; // YouTube's <iframe> code } else { print $simpleLink; }
Templating with Detector & Mustache for RESS
Is Adaptive Web Design Or RESS Better Than Responsive Design For SEO?
Adaptation: Why responsive design actually begins on the server
Client Hints is a new proposal by Ilja Grigorik and will allow clients to indicate a list of device and agent specific preferences. Spec Draft
(request) GET /img.jpg HTTP/1.1 User-Agent: Awesome Browser Accept: image/webp, image/jpg CH: dpr=2.0 (response) HTTP/1.1 200 OK Server: Awesome Server Content-Type: image/jpg Content-Length: 124523 Vary: CH (image data)
For example, given the following request header:
CH: dh=598, dw=384, dpr=2.0
The server knows that the client's screen height is 598px, width is 384px, as measured by density independent pixels on the device, and that the device pixel ratio is 2.0.
ReSrc.it can handle client hints now
Sven Wolfermann | maddesigns