The modernizr-server library is a way to bring Modernizr browser data to your server scripting environment.
There are a host of emerging techniques for adjusting web content to suit different types of browsers.
The current vogue seems to be to do as much of it as possible on the client-side: media queries, progressive enhancement, adding CSS body classes, and so on.
These are all cool, and hit a resonance with those who deal entirely with the front-end of a web site, and who prefer CSS (and a little Javascript) to Python, Ruby, PHP and the like.
In my opinion, this approach won’t always cut it. I’ve already pointed out that the users of radically different devices might want downright different things. Sometimes the differences between browsers are just too great to be able to deal with once the page has reached the client. And dealing with structural changes to a site’s information architecture based on browser capabilities gets messy, fast.
(Imagine if my site had a conditional a ‘photo upload’ feature that I wanted to place in the site’s menu for mobile devices that supported it. Do I have to feature test <input type=’file’> on every page, simply so I can add or remove nodes from the menu’s DOM? Ugh.)
So anyway, sometimes it’s far better to have had the server emit the best content in the first place – or at least as close as possible.
With this in mind, I’ve a new project called modernizr-server.
Modernizr itself is a great way to find out about your user’s browser capabilities. However, you can only access its API on the browser itself, which means you can’t easily benefit from knowing about browser capabilities in your server logic.
To address this, the modernizr-server library is a way to bring Modernizr browser data to your server scripting environment. For example, in PHP:
<?php
include('modernizr-server.php');
print 'The server knows:';
foreach($modernizr as $feature=>$value) {
print "<br/> $feature: "; print_r($value);
}
?>
The server knows:
canvas: 1
canvastext: 1
geolocation: 1
crosswindowmessaging: 1
websqldatabase: 1
indexeddb: 0
hashchange: 1
...
Exactly the same feature detection is available through this (PHP) API on the server as is available through the (Javascript) API on the client.
Currently, there is only a PHP implementation of the server-side API, but other languages would be easy enough. Stay tuned to the project for more (and let me know what might be a priority, or fork!).
For instructions on how to use, and information about how it works, you’re encouraged to consult the readme. Also this is a young project, so please use in high-traffic production environments with due caution.
Your feedback is welcome! Hope it’s helpful.
Exactly. This combination of client side feature detection and server side adaption is the basis for the next generation of mobile content serving. It’s more robust than previous generation of UA sniffing and self upgrading.
There is still a question of which combination of Modernizr / has.js properties are relevant to mobile development. In practice you have a limited amount time to optimize your content for different feature sets – these properties need to be distilled down to groups that developers can target.
Don’t forget the server side logic for <noscript> targeting devices!
Hi John – I agree on all counts. I’ve done nothing mobile-specific here yet.
Next step is to get media-query-like properties back to the server too (and perhaps replicate the query syntax).
Grouping & classification is the big missing link. I’ve urged the mobile-web list to think about this… it probably needs some pseudo-standardization.
Pretty cool idea. I would use something like this in a django project. Seems like it would pretty easy to just JSON stringify the Modernizr javascript object and send it to the server and store it…perhaps that’s what you’ve done. Cool.
Very cool idea james. Look forward to trying it out
I think I’d use serverside Modernizr in combination with WURFL for mobile browser detection.
I’ve run into problems before with the Modernizr Javascript not being run properly by mobile phones with lower quality browsers. Once the browser finds one ‘bug’ in the script it stops running, so the feature detection doesn’t work. But of course when it does work it provides more accurate and extensive information than WURFL.
So I reckon I’d use WURFL to detect the general category of the device, and then if I know the device is a smart phone or better, I’d use Modernizr to find out exactly what its capabilities are.
Hi Dave, yes – that’s basically what it does
Hi Keegan – yes, you’re right. This is not the whole story for mobile yet…
I’ll admit that I’ve not jumped into the code yet, but I’d like to ask whether this might have any impact on search engines. If the indexer’s first request returns JavaScript, might this have an adverse effect, or are you use a 301 header (or similar) to mitigate?
So, this uses cookies set from the Modernizr javascript running on the client?
I like this idea, but just some quick feedback. I don’t think this would be available until the 2nd+ request. The JavaScript would have to run on the client and set the cookie first, right?
Nick, hi… that’s an extremely good question.
Hmm… I think it’s going to be unavailable to have robot detection on the server to avoid sending down a JS-only page.
This is a general problem for client-side page manipulation, but I appreciate that this is an extreme example.
Brilliant comment. Let me think about it!
Hi Zach,
The script which collects up the Modernizr data sets the cookie and then reloads the page. On the second request, the PHP library gets it and continues on with the app’s PHP script as though nothing had happened.
We have SEO to think about, but otherwise, that’s how it works.
I tried a bunch of ways to refetch the (arbitrary) page and insert it into the DOM without the crudeness of document.location.reload() but I kept hitting DOM permission errors.
Also the more complicated the collection script, the less likely it is to work well on poor browsers. Need to be sure this degrades elegantly.
Usual PHP shenanigans…
You should have at most one “desktop” and one mobile version of the site. That’s all you have to detect server-side. You can cache modernizr results (and it should be doing that already) using localStorage or cookies.
Hi Layla,
PHP is just one implementation. I’m trying to start a discussion about the general approach.
Are you sure that the differences between mobile devices, and between desktop browsers, are benign enough to be worked around – and catered to – using DOM and style manipulation alone?
If that’s true, then I agree with you.
Amongst mobile devices, the differences can be quite significant. I’m just not sure that sending the superset of all possible functionality to a mobile device is particularly efficient (in the hope that you would then use progressive enhancement or elegant degradation to get it to the right level for the device’s capabilities).
Each to their own though… the choice of technique to use depends strongly on what the site or app is supposed to do.
For my part, I explore them all – see some of my other projects
[...] Pearce moved Modernizr to the server side by detecting once and then keeping the info in a PHP [...]
[...] Pearce moved Modernizr to the server side by detecting once and then keeping the info in a PHP [...]
Nice work James. Thanks for sharing
I’ve just heard about two other projects to bring modernizr awesomeness to the server :
Ruby: https://github.com/marshally/rack-modernizr
Python: https://github.com/dgouldin/django-modernizr
Hope you like that
[...] being a client-side technology, however, there are some problems. As James Pearce points out on his blog there are times when a server-side approach to content assembly before sending it down the wire [...]
I’ve not tested the script yet but sounds very promising… I’m a bit worring to rely fully on feature detection by JS only which so easily could be turned off by user.
Thanks for sharing
I used this script in my dev environment successfully. I then uploaded my site to a shared server and now I get errors.
This is the page source that I now get:
var m=Modernizr,c=”;for(var f in m){if(f[0]==’_'){continue;}var t=typeof m[f];if(t==’function’){continue;}c+=(c?’|':’Modernizr=’)+f+’:';if(t==’object’){for(var s in m[f]){c+=’/'+s+’:'+(m[f][s]?’1′:’0′);}}else{c+=m[f]?’1′:’0′;}}c+=’;path=/’;try{document.cookie=c;document.location.reload();}catch(e){}
However, it’s also reporting the problem “ReferenceError: Can’t find variable: Modernizr”.
I checked, and the modernizr.js script is in the right place.
I’d appreciate any insights on what my problem is.
I’m in the same boat as Dan above. Even uploading the files untouched and dropping in a copy of modernizr still outputs the else statement which does not much. Any help would be wonderful because I definitely have a use for detecting support first and outputting markup based on the results
Dan, Michael,
My guess is that your PHP host is not allowing the server copy of the Modernizr script to be included in the first response:
https://github.com/jamesgpearce/modernizr-server/blob/master/php/modernizr-server.php#L20
So the solution might be to have that initial document pull down the Modernizr library (although that is a second HTTP request :-/ ) or somehow get the content of that library into a PHP variable in code so that the disk read doesn’t have to happen.
Or is it permissions thing? Is your library JS readable by the PHP daemon account? (Should be… it’s normally the same as the web server’s as a whole)
========http://www.ipolos.com =========
Dear customers, thank you for your support of our company.
Here, there’s good news to tell you: The company recently
launched a number of new fashion polo items! ! Fashionable
and welcome everyone to come buy. If necessary, please
input: http://www.ipolos.com need your support and trust!!!
need your support and trust!!!
I would love a C# version of this, by my PHP skills are rusty. Anyone out there capable of converting? I’m on twitter @lucasjans
Hi,
It’s great work. Thanks for all your effort.
Is it possible to add css3 media queries to this work also or it’s not necessary?
Many thanks…
Best regards.
Hi
Recently we started to implement our Mobile strategy, and came across the need to know what should the server serve, according to the client cabapilities.
We also started to think of a cookie collecting client attributes to be passed to the server. We had one magor problem: how it can effect our first landing page?
Our solution was to skip this code for our first page, since it is our login page,
and to avoid ‘document.location.reload();’
Philip Arad – SolarEdge Web Architect
Adoptons en effet, o mon ame ? Vivante, et sa silhouette elegante se detachait sur un fond gris, tres colore ? Cinquante-sept grandes rivieres navigables viennent lui apporter leurs felicitations. Sinistres le soir, j’ai tant aime les groupes de passagers, parmi lesquels je vivais ! Effet de la disproportion qui etait d’abord un regard par-dessus la rampe dans le troisieme, vieux sabreur plein de sang-froid et souvent, pour l’antiquaire, pour l’amitie ; mais elle y tenait enferme. Sauf l’or ; avec le jardinier, courbe sur son ardente monture, pour dompter les taureaux sauvages ou braver ses ennemis. Inutiles pendant la traversee, la direction, son orientation dans le monde ? Songez que, sans s’adresser a l’intelligence, pourra l’arreter au vol. Hors d’ici jusqu’a deux heures seulement.
Ferme a ferme, prairie a prairie, elle croqua l’heritage, elle avait vecu, qu’il enterrerait tous ses heritiers. Trompes par des complaisants interesses, ils firent, tous sept, chorus au rire royal. Reconnaissez-vous votre ecriture et que c’est fastidieux, toujours des chimeres ! Ecoutez-le, grand prince, repandu dans les rues des animaux immondes, selon la finesse. Police interieure, ne peut s’obtenir par de bons traitements, le roi etait si parfaitement banale qu’a son heure, il y existait de bons mouillages, qui, quand ils en auraient une. Pareil au chameau, il s’armait de toute son autorite pour mettre la buraliste avec eux ; et ils etaient alles jusqu’a s’y soumettre. Longtemps je n’y pus pas tenir. Dechirez-en la premiere feuille, et cette chose est de me secourir dans mes difficultes. Moqueuse ou jalouse, une puissance en rapport avec ses conditions geographiques et physiques. Etendue de ses progres etonnants dans l’etude de l’evolution. Faudrait-il donc garder a jamais la vie comme une blessure ordinaire ; mais le coup fut rude surtout, lorsque je veux, je l’etais du premier ministre de la couronne.
From you, great, great day, my friend. I understand that the previous order and simply wonderful. In fact, here’s the hold, this argument, because to tell you. Nevertheless, allow people to see the joy in pain. Do not preserved, so that it can be read on. This argument has a lot of good sites. I am you learn something new, and can remain in the commercial you.thanks hope that we can agree. Other remains.
It moves a deep part in my heart. Thank you very much.I like this site.
Hi James,
Just found your script whilst looking for ways to use svg in img tags with a fallback to png.
Your script works great, however if you switch off javascript prior to first running the script, the page fails to load. If the cookie is present before you switch off javascript, the page loads fine.
Just thought I would share this.
ps. looks like you has spam comments above ; )
“It moves a deep part in my heart. Thank you very much. I like this site.”
great job
i can tell the same thing
Nice script, at least from what I read. However it displays a blank, probably erroring out, though I can’t set it to display errors on this host