Detecting which webkit/moz/etc. prefix to display

Problem

I've been working on a CSS minifier for PHP that's done except for one thing:

I'd like to have it detect the user's browser and determine whether the user needs border-radius, -webkit-border-radius, -moz-border-radius, etc. So that I dont have to use the very long and annoying groups.

This would either detect all instances of -webkit, -moz, etc. border-radius and merge them OR I would place {vendor}border-radius into the CSS file which would then be replaced by either -webkit-, -moz-, or nothing. The first one is ideal because I'd like for it to be expandable to other projects.

For the life of me, I can't figure out a working PHP implementation that accurately detects which prefix to use (and I've googled/searched everywhere I could think of).

Any help would be much appreciated!

Problem courtesy of: Cabloo

Solution

The main issue here is that PHP (the server) won't know the CSS capabilities of your browser off-hand (the client). The only information that's remotely close to identifying a browser that would get sent to PHP is the user-agent string. Even then, you would still need to research the CSS capabilities of a specific version of a specific browser or engine, based on what you find through parsing the user-agent string, and hard-code some decision-making code based on that information.

I think that's the main liability of trying to use server-side code to determine the CSS capabilities of a client. There may be others, but this seems the biggest hurdle, unfortunately.

On the client side, there exist scripts like -prefix-free that make adding prefixes a trivial job; just serve your minified CSS with only the unprefixed properties and rules, and let the script add the prefixes for you based on what it knows about the browser (that the server doesn't).

The first paragraph from this entry in its FAQ also seems worth a read:

“Something like this belongs to the server-side”

A server side script would need to add all prefixes, making the size of the CSS file considerably larger. Also, it should maintain a list of features that need prefixes, or add them all and unnecessarily bloat the stylesheet. -prefix-free automatically detects what needs a prefix and what doesn’t.

As well as an interview with its author, which it links to:

"This is something better done on the server. Do it once instead of on every pageload"

What -prefix-free exactly does, is impossible to do in the server. -prefix-free detects which features need a prefix and only adds it if needed. Also, it automatically detects which properties are available that need a prefix. It doesn't have to keep lists of which prefixes to add for which features, everything gets feature detected, and thus is very future proof. With preprocessors, lists need to be maintained about this sort of stuff. Such lists are doomed to be incomplete and quickly get out of date. Every server-side prefixer I ever tried fails in a number of cases.

(Emphases mine.)

Solution courtesy of: BoltClock

Discussion

Sniff for the user agent of the browser and then set php conditional statments. I've quickly pasted the script I use for my webapp because I'm kinda busy so can't rewrite it for you, but you can google the user agents of different browsers and modify it as needed.

<?php
    $iPod = stripos($_SERVER['HTTP_USER_AGENT'],"iPod");
    $iPhone = stripos($_SERVER['HTTP_USER_AGENT'],"iPhone");
    $iPad = stripos($_SERVER['HTTP_USER_AGENT'],"iPad");
    $Android = stripos($_SERVER['HTTP_USER_AGENT'],"Android");
    $Blackberry = stripos($_SERVER['HTTP_USER_AGENT'],"Blackberry");
    $Playbook = stripos($_SERVER['HTTP_USER_AGENT'],"Playbook");
    $Mango = stripos($_SERVER['HTTP_USER_AGENT'],"Mango");
    $webOS = stripos($_SERVER['HTTP_USER_AGENT'],"webOS");
?>

Alternatively, in css just set a class that uses all three and just set that class to whatever element you need to. This, in any case, is the easiest and most practical solution. Again, modify as needed.

.border-radius{
    -moz-border-radius: 0px 0px 0px 0px;
    -webkit-border-radius: 0px 0px 0px 0px;
    border-radius: 0px 0px 0px 0px;
}
Discussion courtesy of: CoreyRS

This is not the answer to your question but you can use PrefixFree instead of reinventing the wheel.

look at it's detail here:

http://coding.smashingmagazine.com/2011/10/12/prefixfree-break-free-from-css-prefix-hell/

Regarding your question:

You can use php get_browser() to determine the user browser and do as required.

In my experience, avoiding prefixes wouldn't decrease the css size so much. you can instead GZIP the file, it will affect css file so much and decrease the difference between all prefix or one prefix more even.

Discussion courtesy of: Ali

Here's a PHP browser detector:

<?php
$agent = $_SERVER['HTTP_USER_AGENT']; 
$browserArray = array(
        'Windows Mobile' => 'IEMobile',
    'Android Mobile' => 'Android',
    'iPhone Mobile' => 'iPhone',
    'Firefox' => 'Firefox',
        'Google Chrome' => 'Chrome',
        'Internet Explorer' => 'MSIE',
        'Opera' => 'Opera',
        'Safari' => 'Safari'
);
foreach ($browserArray as $k => $v) {

    if (preg_match("/$v/", $agent)) {
         break;
    }   else {
     $k = "Browser Unknown";
    }
} 
$browser = $k;

if($browser == "Google Chrome"){ echo "-webkit-border-radius: 10px;" } /*etc*/
?>

Personally I'd just always use the un-prefixed version, but that's up to you.

Discussion courtesy of: stackunderflow

This recipe can be found in it's original form on Stack Over Flow.