135

I'm trying to make a "fade-in fade-out" effect using the CSS transition. But I can't get this to work with the background image...

The CSS:

.title a {
    display: block;
    width: 340px;
    height: 338px;
    color: black;
    background: transparent;
    /* TRANSITION */
    -webkit-transition: background 1s;
    -moz-transition: background 1s;
    -o-transition: background 1s;
    transition: background 1s;
}

.title a:hover {
    background: transparent;
    background: url(https://lh3.googleusercontent.com/-p1nr1fkWKUo/T0zUp5CLO3I/AAAAAAAAAWg/jDiQ0cUBuKA/s800/red-pattern.png) repeat;
    /* TRANSITION */
    -webkit-transition: background 1s;
    -moz-transition: background 1s;
    -o-transition: background 1s;
    transition: background 1s;
}​

Take a look: http://jsfiddle.net/AK3La/

Alexis Wilke
  • 15,168
  • 8
  • 60
  • 116
Nick Zani
  • 1,351
  • 2
  • 9
  • 3

13 Answers13

105

You can transition background-image. Use the CSS below on the img element:

-webkit-transition: background-image 0.2s ease-in-out;
transition: background-image 0.2s ease-in-out;

This is supported natively by Chrome, Opera and Safari. Firefox hasn't implemented it yet (bugzil.la). Not sure about IE.

Salman von Abbas
  • 21,808
  • 8
  • 64
  • 56
Hengjie
  • 4,267
  • 2
  • 27
  • 35
  • 121
    `background-image` is not an animatable property (http://www.w3.org/TR/css3-transitions/#animatable-properties), so your solution is not standard compliant. – TLindig May 20 '14 at 08:08
  • 13
    This is not a solution - FF and IE do not support it, and as noted above it's not a property the spec says should be supported. – Sentinel May 23 '14 at 07:45
  • See also for current development in Fx: https://bugzilla.mozilla.org/show_bug.cgi?id=546052 – Volker E. Oct 28 '14 at 18:14
  • 3
    @TLindig It should be an animatable property. –  Jan 03 '15 at 14:30
  • @Hengjie How did you know webkit browsers supported `transition: background-image`? Source? – Michael Lynch Jun 17 '15 at 15:11
  • What if I have multiple background images? Can I somehow only address one of the background images to animate? – Markus Ende Nov 13 '15 at 08:37
  • According to [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_animated_properties) background-image is an animatable property. Perhaps this has changed since 2014? – Coquelicot Sep 03 '16 at 03:59
  • @Coquelicot it must have been added to that list by mistake because it has since been removed. – kjb Dec 03 '16 at 15:17
  • 3
    The animatable property is `background`, and this is what should be used (it works in Chrome for me). Maybe the spec (or the impl) has changed since the question was posted – fps Feb 03 '17 at 22:10
  • I am working with this atm and can confirm transition of "background-image" working on Chrome and Safari. It adds a nice touch and I wish FF and IE would implement it as well. – Pedroinpeace Aug 28 '18 at 20:11
  • @TLindig's link is dead. The animation type of [`background-image`](https://drafts.csswg.org/css-backgrounds-3/#propdef-background-image) can be referenced [here](https://drafts.csswg.org/web-animations-1/#animation-types). – CalMlynarczyk Jul 23 '19 at 19:01
37

The solution (that I found by myself) is a ninja trick, I can offer you two ways:

first you need to make a "container" for the <img>, it will contain normal and hover states at the same time:

<div class="images-container">
    <img src="http://lorempixel.com/400/200/animals/9/">
    <img src="http://lorempixel.com/400/200/animals/10/">
</div>

Basically, you need to hide "normal" state and show their "hover" when you hover it

and that's it, I hope somebody find it useful.

Martijn Pieters
  • 889,049
  • 245
  • 3,507
  • 2,997
Ruffo
  • 420
  • 1
  • 5
  • 14
  • Nice solution. When experimenting with the first sample, I noticed that if you increase the transition duration to 4s, you can see a very noticable jump when the z-index switches in the middle of the transition. At least on Chrome 35, you can shift the timing of the z-index switch and clean up the transition by changing the property value to "all 4s ease, z-index 1ms" (http://jsfiddle.net/eD2zL/330/). – Neal Stublen Jul 01 '14 at 17:55
  • 2
    @NealS. you're right. This answer is 2 years old though, I would remove z-index, it seems unnecessary. The images just need to be in order. – Ruffo Jul 01 '14 at 19:36
  • Thanks a lot. Your solution is very helpful for me. – Volodymyr Chumak Apr 03 '15 at 14:58
  • Is possible "lazy loading" if I use this solution? – Daniel Nov 08 '16 at 23:57
16

I've figured out a solution that worked for me...

If you have a list item (or div) containing only the link, and let's say this is for social links on your page to facebook, twitter, ect. and you're using a sprite image you can do this:

<li id="facebook"><a href="facebook.com"></a></li>

Make the "li"s background your button image

#facebook {
   width:30px;
   height:30px;
   background:url(images/social) no-repeat 0px 0px;
}

Then make the link's background image the hover state of the button. Also add the opacity attribute to this and set it to 0.

#facebook a {
   display:inline-block;
   background:url(images/social) no-repeat 0px -30px;
   opacity:0;
}

Now all you need is "opacity" under "a:hover" and set this to 1.

#facebook a:hover {
   opacity:1;
}

Add the opacity transition attributes for each browser to "a" and "a:hover" so the the final css will look something like this:

#facebook {
   width:30px;
   height:30px;
   background:url(images/social) no-repeat 0px 0px;
}
#facebook a {
   display:inline-block;
   background:url(images/social) no-repeat 0px -30px;
   opacity:0;
   -webkit-transition: opacity 200ms linear;
   -moz-transition: opacity 200ms linear;
   -o-transition: opacity 200ms linear;
   -ms-transition: opacity 200ms linear;
   transition: opacity 200ms linear;
}
#facebook a:hover {
   opacity:1;
   -webkit-transition: opacity 200ms linear;
   -moz-transition: opacity 200ms linear;
   -o-transition: opacity 200ms linear;
   -ms-transition: opacity 200ms linear;
   transition: opacity 200ms linear;
}

If I explained it correctly that should let you have a fading background image button, hope it helps at least!

  • 3
    I also made a video tutorial version of it. http://www.youtube.com/watch?v=6ieR5ApVpr0 – Austin Parrish Thomas Feb 28 '13 at 22:23
  • You shouldn't, AFAIK, need to specify the transitions on the hover pseudoclass; the transition definition for the anchor tag type will carry forward to the hover behavior, all you need to change is the opacity. Keep in mind that this example works well because the styles are applied directly to IDs/tag types; if you do this with classes, you have to make sure you aren't adding and removing the class with the transition defined. – KeithS Mar 30 '17 at 16:45
15

Unfortunately you can't use transition on background-image, see the w3c list of animatable properties.

You may want to do some tricks with background-position.

Taras Yaremkiv
  • 3,205
  • 6
  • 25
  • 48
Olwaro
  • 315
  • 1
  • 8
14

You can use pseudo element to get the effect you want like I did in that Fiddle.

CSS:

.title a {
    display: block;
    width: 340px;
    height: 338px;
    color: black;
    position: relative;
}
.title a:after {
    background: url(https://lh3.googleusercontent.com/-p1nr1fkWKUo/T0zUp5CLO3I/AAAAAAAAAWg/jDiQ0cUBuKA/s800/red-pattern.png) repeat;
    content: "";
    opacity: 0;
    width: inherit;
    height: inherit;
    position: absolute;
    top: 0;
    left: 0;
    /* TRANSISITION */
    transition: opacity 1s ease-in-out;
    -webkit-transition: opacity 1s ease-in-out;
    -moz-transition: opacity 1s ease-in-out;
    -o-transition: opacity 1s ease-in-out;
}
.title a:hover:after{   
    opacity: 1;
}

HTML:

<div class="title">
    <a href="#">HYPERLINK</a>
</div>
Zach Saucier
  • 21,903
  • 12
  • 75
  • 126
MaxCloutier
  • 197
  • 1
  • 10
  • 2
    This works great, but you may run into 2 problems: 1) if you don't see the `:after` element, try setting `width` and `height` as `100%` instead of `inherit`, 2) if the `background-image` is actually displayed in _foreground_, use negative index for the `:after` element: `z-index: -1;` – Radek Pech Oct 26 '15 at 08:09
10

If you can use jQuery, you can try BgSwitcher plugin to switch the background-image with effects, it's very easy to use.

For example :

$('.bgSwitch').bgswitcher({
        images: ["style/img/bg0.jpg","style/img/bg1.jpg","style/img/bg2.jpg"],
        effect: "fade",
        interval: 10000
});

And add your own effect, see adding an effect types

MaxDhn
  • 145
  • 1
  • 7
6

Try this, will make the background animated worked on web but hybrid mobile app not working

@-webkit-keyframes breath {
 0%   {  background-size: 110% auto; }
 50%  {  background-size: 140% auto; }
 100% {  background-size: 110% auto; }      
}
body {
   -webkit-animation: breath 15s linear infinite;
   background-image: url(images/login.png);
    background-size: cover;
}
Hesham Nasser
  • 101
  • 2
  • 5
4

Considering background-images can't be animated, I created a little SCSS mixin allowing to transition between 2 different background-images using pseudo selectors before and after. They are at different z-index layers. The one that is ahead starts with opacity 0 and becomes visible with hover.

You can use it the same approach for creating animations with linear-gradients too.

scss

@mixin bkg-img-transition( $bkg1, $bkg2, $transTime:0.5s ){  
  position: relative;  
  z-index: 100; 
  &:before, &:after {
    background-size: cover;  
    content: '';    
    display: block;
    height: 100%;
    position: absolute;
    top: 0; left: 0;    
    width: 100%;    
    transition: opacity $transTime;
  }
  &:before {    
    z-index: -101;
    background-image: url("#{$bkg1}");    
  }
  &:after {    
    z-index: -100;
    opacity: 0;
    background-image: url("#{$bkg2}");    
  }
  &:hover {
     &:after{
       opacity: 1; 
     }
  }  
}

Now you can simply use it with

@include bkg-img-transition("https://picsum.photos/300/300/?random","https://picsum.photos/g/300/300");

You can check it out here: https://jsfiddle.net/pablosgpacheco/01rmg0qL/

Community
  • 1
  • 1
Pablo S G Pacheco
  • 2,170
  • 23
  • 23
  • Very nice solution! Gave me a better understanding of how to make good use of the element states ':before' and ':after' as a bonus :-) – joronimo Apr 09 '19 at 00:19
3

If animating opacity is not an option, you can also animate background-size.

For example, I used this CSS to set a backgound-image with a delay.

.before {
  background-size: 0;
}

.after {
  transition: background 0.1s step-end;
  background-image: $path-to-image;
  background-size: 20px 20px;
}
shock_one
  • 5,427
  • 2
  • 24
  • 35
  • If you want a fade-out effect from `.after` into `.before` for the background image, you must set the background image into the `.before`. Otherwise it will just disappear without animation. – Radek Pech Oct 22 '15 at 12:51
2

With Chris's inspiring post here:

https://css-tricks.com/different-transitions-for-hover-on-hover-off/

I managed to come up with this:

#banner
{
    display:block;
    width:100%;
    background-repeat:no-repeat;
    background-position:center bottom;
    background-image:url(../images/image1.jpg);
    /* HOVER OFF */
    @include transition(background-image 0.5s ease-in-out); 

    &:hover
    {
        background-image:url(../images/image2.jpg);
        /* HOVER ON */
        @include transition(background-image 0.5s ease-in-out); 
    }
}
Carol McKay
  • 2,251
  • 1
  • 11
  • 13
2

Salam, this answer works only in Chrome, cause IE and FF support color transition.

There is no need to make your HTML elements opacity:0, cause some times they contain text, and no need to double your elements!.

The question with link to an example in jsfiddle needed a small change, that is to put an empty image in .title a like background:url(link to an empty image); same as you put it in .title a:hover but make it empty image, and the code will work.

.title a {
display: block;
width: 340px;
height: 338px;
color: black;
background: url(https://upload.wikimedia.org/wikipedia/commons/5/59/Empty.png) repeat;
/* TRANSISITION */
transition: background 1s;
-webkit-transition: background 1s;
-moz-transition: background 1s;
-o-transition: background 1s;
  }
  .title a:hover{   background: transparent;
   background: url(https://lh3.googleusercontent.com/-p1nr1fkWKUo/T0zUp5CLO3I/AAAAAAAAAWg/jDiQ0cUBuKA/s800/red-pattern.png) repeat;
/* TRANSISITION */
transition: background 1s;
-webkit-transition: background 1s;
-moz-transition: background 1s;
-o-transition: background 1s;
}

Check this out https://jsfiddle.net/Tobasi/vv8q9hum/

0

This can be achieved with greater cross-browser support than the accepted answer by using pseudo-elements as exemplified by this answer: https://stackoverflow.com/a/19818268/2602816

vaer-k
  • 8,476
  • 7
  • 34
  • 51
0

I was struggling with this for a bit, I first used a stack of images on top of each other and every three seconds, I was trying to animate to the next image in the stack and throwing the current image to the bottom of the stack. At the same time I was using animations as shown above. I couldn't get it to work for the life of me.

You can use this library which allows for **dynamically-resized, slideshow-capable background image ** using jquery-backstretch.

https://github.com/jquery-backstretch/jquery-backstretch