Search code examples
javascriptcss-transitionspseudo-elementbrowser-feature-detection

How would I detect CSS Transition support on :before pseudo-elements with javascript?


I'm trying to use CSS Transitions with a :before selector and currently the only browser that supports this is Firefox. I can create a jQuery fallback with no problem, but I'm not sure how to do feature detection with a pseudo-element like that.

Here's a JSBin which shows the HTML and CSS that I'm working with.

(... and here's a similar SO question, but about using regular elements.)

Update: wow, even the platform preview of IE10 has support for this, what's up with that webkit?!

IE 10 Platform preview has CSS Transition support on :before

(Edit: solutions moved to answer below)


Solution

  • Thanks to @Asad for digging up some handy code, I was able to come up with a nice solution here's the jQuery version:

    $(function() {
      var isTransitionSupported = (function (pseudo, transProp, transPropStart, transPropEnd) {
        var id = pseudo + transProp + '-' + (new Date()).valueOf(),
            prefixes = ['o', 'ms', 'moz', 'webkit'],
            prop = "transition: " + transProp + " 99s linear;",
            allprops = (function () {
              var props = "";
              for (var l = prefixes.length; l--;) {
                props += "-" + prefixes[l] + "-" + prop;
              }
              return props + prop;
            }()),
            $css = $("<style>" +
                     "#" + id + "{position:absolute;left:-999em;}" + 
                     "#" + id + ":" + pseudo + "{display:block;content:'M';" + transProp + ":" + transPropStart + ";}" + 
                     "#" + id + ".t:" + pseudo + "{" + allprops + transProp + ":" + transPropEnd + ";}" + 
                     "</style>"),
            $bct = $('<div id="' + id + '" />');
    
          $css.appendTo("head");
          $bct.appendTo("body");
    
          try {
            // get style value before any changes
            window.getComputedStyle($bct[0], ':' + pseudo).getPropertyValue(transProp);
    
            $bct.addClass("t");
    
            // test style after changes
            return (window.getComputedStyle($bct[0], ':' + pseudo).getPropertyValue(transProp) !== transPropEnd);
          } catch (e) {}
          return false;
        }("before", "width", "0px", "1000px"));
    });
    

    Here's a version that doesn't use jQuery:

    var isTransitionSupported = (function (pseudo, transProp, transPropStart, transPropEnd) {
        var ticks = (new Date()).valueOf(),
            id = pseudo + transProp + '-' + ticks,
            prefixes = ['o', 'ms', 'moz', 'webkit'],
            prop = "transition: " + transProp + " 99s linear;",
            allprops = (function () {
                var props = "";
                for (var l = prefixes.length; l--;) {
                    props += "-" + prefixes[l] + "-" + prop;
                }
                return props + prop;
            }()),
            body = document.body || document.createElement('body'),
            node = document.createElement('div'),
            css = "<style>" +
                        "#" + id + "{position:absolute;left:-999em;}" + 
                        "#" + id + ":" + pseudo + "{display:block;content:'M';" + transProp + ":" + transPropStart + ";}" + 
                        "#" + id + ".t" + ticks + ":" + pseudo + "{" + allprops + transProp + ":" + transPropEnd + ";}" + 
                        "</style>",
            bct = document.createElement('div'),
            isSupported = false;
    
        bct.id = id;
        node.innerHTML += css;
        node.appendChild(bct);
        body.appendChild(node);
    
        try {
            // get style value before any changes
            window.getComputedStyle(bct, ':' + pseudo).getPropertyValue(transProp);
    
            bct.className += "t" + ticks;
    
            // test style after changes
            isSupported = (window.getComputedStyle(bct, ':' + pseudo).getPropertyValue(transProp) !== transPropEnd);
        } catch (e) {}
    
        node.parentNode.removeChild(node);
    
        return isSupported;
    }("before", "width", "0px", "1000px"));
    
    document.documentElement.className += ' ' + (isTransitionSupported ? '' : 'no-') + "pseudo-trans";
    

    Here's all that code in a gist on github, if anyone wants to fork and improve it.