21

Okay, so I have dynamically generated images via PHP, so not necessarily the same images result. And I've spent the last four hours scanning the internet and trying countless things with jQuery and/or CSS, and I've come up with the following that works.

    <a href="build.php?x=1875&y=2020"><img style='background:url(images/tile_4.jpg)' src='images/tile_4.jpg' onmouseover="this.src='images/Market.png'" onmouseout="this.src='images/tile_4.jpg'" /></a>
<a href="build.php?x=1876&y=2020"><img style='background:url(images/tile_4.jpg)' src='images/tile_4.jpg' onmouseover="this.src='images/Market.png'" onmouseout="this.src='images/tile_4.jpg'" /></a>
<a href="build.php?x=1877&y=2020"><img style='background:url(images/tile_4.jpg)' src='images/tile_4.jpg' onmouseover="this.src='images/Market.png'" onmouseout="this.src='images/tile_4.jpg'" /></a>
<a href="build.php?x=1878&y=2020"><img style='background:url(images/tile_4.jpg)' src='images/tile_4.jpg' onmouseover="this.src='images/Market.png'" onmouseout="this.src='images/tile_4.jpg'" /></a>
<a href="build.php?x=1879&y=2020"><img style='background:url(images/tile_4.jpg)' src='images/tile_4.jpg' onmouseover="this.src='images/Market.png'" onmouseout="this.src='images/tile_4.jpg'" /></a>

Market.png has a transparent background.

Now, the above works. On mouseover, it displays Market.png with the transparent background part being tile_4.jpg and out mouseout it is tile_4.jpg.

What I want to know: is there ANY way to accomplish the exact same thing as the above with jQuery or CSS? I haven't figured it out, and I've spent hours trying, but I'd rather do something else if at all possible since the above (with massive repetition, the above format is repeated currently around 100 times, but I have plans to expand it to over a 1000 times) will become a bandwidth hog.

Witold Kowelski
  • 924
  • 2
  • 12
  • 27
  • Well, the problem comes into effect when the image, being dynamically generated, isn't always the same image. For example, one of the other images is coded as: `` making a simple switch out of the question. – Witold Kowelski Jul 06 '13 at 23:12

3 Answers3

59

You could add a class to each of your <img /> elements, such as 'xyz' (please pick a better name), and then take advantage of the hover() function. Given that your images are dynamic, you could render the image markup with an extra data attribute to serve as the "alternate" or "hover" image source. In the end, you might render something like this:

<img class="xyz" data-alt-src="/images/Market.png" src="/images/tile_4.png" />
<img class="xyz" data-alt-src="/images/Something.png" src="/images/tile_5.png" />

And then to apply the switching functionality for each image, you can write a little function that swaps the image src attribute and the data-alt-src attribute on hover-in/hover-out:

var sourceSwap = function () {
    var $this = $(this);
    var newSource = $this.data('alt-src');
    $this.data('alt-src', $this.attr('src'));
    $this.attr('src', newSource);
}

And then it's as simple as executing the function directly using a tiny bit of jQuery event binding:

$(function () {
    $('img.xyz').hover(sourceSwap, sourceSwap);
});

Here's a working example (version 1):

var sourceSwap = function () {
        var $this = $(this);
        var newSource = $this.data('alt-src');
        $this.data('alt-src', $this.attr('src'));
        $this.attr('src', newSource);
    }

    $(function () {
        $('img.xyz').hover(sourceSwap, sourceSwap);
    });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<img class="xyz" data-alt-src="http://cdn1.iconfinder.com/data/icons/fatcow/32/accept.png" src="http://cdn1.iconfinder.com/data/icons/fatcow/32/cancel.png" />
<br/>
<img class="xyz" data-alt-src="http://cdn1.iconfinder.com/data/icons/fatcow/32/accept.png" src="http://cdn1.iconfinder.com/data/icons/fatcow/32/cancel.png" />
<br/>
<img class="xyz" data-alt-src="http://cdn1.iconfinder.com/data/icons/fatcow/32/accept.png" src="http://cdn1.iconfinder.com/data/icons/fatcow/32/cancel.png" />

Here is a spin on Andres Separ's example from the comments. With this selector, you don't need to decorate your images with a marker class. It will also pre-load the alternate source image to help eliminate any lag or flicker when hovering:

$(function() {
    $('img[data-alt-src]').each(function() { 
        new Image().src = $(this).data('alt-src'); 
    }).hover(sourceSwap, sourceSwap); 
});

And here's the second version:

var sourceSwap = function () {
        var $this = $(this);
        var newSource = $this.data('alt-src');
        $this.data('alt-src', $this.attr('src'));
        $this.attr('src', newSource);
    }

    $(function() {
        $('img[data-alt-src]').each(function() { 
            new Image().src = $(this).data('alt-src'); 
        }).hover(sourceSwap, sourceSwap); 
    });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<img data-alt-src="http://cdn1.iconfinder.com/data/icons/fatcow/32/accept.png" src="http://cdn1.iconfinder.com/data/icons/fatcow/32/cancel.png" />
<br/>
<img data-alt-src="http://cdn1.iconfinder.com/data/icons/fatcow/32/accept.png" src="http://cdn1.iconfinder.com/data/icons/fatcow/32/cancel.png" />
<br/>
<img data-alt-src="http://cdn1.iconfinder.com/data/icons/fatcow/32/accept.png" src="http://cdn1.iconfinder.com/data/icons/fatcow/32/cancel.png" />
Cᴏʀʏ
  • 105,112
  • 20
  • 162
  • 194
  • Yes, that works. Thanks, it's greatly appreciated. And it also does what I asked if was possible (reduce the amount of code generated in the DOM). Only one thing: seeing as how the overlay png image has a transparent background, it is still required to add `img.xyz{background:url(images/tile_4.png);}` into the document's stylesheet (using your example class of xyz), so that the transparent background is still that of the proper background image and not that of the page's background color. – Witold Kowelski Jul 07 '13 at 00:40
  • now thats a wonderful piece of script. – saurabh Apr 11 '14 at 13:30
  • 2
    @Cory Good work! **I suggest a little bit!** `$('img[data-alt-src]').each(function(){ var $this = $(this); new Image().src = $this.data('alt-src'); $this.hover(sourceSwap, sourceSwap); });` – Andres Separ Oct 07 '14 at 15:33
  • @AndresSepar: Thanks, the preloading is a nice touch. I've included your version in my answer. – Cᴏʀʏ Oct 07 '14 at 15:47
  • works great thank you! Especially version 2 with preloading :D – Can Rau Jul 12 '15 at 20:34
  • @AndresSepar, this is a great method, is the alternative image (`new Image()`) somehow 'attached' to each `img` selected by jQuery? It works great, but it's not clear to me how this pre-loading happens. – luqo33 Jul 20 '15 at 17:16
  • @luqo33: that code is enough for the browser to download the image and store it in the local cache. When it comes time to display the image, it's loading from cache instead, which eliminates the flicker by not having to download the image on demand. – Cᴏʀʏ Jul 20 '15 at 17:41
  • @Cᴏʀʏ so then in reality, `sourceSwap` function makes the browser load the alternative image from the cache and not perform DOM manipulation (swapping sources) ? – luqo33 Jul 20 '15 at 18:17
  • @luqo33: It still performs the DOM manipulation. The DOM layer really isn't any the wiser, it's the browser that was being smart by pre-loading (pre-downloading+caching) the images ahead of time, so that when it came time to do the image source swap, it doesn't have to take time downloading the images before it can display them, it simply loads them from the cache. The behavior is identical *without* the pre-loading, but only after the first on-demand download of the image sources. – Cᴏʀʏ Jul 20 '15 at 18:35
  • @Cᴏʀʏ all clear, thank you :) – luqo33 Jul 20 '15 at 18:39
  • Any clever wat to add click to stay on the data-alt-src image? – alex Sep 24 '17 at 15:49
  • This didn't work `.click(function() { var newSource = $(this).data('alt-src'); alert("bereikbaar "+newSource); $(this).attr('src', newSource); })` – alex Sep 24 '17 at 15:57
15

jQuery

You could use the mouseover and mouseout events :

$("img").on({
 "mouseover" : function() {
    this.src = 'images/Market.png';
  },
  "mouseout" : function() {
    this.src='images/tile_4.jpg';
  }
});

This way you could take out the attributes onmouseout and onmouseover from you HTML and make your code neat.

CSS

However, the easiest way is using CSS:

img {
  background-image: url('images/tile_4.jpg');
}

img:hover {
  background-image: url('images/Market.png');
}
krishwader
  • 11,341
  • 1
  • 34
  • 51
  • It's not always the same images, I said it was dynamically generated. For example, one of the other images is coded as: `` making a simple switch out of the question. – Witold Kowelski Jul 06 '13 at 23:14
  • @WitoldKowelski you'll have to provide the datasource then. from where ae you getting this data? is it JSON? – krishwader Jul 06 '13 at 23:17
  • It's in PHP, with the image src (and thus the onmouseout) coming from a MySQL database. Or is that not what you're asking? – Witold Kowelski Jul 06 '13 at 23:25
  • I think u must add a PHP tag to this question and throw in the code where in dynamically add the image, along with a lil snippet of the data u recieve from the server. – krishwader Jul 06 '13 at 23:27
  • Well, I could. If that'd be helpful. The anchor link isn't really that important I think, and it's all through a while loop that calls several PHP functions, but the variable that controls what image is displayed is coded as `src=\"images/$ImageNumber.jpg\"` where $imageNumber is the 2 in my first comment. If there is no row in the database that corresponds to the DB query, then the result is run through a different function that plainly prints the src out as `src='images/tile_4.jpg'` – Witold Kowelski Jul 06 '13 at 23:31
4

Sure, with jQuery it is easy.

$('img').hover(function(){
    $(this).attr('src','images/Market.png');
},function(){
     $(this).attr('src','images/tile_4.jpg'); 
});
Zevi Sternlicht
  • 5,399
  • 19
  • 31