84

I have this problem where I have set an image to display another image when the mouse hovers over, however the first image still appears and the new one doesn't change height and width and overlaps the other one. I'm still pretty new to HTML/CSS so I may have missed something simple. Here is the code:

<img src="LibraryTransparent.png" id="Library">
#Library {
    height: 70px;
    width: 120px;
}

#Library:hover {
    background-image: url('LibraryHoverTrans.png');
    height: 70px;
    width: 120px;
}
Nisse Engström
  • 4,738
  • 23
  • 27
  • 42
user2704743
  • 1,223
  • 5
  • 15
  • 14

22 Answers22

117

Another option is to use JS:

<img src='LibraryTransparent.png' onmouseover="this.src='LibraryHoverTrans.png';" onmouseout="this.src='LibraryTransparent.png';" />
kurdtpage
  • 3,142
  • 1
  • 24
  • 24
  • 6
    And while this is resurrecting an old solution, it is really a bad practice to embed styles with the HTML. All style info should be included at the top of the HTML file inside style tags, or linked from an external stylesheet. – the digitalmouse Jul 20 '16 at 08:39
  • Is there a way to smoothly transition the img? – CliffVandyck Dec 10 '17 at 14:43
  • @thedigitalmouse good point, I have updated my answer and removed CSS – kurdtpage Dec 12 '17 at 01:21
  • @CliffVandyck you could possibly use jQuery animation to do that – kurdtpage Dec 12 '17 at 01:21
  • Thanks a lot @kurdtpage for such a nice solution! :) How would it looks like if i wanna do that in a .js file. I would like to run that code in an .js file when i hover over the component :) – Noah Oct 31 '22 at 07:31
96

One solution is to use also the first image as a background image like this:

<div id="Library"></div>
#Library {
   background-image: url('LibraryTransparent.png');
   height: 70px;
   width: 120px;
}

#Library:hover {
   background-image: url('LibraryHoverTrans.png');
}

If your hover image has a different size, you've got to set them like so:

#Library:hover {
   background-image: url('LibraryHoverTrans.png');
   width: [IMAGE_WIDTH_IN_PIXELS]px;
   height: [IMAGE_HEIGHT_IN_PIXELS]px;
}
TylerH
  • 20,799
  • 66
  • 75
  • 101
Aurelio De Rosa
  • 21,856
  • 8
  • 48
  • 71
51

What I usually do is that I create a double image with both states, acting like kind of a two-frame film which I then use with as background for the original element so that the element has width / height set in pixels, resulting in showing only one half of the image. Then what the hover state defines is basically "move the film to show the other frame".

For example, imagine that the image has to be a gray Tux, that we need to change to colorful Tux on hover. And the "hosting" element is a span with id "tuxie".

  1. I create 50 x 25 image with two Tuxes, one in color and other gray,
  2. then assign the image as a background for a 25 x 25 span,
  3. and finally set the hover to simply move the background 25px left.

The minimal code:

<style>
    #tuxie {
        width: 25px; height: 25px;
        background: url('images/tuxie.png') no-repeat left top;
    }
    #tuxie:hover { background-position: -25px 0px }
</style>

<div id="tuxie" />

and the image:

Two-frame Tuxie "film"

Advantages are:

  • By putting both frames in one file, it's ensured that they are loaded at once. This avoids the ugly glitch on slower connections when the other frame never loads immediately, so first hover never works properly.

  • It may be easier to manage your images this way since "paired" frames are never confused.

  • With smart use of Javascript or CSS selector, one can extend this and include even more frames in one file.

    In theory you could put even multiple buttons in single file and govern their display by coordinates, although such approach could get quickly out of hand.

Note that this is built with background CSS property, so if you really need to use with <img />s, you must not set the src property since that overlaps the background. (Come to think that clever use of transparency here could lead to interesting results, but probably very dependent on quality of image as well as of the engine.).

Alois Mahdal
  • 10,763
  • 7
  • 51
  • 69
  • 2
    +1 for using "sprites", Sprites are making pages load faster, a good online tool that can help creating sprites for an existing website is [SpriteMe](http://spriteme.org/), it's very useful to create sprites faster as it will create the new CSS and images for you. – jagb Apr 15 '17 at 21:39
  • This is really cool. Would you answer a new question on click image instead of hover with ability to get current state of on/off? (Top half/bottom half of image currently displayed)? Or would that be a duplicate question? – WinEunuuchs2Unix Mar 24 '22 at 00:45
41

Use content:

#Library {
    height: 70px;
    width: 120px;
}

#Library:hover {
    content: url('http://www.furrytalk.com/wp-content/uploads/2010/05/2.jpg');
    height: 70px;
    width: 120px;
}

JSFiddle

Nisse Engström
  • 4,738
  • 23
  • 27
  • 42
Vucko
  • 20,555
  • 10
  • 56
  • 107
  • 4
    I think this is the best solution. It's simpler, uses the proper tag, and doesn't have to worry with background-repeat and stuff like that. – Lombas Jun 02 '16 at 17:37
  • 2
    I found this to be browser dependent. Works in Chrome, but not Firefox or IE11. – Chaz Nov 28 '17 at 18:26
  • @Chaz check the [Browser compatibility](https://developer.mozilla.org/en-US/docs/Web/CSS/content#Browser_compatibility). – Vucko Nov 29 '17 at 08:02
  • 1
    @Vucko, I believe the compatibility issue is with regard to using the content attribute on something that is not :before or :after. From the Browser Compatibility link: The content CSS property is used with the ::before and ::after pseudo-elements to generate content in an element. Try the JSFiddle above in Firefox or IE; it does not work. – Chaz Dec 04 '17 at 20:03
  • 1
    It's the best answer. Thank you very much. – Hsinhsin Hung Mar 04 '21 at 14:27
8

.hover_image:hover {text-decoration: none} /* Optional (avoid undesired underscore if a is used as wrapper) */
.hide {display:none}
/* Do the shift: */
.hover_image:hover img:first-child{display:none}
.hover_image:hover img:last-child{display:inline-block}
<body> 
    <a class="hover_image" href="#">
        <!-- path/to/first/visible/image: -->
        <img src="http://farmacias.dariopm.com/cc2/_cc3/images/f1_silverstone_2016.jpg" />
        <!-- path/to/hover/visible/image: -->
        <img src="http://farmacias.dariopm.com/cc2/_cc3/images/f1_malasia_2016.jpg" class="hide" />
    </a>
</body>

To try to improve this Rashid's good answer I'm adding some comments:

The trick is done over the wrapper of the image to be swapped (an 'a' tag this time but maybe another) so the 'hover_image' class has been put there.

Advantages:

  • Keeping both images url together in the same place helps if they need to be changed.

  • Seems to work with old navigators too (CSS2 standard).

  • It's self explanatory.

  • The hover image is preloaded (no delay after hovering).

Darío Pm
  • 139
  • 1
  • 9
6

The problem with all the previous answers is that the hover image isn't loaded with the page so when the browser calls it, it takes time to load and the whole thing doesn't look really good.

What I do is that I put the original image and the hover image in 1 element and hide the hover image at first. Then at hover in I display the hover image and hide the old one, and at hover out I do the opposite.

HTML:

<span id="bellLogo" onmouseover="hvr(this, 'in')" onmouseleave="hvr(this, 'out')">
  <img src="stylesheets/images/bell.png" class=bell col="g">
  <img src="stylesheets/images/bell_hover.png" class=bell style="display:none" col="b">
</span>

JavaScript/jQuery:

function hvr(dom, action)
{
    if (action == 'in')
    {
        $(dom).find("[col=g]").css("display", "none");
        $(dom).find("[col=b]").css("display", "inline-block");
    }

    else
    {
        $(dom).find("[col=b]").css("display", "none");
        $(dom).find("[col=g]").css("display", "inline-block");
    }
}

This to me is the easiest and most efficient way to do it.

Y2H
  • 2,419
  • 1
  • 19
  • 37
3

You can replace the image of an HTML IMG without needing to make any background image changes to the container div.

This is obtained using the CSS property box-sizing: border-box; (It gives you a possibility to put a kind of hover effect on an <IMG> very efficiently.)

To do this, apply a class like this to your image:

.image-replacement {
  display: block;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
  background: url(http://akamaicovers.oreilly.com/images/9780596517748/cat.gif) no-repeat;/* this image will be shown over the image iSRC */
  width: 180px;
  height: 236px;
  padding-left: 180px;
}

Sample code: http://codepen.io/chriscoyier/pen/cJEjs

Original article: http://css-tricks.com/replace-the-image-in-an-img-with-css/

Hope this will help some of you guys who don't want to put a div to obtain an image having a "hover" effect.

Posting here the sample code:

HTML:

<img id="myImage" src="images/photo1.png" class="ClassBeforeImage-replacement">

jQuery:

$("#myImage").mouseover(function () {
    $(this).attr("class", "image-replacement");
});
$("#myImage").mouseout(function () {
    $(this).attr("class", "ClassBeforeImage-replacement");
});
Nisse Engström
  • 4,738
  • 23
  • 27
  • 42
Nishanth Shaan
  • 1,422
  • 15
  • 18
2

You can't use CSS to change image SRC attributes (unless the browser supports it). You may want to use jQuery with the hover event.

$("#Library ").hover(
    function () {
         $(this).attr("src","isHover.jpg");
    },
    function () {
        $(this).attr("src","notHover.jpg");
    }
);
Nisse Engström
  • 4,738
  • 23
  • 27
  • 42
Asaf
  • 557
  • 1
  • 7
  • 15
2

.foo img:last-child{display:none}
.foo:hover img:first-child{display:none}
.foo:hover img:last-child{display:inline-block}
<body> 
    <a class="foo" href="#">
        <img src="http://lojanak.com/image/9/280/280/1/0" />
        <img src="http://lojanak.com/image/0/280/280/1/0" />
    </a>
</body>
Rashid
  • 29
  • 3
1

Change the img tag to a div and give it a background in CSS.

Jacques ジャック
  • 3,682
  • 2
  • 20
  • 43
1

try one of them

<img src='images/icons/proceed_button.png' width='120' height='70' onmouseover="this.src='images/icons/proceed_button2.png';" onmouseout="this.src='images/icons/proceed_button.png';" />

or if you using image as a button in form

<input type="image" id="proceed" src="images/icons/proceed_button.png" alt"Go to Facebook page" onMouseOver="fnover();"onMouseOut="fnout();" onclick="fnclick()">
function fnover()
        {
            var myimg2 = document.getElementById("proceed");
            myimg2.src = "images/icons/proceed_button2.png";
        }

        function fnout()
        {
            var myimg2 = document.getElementById("proceed");
            myimg2.src = "images/icons/proceed_button.png";
        }
Adiii
  • 54,482
  • 7
  • 145
  • 148
0

The problem is that you set the first image through 'src' attribute and on hover added to the image a background-image. try this:

in html use:

<img id="Library">

then in css:

#Library {
    height: 70px;
    width: 120px;
    background-image: url('LibraryTransparent.png');
}

#Library:hover {
    background-image: url('LibraryHoverTrans.png');
}
Tomzan
  • 2,808
  • 14
  • 25
0

check this fiddle

I think the image path may be wrong in your case

the syntax looks right

background-image:url('http://www.bluecowcreative.ca/wp-content/uploads/2013/08/hi.jpg');
Vignesh Subramanian
  • 7,161
  • 14
  • 87
  • 150
0

In the way that you're doing things, it won't happen. You're changing the background image of the image, which is being blocked by the original image. Changing the height and width also won't happen. To change the src attribute of the image, you would need Javascript or a Javascript Library such as jQuery. You could however, change the image to a simple div (text) box, and have a background image that changes on hover, even though the div box itself will be empty. Here's how.

<div id="emptydiv"></div>

#emptydiv {

background-image: url("LibraryHover.png");
height: 70px;
width: 120px;

}

#emptydiv:hover {

background-image: url("LibraryHoverTrans.png");
height: 700px;
width: 1200px;

}

I hope this is what you're asking for :)

Daniel Schwarz
  • 284
  • 1
  • 10
0

With everyones answer using the background-image option they're missing one attribute. The height and width will set the container size for the image but won't resize the image itself. background-size is needed to compress or stretch the image to fit this container. I've used the example from the 'best answer'

<div id="Library"></div>
#Library {
   background-image: url('LibraryTransparent.png');
   background-size: 120px;
   height: 70px;
   width: 120px;
}

#Library:hover {
   background-image: url('LibraryHoverTrans.png');
}
Fi Horan
  • 503
  • 4
  • 14
0

My jquery solution.

function changeOverImage(element) {
        var url = $(element).prop('src'),
            url_over = $(element).data('change-over')
        ;

        $(element)
            .prop('src', url_over)
            .data('change-over', url)
        ;
    }
    $(document).delegate('img[data-change-over]', 'mouseover', function () {
        changeOverImage(this);
    });
    $(document).delegate('img[data-change-over]', 'mouseout', function () {
        changeOverImage(this);
    });

and html

<img src="https://placeholdit.imgix.net/~text?txtsize=33&txt=%3Cimg%20original%20/%3E&w=342&h=300" data-change-over="https://placeholdit.imgix.net/~text?txtsize=33&txt=%3Cimg%20over%20/%3E&w=342&h=300" />

Demo: JSFiddle demo

Regards

iBet7o
  • 758
  • 8
  • 9
0

Live Example: JSFiddle

The Accepted answer has some problem. The image wasn't resized there. Use background-size property for resizing the image.

HTML:

<div id="image"></div>

CSS:

#image {
   background-image: url('image1');
   background-size: 300px 390px;
   width: 300px;
   height:390px;
}

#image:hover{
  background: url("image2");
  background-size: 300px 390px;
}
Md Rafee
  • 5,070
  • 3
  • 23
  • 32
0

What I would recommend is to use only CSS if possible. My solution would be:

HTML:

<img id="img" class="" src="" />

CSS:

img#img{
    background: url("pictureNumberOne.png");
    background-size: 100px 100px;
    /* Optional transition: */
    transition: background 0.25s ease-in-out;
}
img#img:hover{
    background: url("pictureNumberTwo.png");
    background-size: 100px 100px;
}

That (not defining the src attribute) also ensures that transparent images (or images with transparent parts) are shown correctly (otherwise, if the second pic would be half-transparent, you would also see parts of the first picture).

The background-size attribute is used to set the height and width of a background-image.

If (for any reason) you don't want to change the bg-image of an image, you could also put the image in a div-container as following:

HTML:

<div id="imgContainer" class="">
    <img id="" class="" src="" />
</div>

... and so on.

j3141592653589793238
  • 1,810
  • 2
  • 16
  • 38
0

Use "content:;" at the hover.This works.

-1

Just use Photoshop and create two of the same image, the 1st one being how you want it to look, the 2nd being how you want it to look when it's hovered over. I'm wrapping the image in an <a> tag, because I'm assuming that it's what you want. For this example I'm doing a facebook icon which is desaturated, but when hovered over it will show the blue color of facebook.

<a href="www.facebook.com"><img src="place of 1st image" onmouseover="this.src='place of 2nd image'" onmouseout="this.src='place of 1st image'"></a>
Tunaki
  • 132,869
  • 46
  • 340
  • 423
Phong Ly
  • 1
  • 1
-1

Here is the simple trick. Just copy and paste it.

<!DOCTYPE html>
    <html lang="en">
    <head>
    <title>Change Image on Hover in CSS</title>
    <style type="text/css">
        .card {
            width: 130px;
            height: 195px;
            background: url("../images/card-back.jpg") no-repeat;
            margin: 50px;
        }
        .card:hover {
            background: url("../images/card-front.jpg") no-repeat;
        }
    </style>
    </head>
    <body>
        <div class="card"></div>
    </body>
    </html>       
-1

I had a similar problem.

With my button defined like:

<button  id="myButton" class="myButtonClass"></button>

I had the background styling like this:

#myButton{ background-image:url(img/picture.jpg)}

.myButtonClass{background-image:url(img/picture.jpg)}

.myButtonClass:hover{background-image:url(img/picture_hover.jpg)}

When I switched it to:

#myButton{}

.myButtonClass{background-image:url(img/picture.jpg)}

.myButtonClass:hover{background-image:url(img/picture_hover.jpg)}

The hover over feature worked just fine.

(not addressing other attributes like size and position of image or of container, just the background image changing)

wolfsshield
  • 757
  • 5
  • 14