1

I have a clickable image (logo) that I want to be defined in HTML (not CSS) since it's a logo that sits in the menu, should be scaled with the text and also is a semantic part of the content.

I want it to change on hover so:

<img src="logo.svg"
    onmouseover="this.src='logo_hover.svg'"
    onmouseout="this.src='logo.svg'">

The problem is that the menu and logo flickers when I hover the image. This doesn't always happen but seems to have to do with that it takes a blink for the new image to be scaled right. I have width: 100% on the logo and width: 5em set on the div that holds it.

How can I avoid this flickering? Should I set both width and height on the image, if so how do I find out what height the image should have? Or is there some other way to avoid the browser being "surprised" when the new image is loaded?


What I've triend so far:

I've already tried to preload the image with javascript, and also with a <link rel='prefetch'> tag, but the flickering still happens.

PetaspeedBeaver
  • 433
  • 6
  • 17
  • Why is css no good? You could use an image and set it to be the background-image of a div. This image would be too large and would contain both pics you wish to display. You would control the visible portion by using css, with the mouseover/mouseout functions just changing the offset of the image shown at the top left. Since you've only got one image, it would always be already loaded (loading is where your flicker comes from) and could have the offsets changed in the blink of an eye. (That's how SO does their icons - they're in a single file) – enhzflep Apr 20 '16 at 06:42
  • @enhzflep Very good idea, but I think it's still more correct to keep the image defined in an ``, what do you think? See my edit above for thoughts around this. – PetaspeedBeaver Apr 21 '16 at 09:28
  • 1
    Well, I've seen the trick used commonly. It's used for a number of reasons (0) to cut down on the number of requests to the server (1) to cut down on the wasted bytes transmitted, since you only need to send a single image header (2) it helps keep all your images together (3) it avoids flicker, since the 2nd image is guaranteed to be loaded already (4) you can make further bandwidth savings, since there's more chance of getting good compression on the image. If you navigate to http://cdn.sstatic.net/Sites/stackoverflow/img/sprites.svg?v=bc7c2f3904bf you can see one of SO's spritemaps. – enhzflep Apr 21 '16 at 10:49

3 Answers3

1

The flickering has probably to do with the new image not having been loaded, so it doesn't start to load until the moment you set the src attribute of the img tag. So to avoid this you would preload the new image with javascript.

If you want to know how to do this you can check out this answer: Load Image from javascript

But a better solution for switching images on hover would be to put both images into a spritesheet, set the image as background of a div, span, a, etc. and use the CSS background-position to make the hover-part of the image visible on hover as answered here: https://stackoverflow.com/a/19967062/1768033

Community
  • 1
  • 1
Martin Cup
  • 2,399
  • 1
  • 21
  • 32
1

If it's a matter of the image not being loaded when you hover the object, you only need preloading the image. You can do that in various ways.

You can do it without one bit of CSS by adding the image again at the very end of your page, and set this duplicate to have a width and height of 0. I suggest the "end of page" because you probably want the visible bits of your page to load first. If you put it at the beginning the loading time of the visible bits of the page may take a bit longer, but the rollover shouldn't need the page to be fully loaded to work.

<img src="myimage_onhover.png" height="0" width="0" />

This way the browser has the image on cache, even though it doesn't show up.

So if you have an image like:

<img src="myimage.png" onmouseover="this.src='myimage_onhover.png'" [...] />

When the user hovers over the image, the browser should fetch the cache image that was already loaded on this same page load.

Marc Compte
  • 4,579
  • 2
  • 16
  • 22
1

Based on what it looks like you're trying to do, I would strongly advise against this approach as you can actually manipulate properties of the SVG using just CSS for a hover state.

What are you changing on the logo - if I may ask?

If it were a case of colours etc you could use the approach of using the inline SVG code directly into your HTML and then using CSS to apply colours etc. This then enables you to edit those CSS properties for a hover state. The problem using SVGs via the img tag is you can't edit their properties — which I am sure you are aware of.

For istance - a svg logo:

<svg version="1.1" id="my-Logo" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
     viewBox="0 0 140.9 36.1" xml:space="preserve">
<g>
    <path d="M0,35.8v-35h7.8v28h14.9v7H0z"/>
    <path d="M56.9,30.9c-3.5,3.5-7.9,5.2-13.1,5.2c-5.2,0-9.5-1.7-13-5.2c-3.5-3.4-5.3-7.7-5.3-12.9c0-5.1,1.8-9.4,5.3-12.9
        c3.5-3.4,7.9-5.2,13-5.2c5.2,0,9.5,1.7,13.1,5.2c3.5,3.5,5.3,7.7,5.3,12.9C62.1,23.2,60.4,27.5,56.9,30.9z M54.2,18.1
        c0-3.1-1-5.8-3-8c-2-2.2-4.5-3.3-7.4-3.3c-2.9,0-5.4,1.1-7.4,3.3c-2,2.2-3,4.9-3,8c0,3.1,1,5.8,3,7.9c2,2.2,4.5,3.3,7.4,3.3
        c2.9,0,5.4-1.1,7.4-3.3C53.2,23.8,54.2,21.2,54.2,18.1z"/>
    <path d="M91.4,18h7.9v12.4c-3.5,3.9-8.3,5.8-14.4,5.8c-5.1,0-9.4-1.7-12.9-5.1c-3.5-3.4-5.2-7.7-5.2-12.9c0-5.2,1.8-9.5,5.3-13
        S79.9,0,84.9,0c5,0,9.4,1.6,13.1,5l-4,5.8c-1.6-1.4-3-2.3-4.3-2.8c-1.3-0.5-2.7-0.8-4.3-0.8c-3,0-5.5,1-7.5,3c-2,2-3,4.7-3,8
        c0,3.3,1,5.9,2.9,7.9c2,2,4.3,3,7,3s5-0.5,6.8-1.6V18z"/>
    <path d="M135.6,30.9c-3.5,3.5-7.9,5.2-13.1,5.2c-5.2,0-9.5-1.7-13-5.2c-3.5-3.4-5.3-7.7-5.3-12.9c0-5.1,1.8-9.4,5.3-12.9
        c3.5-3.4,7.9-5.2,13-5.2c5.2,0,9.5,1.7,13.1,5.2c3.5,3.5,5.3,7.7,5.3,12.9C140.9,23.2,139.2,27.5,135.6,30.9z M133,18.1
        c0-3.1-1-5.8-3-8c-2-2.2-4.5-3.3-7.4-3.3c-2.9,0-5.4,1.1-7.4,3.3c-2,2.2-3,4.9-3,8c0,3.1,1,5.8,3,7.9c2,2.2,4.5,3.3,7.4,3.3
        c2.9,0,5.4-1.1,7.4-3.3C132,23.8,133,21.2,133,18.1z"/>
</g>
</svg>

CSS for a hover color change:

#my-Logo{
  fill: orange;
}

#my-Logo:hover{
  fill: red;
}

You have far more flexibility if you want to edit / manipulate the SVG properties with this method that can avoid doing some over convoluted javascript magician shazaam.

Live Example

Gerico
  • 5,079
  • 14
  • 44
  • 85
  • Yes this is the best method, I tried this approach but had some compatibility issues with some not so old IE versions. But maybe I should go with this anyway and just accept that the logo doesn't change on some IE ... – PetaspeedBeaver Apr 21 '16 at 10:32
  • I assume perhaps IE8? You could always just use a fallback and display something other than an SVG, if that fits within the requirements of your project. – Gerico Apr 21 '16 at 10:35
  • 1
    **All answers are very good suggestions**, but I personally will go for this and if needed will use [Modernizr](https://en.wikipedia.org/wiki/Modernizr) to change to a png for the IE that has problems with changing color on the svg. – PetaspeedBeaver Apr 21 '16 at 18:32
  • This approach seems a bit ineffective if the svg appears more than once in the page though, it wouldn't be cached if it's written in the HTML ... – PetaspeedBeaver Apr 23 '16 at 19:47