Coder Perfect

jQuery animate backgroundColor

Problem

I’m trying to utilize jQuery to animate a change in backgroundColor on mouseover.

I reviewed some examples and it appears that I have it correct; it works with other attributes like fontSize, but not with backgroundColor, which results in a js error of “Invalid Property.” A div is the element I’m working with.

$(".usercontent").mouseover(function() {
    $(this).animate({ backgroundColor: "olive" }, "slow");
});

Any ideas?

Asked by SteveCl

Solution #1

The color plugin is only 4kb in size, making it significantly less expensive than the UI library. Of course, you’ll want to use a good plugin rather than a buggy old one that doesn’t work with Safari and crashes when the transitions are too rapid. Because a minified version isn’t provided, you might want to experiment with other compressors and create your own min version. In this situation, YUI has the best compression, requiring only 2317 bytes, and because it is so small, here it is:

(function (d) {
    d.each(["backgroundColor", "borderBottomColor", "borderLeftColor", "borderRightColor", "borderTopColor", "color", "outlineColor"], function (f, e) {
        d.fx.step[e] = function (g) {
            if (!g.colorInit) {
                g.start = c(g.elem, e);
                g.end = b(g.end);
                g.colorInit = true
            }
            g.elem.style[e] = "rgb(" + [Math.max(Math.min(parseInt((g.pos * (g.end[0] - g.start[0])) + g.start[0]), 255), 0), Math.max(Math.min(parseInt((g.pos * (g.end[1] - g.start[1])) + g.start[1]), 255), 0), Math.max(Math.min(parseInt((g.pos * (g.end[2] - g.start[2])) + g.start[2]), 255), 0)].join(",") + ")"
        }
    });

    function b(f) {
        var e;
        if (f && f.constructor == Array && f.length == 3) {
            return f
        }
        if (e = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(f)) {
            return [parseInt(e[1]), parseInt(e[2]), parseInt(e[3])]
        }
        if (e = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(f)) {
            return [parseFloat(e[1]) * 2.55, parseFloat(e[2]) * 2.55, parseFloat(e[3]) * 2.55]
        }
        if (e = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(f)) {
            return [parseInt(e[1], 16), parseInt(e[2], 16), parseInt(e[3], 16)]
        }
        if (e = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(f)) {
            return [parseInt(e[1] + e[1], 16), parseInt(e[2] + e[2], 16), parseInt(e[3] + e[3], 16)]
        }
        if (e = /rgba\(0, 0, 0, 0\)/.exec(f)) {
            return a.transparent
        }
        return a[d.trim(f).toLowerCase()]
    }
    function c(g, e) {
        var f;
        do {
            f = d.css(g, e);
            if (f != "" && f != "transparent" || d.nodeName(g, "body")) {
                break
            }
            e = "backgroundColor"
        } while (g = g.parentNode);
        return b(f)
    }
    var a = {
        aqua: [0, 255, 255],
        azure: [240, 255, 255],
        beige: [245, 245, 220],
        black: [0, 0, 0],
        blue: [0, 0, 255],
        brown: [165, 42, 42],
        cyan: [0, 255, 255],
        darkblue: [0, 0, 139],
        darkcyan: [0, 139, 139],
        darkgrey: [169, 169, 169],
        darkgreen: [0, 100, 0],
        darkkhaki: [189, 183, 107],
        darkmagenta: [139, 0, 139],
        darkolivegreen: [85, 107, 47],
        darkorange: [255, 140, 0],
        darkorchid: [153, 50, 204],
        darkred: [139, 0, 0],
        darksalmon: [233, 150, 122],
        darkviolet: [148, 0, 211],
        fuchsia: [255, 0, 255],
        gold: [255, 215, 0],
        green: [0, 128, 0],
        indigo: [75, 0, 130],
        khaki: [240, 230, 140],
        lightblue: [173, 216, 230],
        lightcyan: [224, 255, 255],
        lightgreen: [144, 238, 144],
        lightgrey: [211, 211, 211],
        lightpink: [255, 182, 193],
        lightyellow: [255, 255, 224],
        lime: [0, 255, 0],
        magenta: [255, 0, 255],
        maroon: [128, 0, 0],
        navy: [0, 0, 128],
        olive: [128, 128, 0],
        orange: [255, 165, 0],
        pink: [255, 192, 203],
        purple: [128, 0, 128],
        violet: [128, 0, 128],
        red: [255, 0, 0],
        silver: [192, 192, 192],
        white: [255, 255, 255],
        yellow: [255, 255, 0],
        transparent: [255, 255, 255]
    }
})(jQuery);

Answered by Andrew

Solution #2

I experienced the identical issue and was able to solve it by using jQuery UI. The following is the whole script:

<!-- include Google's AJAX API loader -->
<script src="http://www.google.com/jsapi"></script>
<!-- load JQuery and UI from Google (need to use UI to animate colors) -->
<script type="text/javascript">
google.load("jqueryui", "1.5.2");
</script>


<script type="text/javascript">
$(document).ready(function() {
$('#menu ul li.item').hover(
    function() {
        $(this).stop().animate({backgroundColor:'#4E1402'}, 300);
        }, function () {
        $(this).stop().animate({backgroundColor:'#943D20'}, 100);
    });
});
</script>

Answered by menardmam

Solution #3

Use CSS3-Transitions to accomplish this. There is a lot of help available (all modern browsers, even IE). This is simple to achieve with Compass and SASS:

#foo {background:red; @include transition(background 1s)}
#foo:hover {background:yellow}

Pure CSS:

#foo {
background:red;
-webkit-transition:background 1s;
-moz-transition:background 1s;
-o-transition:background 1s;
transition:background 1s
}
#foo:hover {background:yellow}

This is a topic about which I published a German article: http://www.solife.cc/blog/animation-farben-css3-transition.html

Answered by volf

Solution #4

The finest jquery color animation plugin I’ve seen is Bitstorm’s. It makes the jquery color project better. Rgba is also supported.

http://www.bitstorm.org/jquery/color-animation/

Answered by Emmanuel

Solution #5

This capability can be added with the help of jQuery UI. You can only get what you need, therefore all you have to do to animate color is add the following code. It came from the most recent version of jQuery UI (currently 1.8.14)

/******************************************************************************/
/****************************** COLOR ANIMATIONS ******************************/
/******************************************************************************/

// override the animation for color styles
$.each(['backgroundColor', 'borderBottomColor', 'borderLeftColor',
    'borderRightColor', 'borderTopColor', 'borderColor', 'color', 'outlineColor'],
function(i, attr) {
    $.fx.step[attr] = function(fx) {
        if (!fx.colorInit) {
            fx.start = getColor(fx.elem, attr);
            fx.end = getRGB(fx.end);
            fx.colorInit = true;
        }

        fx.elem.style[attr] = 'rgb(' +
            Math.max(Math.min(parseInt((fx.pos * (fx.end[0] - fx.start[0])) + fx.start[0], 10), 255), 0) + ',' +
            Math.max(Math.min(parseInt((fx.pos * (fx.end[1] - fx.start[1])) + fx.start[1], 10), 255), 0) + ',' +
            Math.max(Math.min(parseInt((fx.pos * (fx.end[2] - fx.start[2])) + fx.start[2], 10), 255), 0) + ')';
    };
});

// Color Conversion functions from highlightFade
// By Blair Mitchelmore
// http://jquery.offput.ca/highlightFade/

// Parse strings looking for color tuples [255,255,255]
function getRGB(color) {
        var result;

        // Check if we're already dealing with an array of colors
        if ( color && color.constructor == Array && color.length == 3 )
                return color;

        // Look for rgb(num,num,num)
        if (result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color))
                return [parseInt(result[1],10), parseInt(result[2],10), parseInt(result[3],10)];

        // Look for rgb(num%,num%,num%)
        if (result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(color))
                return [parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55];

        // Look for #a0b1c2
        if (result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color))
                return [parseInt(result[1],16), parseInt(result[2],16), parseInt(result[3],16)];

        // Look for #fff
        if (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color))
                return [parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16)];

        // Look for rgba(0, 0, 0, 0) == transparent in Safari 3
        if (result = /rgba\(0, 0, 0, 0\)/.exec(color))
                return colors['transparent'];

        // Otherwise, we're most likely dealing with a named color
        return colors[$.trim(color).toLowerCase()];
}

function getColor(elem, attr) {
        var color;

        do {
                color = $.curCSS(elem, attr);

                // Keep going until we find an element that has color, or we hit the body
                if ( color != '' && color != 'transparent' || $.nodeName(elem, "body") )
                        break;

                attr = "backgroundColor";
        } while ( elem = elem.parentNode );

        return getRGB(color);
};

After compressing with YUI, it’s only 1.43kb:

$.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor","borderTopColor","borderColor","color","outlineColor"],function(b,a){$.fx.step[a]=function(c){if(!c.colorInit){c.start=getColor(c.elem,a);c.end=getRGB(c.end);c.colorInit=true}c.elem.style[a]="rgb("+Math.max(Math.min(parseInt((c.pos*(c.end[0]-c.start[0]))+c.start[0],10),255),0)+","+Math.max(Math.min(parseInt((c.pos*(c.end[1]-c.start[1]))+c.start[1],10),255),0)+","+Math.max(Math.min(parseInt((c.pos*(c.end[2]-c.start[2]))+c.start[2],10),255),0)+")"}});function getRGB(b){var a;if(b&&b.constructor==Array&&b.length==3){return b}if(a=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(b)){return[parseInt(a[1],10),parseInt(a[2],10),parseInt(a[3],10)]}if(a=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(b)){return[parseFloat(a[1])*2.55,parseFloat(a[2])*2.55,parseFloat(a[3])*2.55]}if(a=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(b)){return[parseInt(a[1],16),parseInt(a[2],16),parseInt(a[3],16)]}if(a=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(b)){return[parseInt(a[1]+a[1],16),parseInt(a[2]+a[2],16),parseInt(a[3]+a[3],16)]}if(a=/rgba\(0, 0, 0, 0\)/.exec(b)){return colors.transparent}return colors[$.trim(b).toLowerCase()]}function getColor(c,a){var b;do{b=$.curCSS(c,a);if(b!=""&&b!="transparent"||$.nodeName(c,"body")){break}a="backgroundColor"}while(c=c.parentNode);return getRGB(b)};

Colors can also be animated using CSS3 transitions, however this feature is only available in newer browsers.

a.test {
  color: red;
  -moz-transition-property: color;  /* FF4+ */
  -moz-transition-duration: 1s;
  -webkit-transition-property: color;  /* Saf3.2+, Chrome */
  -webkit-transition-duration: 1s;
  -o-transition-property: color;  /* Opera 10.5+ */
  -o-transition-duration: 1s;
  -ms-transition-property: color;  /* IE10? */
  -ms-transition-duration: 1s;
  transition-property: color;  /* Standard */
  transition-duration: 1s;
  }

  a.test:hover {
  color: blue;
  }

Using shorthand property:

/* shorthand notation for transition properties */
/* transition: [transition-property] [transition-duration] [transition-timing-function] [transition-delay]; */

a.test {
  color: red;
  -moz-transition: color 1s;
  -webkit-transition: color 1s;
  -o-transition: color 1s;
  -ms-transition: color 1s;
  transition: color 1s;
  }

a.test {
  color: blue;
 }

CSS3 transitions, unlike conventional javascript transitions, are hardware accelerated and hence smoother. You can use Modernizr to see if your browser supports CSS3 transitions, and if it doesn’t, you can fall back on jQuery:

if ( !cssTransitions() ) {
    $(document).ready(function(){
        $(".test").hover(function () {
                $(this).stop().animate({ backgroundColor: "red" },500)
             }, function() {
                 $(this).stop().animate({ backgroundColor: "blue" },500)}    
             );
    }); 
}

Remember to use stop() to halt the current animation before initiating a new one; otherwise, the effect will blink for a long time if you pass over the element too quickly.

Answered by Faraz Kelhini

Post is based on https://stackoverflow.com/questions/190560/jquery-animate-backgroundcolor