How can I feature-detect CSS filters?
Asked Answered
T

3

17

In some browsers, including Chrome stable, you can do this:

h3 {
  -webkit-filter: grayscale(1);
  filter: grayscale(1);
}

And wouldn’t you know it, the h1 will be rendered completely in grayscale. Everything old is new again.

Anyway — does anyone know of any way to feature-detect for this?

I need to be able to apply other styles if the filter won’t work.

Troy answered 15/6, 2012 at 8:34 Comment(3)
You mean different styles inside of filter, or filter itself?Paramorphism
@3p3r Oh great, do certain browsers only support some of them?… of course. Well, whatever is necessary to test, I guess.Troy
I assume, that's the case, because my browser (Chrome 19) supports filter but it doesn't support grayscaleParamorphism
I
2

You can now use CSS' build-in @support to conditionally apply styles. Note that the browser support for @support is good but not perfect. This is a nice article explaining how it works with several examples: https://iamsteve.me/blog/entry/feature-detection-with-css

For instance, you can do something like this (see it live):

@supports (filter: grayscale(1)) or (-webkit-filter: grayscale(1)) {
  h3 {
    -webkit-filter: grayscale(1);
    filter: grayscale(1);
  }
}

@supports not (filter: grayscale(1)) and not not (-webkit-filter: grayscale(1)) {
  h3 {
    color: #808080;
  }
}
Intumescence answered 27/5, 2019 at 5:12 Comment(3)
More so, there is a JS option alongside it: Mozilla documentationDictionary
Times have changed and this is probably now the best answer, so I am changing my accepted answer to this one. That said, I imagine that the number of browsers supporting @support but not CSS filter must be small... possibly only Opera Mini and some embedded browsers.Troy
Regarding browser support, every current browser (that is, not dead ones like MSIE) supports @support 🙂Troy
P
19

So called UPDATED answer:

As the OP mentioned a good point I'm updating the answer but this does not have anything related or in contradict with my previous answer, this is simply a browser detection.

Alan H. mentioned that IE, prior to its 10th. version, supports filter css property but not in the way we all know about it (CSS3 filter I meant).

So If we want to feature detect CSS3 filters only, we should go ahead and use a little browser-detection. As I mentioned in my comments.

Using documentMode property, and combining it with our simple feature-detect we can exclude so called false positives in IE.

function css3FilterFeatureDetect(enableWebkit) {
    //As I mentioned in my comments, the only render engine which truly supports
    //CSS3 filter is webkit. so here we fill webkit detection arg with its default
    if(enableWebkit === undefined) {
        enableWebkit = false;
    }
    //creating an element dynamically
    el = document.createElement('div');
    //adding filter-blur property to it
    el.style.cssText = (enableWebkit?'-webkit-':'') + 'filter: blur(2px)';
    //checking whether the style is computed or ignored
    //And this is not because I don't understand the !! operator
    //This is because !! is so obscure for learning purposes! :D
    test1 = (el.style.length != 0);
    //checking for false positives of IE
    //I prefer Modernizr's smart method of browser detection
    test2 = (
        document.documentMode === undefined //non-IE browsers, including ancient IEs
        || document.documentMode > 9 //IE compatibility moe
    );
    //combining test results
    return test1 && test2;
}

Original Modernizr source


if(document.body.style.webkitFilter !== undefined)

or

if(document.body.style.filter !== undefined)

Extra information:

For just a simple feature detection use my codes above. For a list of supported functions, take a look at here:

For a live demonstration of filters in Chrome, take a look at here:

And 2 more resources for you:

As I'm writing this answer, you must use webkit vendor prefix to make it to work.

Paramorphism answered 15/6, 2012 at 8:38 Comment(10)
Awesome. But I noticed that in Chrome, .filter is defined, but does notheing (unlike .webkitFilter, which is defined and works). Why do you think that is?Troy
I don't have any explanations for this, because I know that browser vendor prefixes are for those styles which are in prototype (non standard) phase or ones that are really browser specific.Paramorphism
@AlanH. Here remarks that it only works with webkit vendor prefix.Paramorphism
I guess my concern is that it seems really weird and unreliable that .filter is defined but unusable — kind of defeats the point of feature testing if it’s wrong.Troy
@AlanH. - IE implements a non-standard filter CSS property for a different purpose which the new standard replaces. Maybe Chrome always supported filter for compatibility with IE which explains why it's defined, but rest assured it will be replaced with the same thing as webkitFilter once standardised. Unfortunately this does complicate feature detection - how do you detect existence of filter in a future-proof way which won't false-positive on IE?Karlise
@Karlise Not sure if my comment here helps or not, but; If you know a specific version of IE (let's say IE8) supports filter but in its non-standard way, then why are you looking for feature detection? go with browser detection instead!Paramorphism
Modernizr now has this feature. They test for style.filter and prefixes as mentioned here, and then do a sort-of-browser-detect via IE’s document.documentMode property. Here’s the diff for the relevant pull request: github.com/Modernizr/Modernizr/pull/615/filesTroy
@3p3r I can’t accept w/o your actual answer including a way to stop false positives in old IEs (and probably including additional prefixes). Address those & I’ll be quite glad to accept.Troy
@AlanH. Updated it, hope it helps.Paramorphism
@3p3r Thanks, however this code contains a concatenation error on the line with the ternary operator: (enableWebkit)?'-webkit-':'' + 'filter: blur(2px)'; should be: (enableWebkit ?'-webkit-':'') + 'filter: blur(2px)'; Also, if learning purposes is a concern, probably best to prefix el, test1 and test2 with a var.Garboard
N
2

To build off of @Sepehr's answer, but to modernize it a bit and to remove extra lines:

var supportsFilters = (function() {
  var filterEl = document.createElement('div');
  filterEl.style.cssText = 'filter:blur(2px)';
  return filterEl.style.length != 0 && (document.documentMode === undefined || document.documentMode > 9);
})();
Nerland answered 27/2, 2019 at 21:15 Comment(0)
I
2

You can now use CSS' build-in @support to conditionally apply styles. Note that the browser support for @support is good but not perfect. This is a nice article explaining how it works with several examples: https://iamsteve.me/blog/entry/feature-detection-with-css

For instance, you can do something like this (see it live):

@supports (filter: grayscale(1)) or (-webkit-filter: grayscale(1)) {
  h3 {
    -webkit-filter: grayscale(1);
    filter: grayscale(1);
  }
}

@supports not (filter: grayscale(1)) and not not (-webkit-filter: grayscale(1)) {
  h3 {
    color: #808080;
  }
}
Intumescence answered 27/5, 2019 at 5:12 Comment(3)
More so, there is a JS option alongside it: Mozilla documentationDictionary
Times have changed and this is probably now the best answer, so I am changing my accepted answer to this one. That said, I imagine that the number of browsers supporting @support but not CSS filter must be small... possibly only Opera Mini and some embedded browsers.Troy
Regarding browser support, every current browser (that is, not dead ones like MSIE) supports @support 🙂Troy

© 2022 - 2024 — McMap. All rights reserved.