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.

Alan H.
  • 16,219
  • 17
  • 80
  • 113
  • You mean different styles inside of `filter`, or `filter` itself? – Sepehr Jun 15 '12 at 08:43
  • @3p3r Oh great, do certain browsers only support some of them?… of course. Well, whatever is necessary to test, I guess. – Alan H. Jun 15 '12 at 08:45
  • I assume, that's the case, because my browser (Chrome 19) supports `filter` but it doesn't support `grayscale` – Sepehr Jun 15 '12 at 08:49

3 Answers3

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.

Community
  • 1
  • 1
Sepehr
  • 2,051
  • 19
  • 29
  • 1
    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? – Alan H. Jun 15 '12 at 08:44
  • 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. – Sepehr Jun 15 '12 at 08:51
  • @AlanH. [Here](http://caniuse.com/css-filters) remarks that it only works with webkit vendor prefix. – Sepehr Jun 15 '12 at 09:02
  • 1
    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. – Alan H. Jun 15 '12 at 19:12
  • @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? – AshleysBrain Jul 13 '12 at 19:16
  • @AshleysBrain 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! – Sepehr Jul 14 '12 at 15:24
  • 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: https://github.com/Modernizr/Modernizr/pull/615/files – Alan H. Jul 19 '12 at 17:32
  • @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. – Alan H. Jul 19 '12 at 18:26
  • @AlanH. Updated it, hope it helps. – Sepehr Jul 21 '12 at 16:40
  • @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. – sq2 Mar 07 '13 at 01:22
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);
})();
Chris Barr
  • 29,851
  • 23
  • 95
  • 135
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;
  }
}
F Lekschas
  • 12,481
  • 10
  • 60
  • 72
  • 2
    More so, there is a JS option alongside it: [Mozilla documentation](https://developer.mozilla.org/en-US/docs/Web/API/CSS/supports) – Shikkediel Oct 13 '20 at 22:55
  • 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. – Alan H. Feb 26 '21 at 02:29
  • Regarding browser support, every current browser (that is, not dead ones like MSIE) supports `@support` – Alan H. Feb 26 '21 at 02:30