How can I change a CSS gradient via JavaScript?

11,057

Solution 1

With jQuery it'll be :

$('.gradient').css({'background-image': 'linear-gradient(to top,  #2E2E28 0%, #4D4C48 100%)'});

For safari :

$('.gradient').css({'background-image': '-webkit-linear-gradient(top,  #2E2E28 0%, #4D4C48 100%)'});

See here for a live example.

Seems to work cross-browser.

Edit :

I did a small plugin which can help you with the different colors :

;(function($) {
    var isSafari = /Safari/.test(navigator.userAgent) && /Apple Computer/.test(navigator.vendor);

    var methods = {
        init: function (settings) {

            settings = $.extend( {
              'colors'         : ['red', 'blue'],
              'direction'      : 'top'
            }, settings);

            return this.each(function(){
                if($.isArray(settings.colors) && settings.colors.length >= 2) {
                    $(this).css({ 
                        'background':
                        methods.gradientToString(settings.colors, settings.direction)
                    });
                } else {
                    $.error('Please pass an array');
                }

            });

        },
        gradientToString: function (colors, direction) {

            var nbColors = colors.length;

            //If no percent, we need to calculate them
            if(colors[0].percent === undefined) {

                //Passed only colors as an array we make it an object
                if(colors[0].color === undefined) {
                    var tmp = [];
                    for(i=0; i < nbColors; i++)
                        tmp.push({'color':colors[i]});

                    colors = tmp;
                }

                var p = 0,
                    percent = 100 / (nbColors - 1);

                //calculate percent
                for(i=0; i< nbColors; i++) {
                    p = i === 0 ? p : (i == nbColors-1 ? 100 : p + percent);
                    colors[i].percent = p;
                }
            }

            var to = isSafari ? '' : 'to';

            //build the string
            var gradientString = isSafari ? '-webkit-linear-gradient(' : 'linear-gradient(';

           gradientString += to +' '+ direction;

            for(i=0; i < nbColors; i++)
               gradientString += ', '+ colors[i].color + ' ' + colors[i].percent + '%';

            gradientString += ')';
            return gradientString;

        }

    };

    $.fn.gradientGenerator = function () {
        return methods.init.apply( this, arguments );
    };
})(jQuery);

Use it like this for example :

$('.gradient').gradientGenerator({
    colors : ['#2E2E28', '#4D4C48']
});

$('.change-color').on('click', function(e) {

    e.preventDefault();
    $('.gradient').gradientGenerator({
        colors : [{color:'#4D4C48',percent:0}, {color:'#282827', percent:30}, {color:'#2E2E28', percent: 100}],
        direction : 'left'
    });

});

See it working here.

Solution 2

The following function will take two colours as parameters and return the style string, as you've specified it, with the appropriate substrings replaced with the given colours.

You can see this in action here.

var makeGradientStyle = function(){
    var gradientString = '\
        /* Mozilla Firefox */ \
background-image: -moz-linear-gradient(top, {colour1} 0%, {colour2} 100%);\
        /* Opera */ \
        background-image: -o-linear-gradient(top, {colour1} 0%, {colour2} 100%);\
        /* Webkit (Safari/Chrome 10) */ \
        background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, {colour1}), color-stop(1, {colour2}));\
        /* Webkit (Chrome 11+) */ \
        background-image: -webkit-linear-gradient(top, {colour1} 0%, {colour2} 100%);\
        /* IE10+ */\
        background: -ms-linear-gradient(top,  {colour1} 0%,{colour2} 100%);\
        /* W3C */\
        background: linear-gradient(top,  {colour1} 0%,{colour2} 100%);\
    ';

    return function(colour1, colour2){
        return gradientString.replace(/\{colour1\}/g, colour1).replace(/\{colour2\}/g, colour2)
    }
}();

You can then apply as follows. The disadvantage lies in the fact that you're replacing the entire style string, but you can get round that with

var p = document.getElementById('p');

p.setAttribute('style', p.getAttribute('style') + '; ' + makeGradientStyle('#ff0000', '#0000ff'));
Share:
11,057

Related videos on Youtube

The_asMan
Author by

The_asMan

Updated on June 14, 2022

Comments

  • The_asMan
    The_asMan almost 2 years

    I have a div with the following gradient applied to it:

    /* Mozilla Firefox */ 
    background-image: -moz-linear-gradient(top, #2E2E28 0%, #4D4C48 100%);
    /* Opera */ 
    background-image: -o-linear-gradient(top, #2E2E28 0%, #4D4C48 100%);
    /* Webkit (Safari/Chrome 10) */ 
    background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #2E2E28), color-stop(1, #4D4C48));
    /* Webkit (Chrome 11+) */ 
    background-image: -webkit-linear-gradient(top, #2E2E28 0%, #4D4C48 100%);
    /* IE10+ */
    background: -ms-linear-gradient(top,  #2E2E28 0%,#4D4C48 100%);
    /* W3C */
    background: linear-gradient(top,  #2E2E28 0%,#4D4C48 100%);
    

    How could I change "#2E2E28" to another number, but still avoid the cross-browser nightmare?

    • The_asMan
      The_asMan
      @Piyuesh Nothing in that example preserves cross-browser functionality
  • The_asMan
    The_asMan almost 11 years
    Assigning the style as a whole attribute is an interesting idea.
  • The_asMan
    The_asMan almost 11 years
    just tested again jsfiddle.net/soyuka/vnQke does not work in safari on ipad or safari on windows 7 pc
  • soyuka
    soyuka almost 11 years
    You're right it's working on opera, ff, chrome but not safari, I'm trying to find why.
  • soyuka
    soyuka almost 11 years
    @The_asMan Now it's working on safari, can you test on iPad ? I didn't tried on IE though.
  • Barney
    Barney almost 11 years
    You need to specify different style properties depending on the implementation. I figure you've already got the CSS using in-built logic to handle the different variations, so JS can stick to the stuff it's good at: dynamic modification and DOM manipulation. The other advantage with this method is that you could easily modify the CSS string to cater for old IE via filter or some such.
  • Barney
    Barney almost 11 years
    The key thing being that you don't have to implement alternative logic to determine the appropriate implementation method: CSS takes care of that itself.
  • The_asMan
    The_asMan almost 11 years
    broken in chrome and IE9 not sure need it to work on ie9 but cant test 10 atm
  • soyuka
    soyuka almost 11 years
    Please test IE10, it won't work with IE9 I've worked on it this morning but it seems a bit useless to me. For IE9 it needs the filter attr, only 2 colors compatible and I'm on OS X so it's hard to debug. Maybe you can implement it yourself :).
  • The_asMan
    The_asMan almost 11 years
    The specs for our new system haven't been fully set yet but they keep saying "HTML5" so like i was saying probably do not have to support IE9 and under. so can ignore filter. And I don't have an IE10 test environment set up for me yet. I swear you had it working in chrome yesterday
  • Charles Robertson
    Charles Robertson over 6 years
    @Barney This is a great answer. Thinking outside the box. I have packaged it into a lightweight jQuery plugin, below...