There is a fierce competition in the browser market (sometimes referred as the "new browser war"), leading to an incredible pace of innovation, but also to a tremendous fragmentation in implementations.
Service providers and web developers have so far used two different strategies to deal with the fragmentation: limit themselves to a core set of features that are implemented accross a significant device base, or always try to use cutting-edge features, providing fallbacks or degrading gracefully when they are not supported.
What is your best profile ?
The first strategy is often designated in the software industry as 'profiling' the standards, and several business organizations have indeed been very successful in profiling activities.
The main issue with this approach is that making sure that a reasonable number of devices are actually compliant with your profile may represent a significant effort in testing, unless you are big enough to have the implementors test themselves their implementation against your specifications.
Facebook's Ringmark is a good example of a self-certifying profile based on an online benchmark.
If you're too small for implementors to matter, then it is often up to you to figure out what you can reasonably expect from existing browsers, with a little help from the community.
Educated decision or calculated risk ?
The second approach relies entirely on your ability to dynamically discover the features a specific browser supports.
In the past, when the pace of innovation was muuuch slower and only a few desktop browsers were available, web developers used to rely on 'UA sniffing' techniques to first identify the browser, then deduce the features that were supported.
This is not an option anymore, with dozens of variants of the most popular web browsers in the wild: the current favored approach is to test for each feature individually.
If you're there, then you probably don't want to reinvent the wheel: Modernizr does just that, and does it good.
This technique is however far from being ideal:
- First, it isn't entirely reliable, as most of the time you can only guarantee that a specific syntax is understood by the browser, but not that it is actually well implemented,
- Second, this complexifies a lot the code, making it harder to maintain (especially if you want to provide decent fallbacks).
The first concern could be adressed by having the user-agent express themselves what feature they support: recent specifications in W3C seem to go down that path, like the CSS3 CSS Conditional Rules specification that introduces a @supports rule.
The second concern can be partially addressed by relying on utility libraries, but this brings more issues:
- Second, thanks to the incredible amount of new features coming out with every new browser release, the number of tests to be performed has already become quite large, to the extent that it is simply not reasonable to perform all of them on every single page: this leads utility developers to introduce customization and extensibility mechanisms, making both their libraries and the applications using them harder to maintain.
Define your own compromise
After having tested various approaches, I have come up with what seems to me a good compromise:
- I use Modernizr for feature detection only,
- I don't use any polyfills nor cross-browser libraries,
- Instead, I degrade the service, unfortunately most of the time not so gracefully (people: upgrade your browsers!),
- I introduced a caching mechanism to Modernizr to reduce page loading time,
- As a bonus, I use -prefix-free to avoid CSS prefixes and make my code easier to maintain.