16

I want to serve different javascript files depending on if browser supports CSS3 transition or not. Is there a better way to detect transition support than my code below?

window.onload = function () {
    var b = document.body.style;
    if(b.MozTransition=='' || b.WebkitTransition=='' || b.OTransition=='' || b.transition=='') {
        alert('supported');
    } else {
        alert('NOT supported')
    }
}
BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
user1087110
  • 3,633
  • 11
  • 34
  • 43

5 Answers5

38

I also think including Modernizr is an overkill. The function below should work for any feature.

function detectCSSFeature(featurename){
    var feature = false,
    domPrefixes = 'Webkit Moz ms O'.split(' '),
    elm = document.createElement('div'),
    featurenameCapital = null;

    featurename = featurename.toLowerCase();

    if( elm.style[featurename] !== undefined ) { feature = true; } 

    if( feature === false ) {
        featurenameCapital = featurename.charAt(0).toUpperCase() + featurename.substr(1);
        for( var i = 0; i < domPrefixes.length; i++ ) {
            if( elm.style[domPrefixes[i] + featurenameCapital ] !== undefined ) {
              feature = true;
              break;
            }
        }
    }
    return feature; 
}

var hasCssTransitionSupport = detectCSSFeature("transition");

Inspired by https://developer.mozilla.org/en-US/docs/CSS/Tutorials/Using_CSS_animations/Detecting_CSS_animation_support

Dan
  • 55,715
  • 40
  • 116
  • 154
Daniel
  • 2,343
  • 2
  • 20
  • 24
  • 5
    As IE reported elm.style[featurename] as an empty string. I added!== undefined on the first check; if( elm.style[featurename] !== undefined) { feature = true; } and now it works. – Stoffe Sep 03 '13 at 09:56
1

Modernizr will detect this for you. Use this link to create a custom download build that only contains CSS3 2D and/or 3D transitions.

Once it's run, you can either test for the csstransitions class on the html tag (CSS), or in JavaScript, test if Modernizr.csstransitions is true.

More docs: http://modernizr.com/docs/#csstransitions

Blazemonger
  • 90,923
  • 26
  • 142
  • 180
  • 12
    Thanks. But I don't want to include a library for this :) – user1087110 Jun 04 '12 at 21:03
  • The Modernizr builder lets you select only the features you want detected, giving you the smallest possible code. It's been repeatedly tested and refined, so it really is the best way to do this sort of thing. – Blazemonger Jun 04 '12 at 21:06
  • 2
    Using the Modernizr build tool gives you the smallest possible *Modernizr* code, instead of the entire library. (You specifically asked for "a better way", not the smallest possible code. Modernizr is the best way I know of.) – Blazemonger Jun 04 '12 at 21:42
  • 9
    its not small at all actually and the output code for testing such a simple thing is 50 times larger than needed. I won't use modernizer ever unless i need more than just one of it's tests, and even then I would copy the tests and clean the code up – vsync Oct 26 '12 at 04:47
1

Here is another testing code. Maybe it is an overkill, but the function tries to set the CSS property to DOM object and then read back from it.

Never tested this code on large amount of exotic browsers, but it is safer than just checking for the CSS property availability. Ah, yes, it can distinguish 2D transform support from 3D transform support! Just pass CSS property values you want to test!

The plus of this code is that it detects the vendor prefix supported (if any). Possible return values:

false, when feature unsupported, or

{
    vendor: 'moz',
    cssStyle: '-moz-transition',
    jsStyle: 'MozTransition'
}

when feature supported

/**
 * Test for CSS3 feature support. Single-word properties only by now.
 * This function is not generic, but it works well for transition and transform at least
 */
testCSSSupport: function (feature, cssTestValue/* optional for transition and transform */) {
    var testDiv,
        featureCapital = feature.charAt(0).toUpperCase() + feature.substr(1),
        vendors = ['', 'webkit', 'moz', 'ms', 'o'],
        jsPrefixes = ['', 'Webkit', 'Moz', 'ms', 'O'],
        defaultTestValues = {
            transition: 'left 2s ease 1s',
            transform: 'rotateX(-180deg) translateZ(.5em) scale(0.5)'
           // This will test for 3D transform support
           // Use other values if you need to test for 2D support only
        },
        testFunctions = {
            transition: function (jsProperty, computed) {
                return computed[jsProperty + 'Delay'] === '1s' && computed[jsProperty + 'Duration'] === '2s' && computed[jsProperty + 'Property'] === 'left';
            },
            transform: function (jsProperty, computed) {
                return computed[jsProperty].substr(0, 9) === 'matrix3d(';
            }
        };

    /* test given vendor prefix */
    function isStyleSupported(feature, jsPrefixedProperty) {
        if (jsPrefixedProperty in testDiv.style) {
            var testVal = cssTestValue || defaultTestValues[feature],
                testFn = testFunctions[feature];
            if (!testVal) {
                return false;
            }       

            testDiv.style[jsPrefixedProperty] = testVal;
            var computed = window.getComputedStyle(testDiv);

            if (testFn) {
                return testFn(jsPrefixedProperty, computed);
            }
            else {
                return computed[jsPrefixedProperty] === testVal;
            }
        }
        return false;
    }

    //Assume browser without getComputedStyle is either IE8 or something even more poor
    if (!window.getComputedStyle) {
        return false;
    }

    //Create a div for tests and remove it afterwards
    if (!testDiv) {
        testDiv = document.createElement('div');
        document.body.appendChild(testDiv);
        setTimeout(function () {
            document.body.removeChild(testDiv);
            testDiv = null;
        }, 0);
    }

    var cssPrefixedProperty,
        jsPrefixedProperty;

    for (var i = 0; i < vendors.length; i++) {
        if (i === 0) {
            cssPrefixedProperty = feature;  //todo: this code now works for single-word features only!
            jsPrefixedProperty = feature;   //therefore box-sizing -> boxSizing won't work here
        }
        else {
            cssPrefixedProperty = '-' + vendors[i] + '-' + feature;
            jsPrefixedProperty = jsPrefixes[i] + featureCapital;
        }

        if (isStyleSupported(feature, jsPrefixedProperty)) {
            return {
                vendor: vendors[i],
                cssStyle: cssPrefixedProperty,
                jsStyle: jsPrefixedProperty
            };
        }
    }

    return false;
}

Github: https://github.com/easy-one/CSS3test

Dan
  • 55,715
  • 40
  • 116
  • 154
0
if (window.TransitionEvent){

}
f0rmat1k
  • 55
  • 5
0

With Modernizr 3.0 (alpha), you can generate custom builds locally. This may resolve the aforementioned "overkill" concern - although i'm not entirely clear on that concern in the first place (but i'm assuming it's size). The new api provides a 'build' method, to which you can pass json containing the tests that you would like to include in the build.

I use something like this in my gulp file but gulp is not needed - a simple node script will do.

gulp.task('js:modernizr', function() {
    var modConfig = JSON.parse(fs.readFileSync('modernizr-config.json', {
            encoding: 'utf8'
        }));
    modernizr.build(modConfig, function(res) {
        fs.writeFileSync('modernizr.js', res);
        return true;
    });
}); 

And an example of the 'modernizr-config.json' file would be

{
  "classPrefix": "",
  "options": [
    "addTest",
    "atRule",
    "domPrefixes",
    "hasEvent",
    "html5shiv",
    "html5printshiv",
    "load",
    "mq",
    "prefixed",
    "prefixes",
    "prefixedCSS",
    "setClasses",
    "testAllProps",
    "testProp",
    "testStyles"
  ],
  "feature-detects": [
    "css/transforms",
    "css/transforms3d",
    "css/transformstylepreserve3d",
    "css/transitions",
    "touchevents",
    "workers/webworkers",
    "history"
  ]
}

The full config file is included in the Modernizr package.

With this approach, you can take advantage of the well maintained Modernizr test suite via package installers and easily add/remove tests as needed. Less tests, smaller file obviously.

The 'setClasses' option will add the related test class to your html but you can also take advantage of the 3.0 async events like so:

Modernizr.on('csstransitions', function(bool) {
    if (bool === true) // do transition stuffs
}
Jbird
  • 2,839
  • 1
  • 21
  • 28