212

I am making an expand/collapse call rates table for the company I work for. I currently have a table with a button under it to expand it, the button says "Expand". It is functional except I need the button to change to "Collapse" when it is clicked and then of course back to "Expand" when it is clicked again. The writing on the button is a background image.

So basically all I need is to change the background image of a div when it is clicked, except sort of like a toggle.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
zuk1
  • 18,009
  • 21
  • 59
  • 63

14 Answers14

459
$('#divID').css("background-image", "url(/myimage.jpg)");  

Should do the trick, just hook it up in a click event on the element

$('#divID').click(function()
{
  // do my image switching logic here.
});
Joel
  • 19,175
  • 2
  • 63
  • 83
Nick
  • 9,113
  • 4
  • 25
  • 29
  • @fuccboi it does, as I use this code to fire off an animated svg checkmark when a user selects an option. :) – norcal johnny Dec 03 '16 at 04:08
  • Good answere, i want do point out >> url() IS PART OF THE STRING << which is really confusing if you are coming from a strong typedef language – clockw0rk Sep 14 '18 at 11:04
62

I personally would just use the JavaScript code to switch between 2 classes.

Have the CSS outline everything you need on your div MINUS the background rule, then add two classes (e.g: expanded & collapsed) as rules each with the correct background image (or background position if using a sprite).

CSS with different images

.div {
    /* button size etc properties */
}

.expanded {background: url(img/x.gif) no-repeat left top;}
.collapsed {background: url(img/y.gif) no-repeat left top;}

Or CSS with image sprite

.div {
    background: url(img/sprite.gif) no-repeat left top;
    /* Other styles */
}

.expanded {background-position: left bottom;}

Then...

JavaScript code with images

$(function){
    $('#button').click(function(){
        if($(this).hasClass('expanded'))
        {
            $(this).addClass('collapsed').removeClass('expanded');
        }
        else
        {
            $(this).addClass('expanded').removeClass('collapsed');
        }
    });
}

JavaScript with sprite

Note: the elegant toggleClass does not work in Internet Explorer 6, but the below addClass/removeClass method will work fine in this situation as well

The most elegant solution (unfortunately not Internet Explorer 6 friendly)

$(function){
        $('#button').click(function(){
            $(this).toggleClass('expanded');
        });
    }

$(function){
        $('#button').click(function(){
            if($(this).hasClass('expanded'))
            {
                $(this).removeClass('expanded');
            }
            else
            {
                $(this).addClass('expanded');
            }
        });
    }

As far as I know this method will work accross browsers, and I would feel much more comfortable playing with CSS and classes than with URL changes in the script.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Kelly
  • 629
  • 5
  • 2
49

There are two different ways to change a background image CSS with jQuery.

  1. $('selector').css('backgroundImage','url(images/example.jpg)');
  2. $('selector').css({'background-image':'url(images/example.jpg)'});

Look carefully to note the differences. In the second, you can use conventional CSS and string multiple CSS properties together.

Ecropolis
  • 2,005
  • 2
  • 22
  • 27
  • 6
    2. is incorrect an invalid. Stringing multiple properties together is done like this: $('selector').css({'background-color':'yellow','background-image':'url()'}) – codecowboy Jul 20 '11 at 15:26
  • If I try 2. , I get an error - Uncaught SyntaxError: Unexpected token : – geeky_monster May 10 '12 at 13:56
  • Correctly, but i had to use the whole path to make it work! Not working: "url(../images/img.jpg)" – Flemming Jul 05 '20 at 09:30
17

If you use a CSS sprite for the background images, you could bump the background offset +/- n pixels depending on whether you were expanding or collapsing. Not a toggle, but closer to it than having to switch background image URLs.

Dave Ward
  • 59,815
  • 13
  • 117
  • 134
  • 2
    Bonus: Ifyou use separate images only the one that is displayed on load is actually loaded. There will be a small delay when switching images before the second state is loaded. With a sprite, you only have one image and it will already be there. – Lasar Oct 31 '08 at 15:29
14

Here is how I do it:

CSS

#button{
   background-image: url("initial_image.png");
}

#button.toggled{
  background-image:url("toggled_image.png");
}

JS

$('#button').click(function(){
  $('#my_content').toggle();
  $(this).toggleClass('toggled');
});
Loupax
  • 4,728
  • 6
  • 41
  • 68
10

One way to do this is to put both images in the HTML, inside a SPAN or DIV, you can hide the default either with CSS, or with JS on page load. Then you can toggle on click. Here is a similar example I am using to put left/down icons on a list:

$(document).ready(function(){
    $(".button").click(function () {
        $(this).children(".arrow").toggle();
            return false;
    });
});

<a href="#" class="button">
    <span class="arrow">
        <img src="/images/icons/left.png" alt="+" />
    </span>
    <span class="arrow" style="display: none;">
        <img src="/images/down.png" alt="-" />
    </span>
</a>
alexp206
  • 1,739
  • 1
  • 16
  • 20
6

Mine is animated:

$(this).animate({
    opacity: 0
}, 100, function() {
    // Callback
    $(this).css("background-image", "url(" + new_img + ")").promise().done(function(){
        // Callback of the callback :)
        $(this).animate({
            opacity: 1
        }, 600)
    });    
});
yPhil
  • 8,049
  • 4
  • 57
  • 83
5

I did mine using regular expressions, since I wanted to preserve a relative path and not use add the addClass function. I just wanted to make it convoluted, lol.

$(".travelinfo-btn").click(
            function() {
                $("html, body").animate({scrollTop: $(this).offset().top}, 200);
                var bgImg = $(this).css('background-image')
                var bgPath = bgImg.substr(0, bgImg.lastIndexOf('/')+1)
                if(bgImg.match(/collapse/)) {
                    $(this).stop().css('background-image', bgImg.replace(/collapse/,'expand'));
                    $(this).next(".travelinfo-item").stop().slideToggle(400);
                } else {
                    $(this).stop().css('background-image', bgImg.replace(/expand/,'collapse'));
                    $(this).next(".travelinfo-item").stop().slideToggle(400);
                }
            }
        );
user2220104
  • 51
  • 1
  • 1
5

This works on all current browsers on WinXP. Basically just checking what the current backgrond image is. If it's image1, show image2, otherwise show image1.

The jsapi stuff just loads jQuery from the Google CDN (easier for testing a misc file on the desktop).

The replace is for cross-browser compatibility (opera and ie add quotes to the url and firefox, chrome and safari remove quotes).

<html>
    <head>
        <script src="http://www.google.com/jsapi"></script>
        <script>
          google.load("jquery", "1.2.6");
          google.setOnLoadCallback(function() {
            var original_image = 'url(http://stackoverflow.com/Content/img/wmd/link.png)';
            var second_image = 'url(http://stackoverflow.com/Content/img/wmd/code.png)';

            $('.mydiv').click(function() {
                if ($(this).css('background-image').replace(/"/g, '') == original_image) {
                    $(this).css('background-image', second_image);
                } else {
                    $(this).css('background-image', original_image);
                }

                return false;
            });
          });
        </script>

        <style>
            .mydiv {
                background-image: url('http://stackoverflow.com/Content/img/wmd/link.png');
                width: 100px;
                height: 100px;
            }
        </style>
    </head>
    <body>
        <div class="mydiv">&nbsp;</div>
    </body>
</html>
enobrev
  • 22,314
  • 7
  • 42
  • 53
  • 1
    just did it for the example. This way, the whole code snippet works on its own. – enobrev Oct 31 '08 at 14:44
  • 20
    Loading it from Google is preferable for public facing sites. Google's CDN is very likely faster than your site, allows it to download in parallel with something else on your site, and the more sites that use it the more likely a cached copy from the user's browser will be used. – Dave Ward Oct 31 '08 at 15:32
  • Although loading it from Google allows them to track your visitors and insert arbitrary code into your site. And if Google is down (NO WAI!!), your JS won’t work anymore. – scy Aug 16 '10 at 14:12
  • 2
    If Google goes down and I'm still alive; let me know. – greenimpala Dec 13 '10 at 22:55
  • 1
    @Nick Go to jQuery.com, you'll find their own website uses ` ` – user229044 Apr 08 '11 at 18:57
  • 2
    @Nick The question should really be, why *wouldn't* you want to load if off Google. :-) – John Parker Apr 08 '11 at 19:12
  • When you work in corporate IT environments, some corps have their own CDNs or are extremely restrictive on what you are serving up and from where. – Nick Apr 09 '11 at 14:24
3

Old post, but this would allow you to use an image sprite and adjust the repeat as well as positioning by using the shorthand for the css property (background, repeat, left top).

$.each($('.smallPreview'), function(i){
  var $this = $(this);

  $this.mouseenter(function(){
    $this.css('background', 'url(Assets/imgs/imgBckg-Small_Over.png) no-repeat 0 0');
  });

  $this.mouseleave(function(){
    $this.css('background', 'url(Assets/imgs/imgBckg-Small.png) no-repeat 0 0');
  });

});
bphillips
  • 459
  • 2
  • 5
3

I always use a timestamp as well to prevent browsers from caching the image. For example, if the user is rotating their avatar, it will often get cached and appear to not change.

var d = new Date();
var t = d.getTime();

$('#avatar').css("background-image", "url(" + iPath + "?" + t + ")");
AdamVanBuskirk
  • 509
  • 4
  • 10
2

This is a fairly simple response changes the background of the site with a list of items

function randomToN(maxVal) {
    var randVal = Math.random() * maxVal;
    return typeof 0 == 'undefined' ? Math.round(randVal) : randVal.toFixed(0);
};
var list = [ "IMG0.EXT", "IMG2.EXT","IMG3.EXT" ], // Images
    ram = list[parseFloat(randomToN(list.length))], // Random 1 to n
    img = ram == undefined || ram == null ? list[0] : ram; // Detect null
$("div#ID").css("backgroundImage", "url(" + img + ")"); // push de background
2

I've found a solution in a forum, Toggle Background Img.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • Welcome to Stack Overflow, Sebastian. This question was asked over a year ago, and already has several acceptable answers. – rjh Mar 24 '10 at 15:47
2

CSS Sprites work best. I tried switching classes and manipulating the 'background-image' property with jQuery, none worked. I think it's because the browsers (at least the latest stable Chrome) can't "reload" an image already loaded.

Bonus : CSS Sprites are faster to download and faster to display. Less HTTP requests means faster page load. Reducing the number of HTTP is the best way to improve front end performance, so I recommend going this route all the time.

DjebbZ
  • 1,594
  • 1
  • 18
  • 34