Search code examples
javascriptcssprop

Testing if css prop is supported by the client. Code breaks after repetitions


I’d be very thankful if maybe someone else got a clue on why my code breaks / infinite loops when I run it multiple times, purposely resulting in a result 'false'

Warning your browser may stop responding if you run the code with an invalid/unsupported css prop.

<!DOCTYPE html>
<html>
<body>

<p>Test if a style property is supported by the browser.</p>

<form onsubmit="myFunction(); return false">
<input type="text" id="prop" style="width: 180px;" placeholder="e.g. box-shadow">
<button type="submit">Try it</button>
</form>

<p id="demo"></p>

<script>
String.prototype.isSupported = (function() { 
    var div = document.createElement('div'), 
        vendors = 'khtml ms o moz webkit'.split(' '), 
        len = vendors.length; 

    return function(prop) { 
        prop = this.valueOf(); 
        if(prop in div.style) return true; 
        prop = prop.replace(/^[a-z]/, function(val) { return val.toUpperCase(); }); 
        while(len--) { 
            if(vendors[len] + prop in div.style) { return true; } 
        } 
        return false; 
    }; 
}) ();

function myFunction() {
    var input = document.getElementById("prop").value;
    document.getElementById("demo").innerHTML = input.isSupported();
}
</script>

</body>
</html>


Solution

  • You need to reset the len value every time your isSupported() function is called. Right now your code suggests that you are collecting the length only when isSupported() method is declared. So, after the first call, your while loop made the len variable to 0. Then any subsequent call decremented the len variable further more and took it to -1, -2, and so on. In JS minus values are truthy. So, your while loop is getting stuck. All you need to do is to reset the len variable when the function gets called. Here is the fixed code: https://jsfiddle.net/f3kpdwu4/4/

    String.prototype.isSupported = (function() { 
        var div = document.createElement('div'), 
            vendors = 'khtml ms o moz webkit'.split(' '), 
            len = vendors.length; // it runs only once
    
        return function(prop) { 
            len = vendors.length; // refresh it on every call
            prop = this.valueOf(); 
            if(prop in div.style) return true; 
            prop = prop.replace(/^[a-z]/, function(val) { return val.toUpperCase(); }); 
            while(len--) { 
                if(vendors[len] + prop in div.style) { return true; } 
            } 
            return false; 
        }; 
    }) ();