简体   繁体   中英

How can I avoid flickering when image is changed for another with MouseEvent?

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.

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.

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM