Dynamic CSS3 prefix user agent detection

2020-07-24 03:37发布

问题:

Is there a better way then using jQuery.browser, or equivalents, for determining css 3 prefixes (-moz, -webkit, etc), as it is disencouraged? Since the css is dynamic (the user can do anything with it on runtime), css hacks and style tag hacks can't be considered.

回答1:

I don't see the issue with using the navigator.userAgent to determine if you need to cater for Webkit / Gecko CSS3 prefixes. Or better yet, just stick with CSS2 until CSS3 becomes a W3C Recommendation.

The reason use of the navigator object is discouraged is because it was used over Object detection when (java)scripting for different browsers, your situation is one where it is fine to use user agent detection, because your'e specifically targeting certain quirks with different rendering engines.

Edit: Picking up from where cy left off, you can use javascript object detection to detect whether a prefix is used, I made some quick code to do so:

window.onload = function ()
{
    CSS3 = {
        supported: false,
        prefix: ""
    };
    if (typeof(document.body.style.borderRadius) != 'undefined') {
        CSS3.supported = true;
        CSS3.prefix = "";
    } else if (typeof(document.body.style.MozBorderRadius) != 'undefined') {
        CSS3.supported = true;
        CSS3.prefix = "-moz-";
    } else if (typeof(document.body.style.webkitBorderRadius) != 'undefined') {
        CSS3.supported = true;
        CSS3.prefix = "-webkit-";
    }
    if (CSS3.supported)
        if (CSS3.prefix == "")
            alert("CSS3 is supported in this browser with no prefix required.");
        else
            alert("CSS3 is supported in this browser with the prefix: '"+CSS3.prefix+"'.");
    else
        alert("CSS3 is NOT supported in this browser.");
};

Remember to watch out for strange quirks such as -moz-opacity which is only supported in older versions of Firefox but has now been deprecated in favour of opacity, while it still uses the -moz- prefix for other new CSS3 styles.



回答2:

Array.prototype.slice.call(
  document.defaultView.getComputedStyle(document.body, "")
)
.join("")
.match(/(?:-(moz|webkit|ms|khtml)-)/);

Will return an array with two elements. One with dashes and one without dashes, both lowercase, for your convenience.

Array.prototype.slice.call(
  document.defaultView.getComputedStyle(document.body, "")
);

Without the browser check will return an array of nearly all the css properties the browser understands. Since it's computed style it won't display shorthand versions, but otherwise I think it gets all of them. It's a quick hop skip and a jump to auto detect whatever you need as only vendor prefixed stuff starts with a dash.

IE9, Chrome, Safari, FF. Opera won't let you slice CSSStyleDeclaration for you can still use the same getComputedStyle code and loop through the properties or test for a specific one. Opera also wanted to be the odd man out and not report the vendor prefix dasherized. Thanks Opera.

Object.keys(CSSStyleDeclaration.prototype)

Works in IE9 and FF and reports the TitleCased (JavaScript) version of the vendor property names. Doesn't work in WebKit as the prototype only reports the methods.

Here's an interesting and very dangerous function I just wrote along these lines:

(function(vp,np){
Object.keys(this).filter(function(p){return vp=vp||p.match(/^(Moz|ms)/)}).forEach(function(op){
    this.__defineGetter__(np=op.replace(vp[0], ""), function() { return this[op] });
    this.__defineSetter__(np, function(val) { this[op] = val.toString() });
}, this);
}).call(CSSStyleDeclaration.prototype);

I didn't test anything Konquerer.



回答3:

It's adding in another library, but would Modernizr work for you? It adds CSS classes to the <html> tag that can tell you what the browser supports.

It does muddy up the code a bit, but can certainly be helpful in appropriate situations.



回答4:

Speculatively: Yes. You can try adding a vendor prefix css rule (that's what they're called), and then test to see if that rule exists. Those vendor-specific rules won't be added to the DOM in browsers in which they're not supported in some cases.

For example, if you try adding a -moz rule in webkit, it won't add to the DOM, and thus jQuery won't be able to detect it.

so,

$('#blah').css('-moz-border-radius','1px');
$('#blah').css('-moz-border-radius') //null in Chrome

Conversely,

$('#blah').css('-webkit-border-radius','1px');
$('#blah').css('-webkit-border-radius'); //returns "" in Chrome

This method works in WebKit browsers; I'm testing to see if it works in others. Pending.


Edit: Sadly, this isn't working in Firefox or Opera, which just returns "" no matter compatibility. Thinking of ways to do this cross-browser...

Final Edit: Andrew Dunn's answer does this in a way that works (at least in FF and Webkit, which is better than my method).



回答5:

I use ternary operator to have it only in 1 line. If it's not webkit nor gecko, I'll just use the standard property. If it has no support, who really cares then?

var prefix = ('webkitAnimation' in document.body.style) ? '-webkit-' : ('MozAnimation' in document.body.style? '-moz-' : '');

Basically I found Animation is one of the properties never changed. As soon as the browser starts supporting the Draft / Candidate Recommendation of a CSS3 property, it drops the prefix on JS side. So you will need to be careful and take in mind that, before copy-pasting.