Search code examples
cssscale

How can I create an infinite scale mouseover animation with a smooth mouseout effect with css?


I'm coding a CSS3 effect fired on mouseover; this effect simply animate an inner div scaling it endlessly.

All works great, but when I move the mouse away the div suddenly return to its original size. I would like to add a smooth effect to scale the div back.

I already checked the suggestion of this post: Make CSS Hover state remain after "unhovering" Unfortunately the code posted doesn't work :( In my opinion my issue could be related with the "infinite" loop of the scale effect.

THe goal I would like to gain is the on mouse-out the image could return to its original size smoothly.

Here's the code: https://jsfiddle.net/9dtqpsLa/1/

CSS

@keyframes imageZoom{
    0% { transform: scale(1); }
    50% { transform: scale(1.24); }
    100% { transform: scale(1);}
}

@-moz-keyframes imageZoom{
    0% { -moz-transform: scale(1);}
    50% { -moz-transform: scale(1.24); }
    100% { -moz-transform: scale(1); }
}

@-webkit-keyframes imageZoom{
    0% { -webkit-transform: scale(1); }
    50% {-webkit-transform: scale(1.24); }
    100% { -webkit-transform: scale(1); }
}

@-ms-keyframes imageZoom{
    0% { -ms-transform: scale(1); }
    50% { -ms-transform: scale(1.24); }
    100% { -ms-transform: scale(1); }
}

.article:hover .imageWrapper {
    animation: imageZoom linear 10s;
    animation-iteration-count: infinite;
    -webkit-animation: imageZoom linear 10s;
    -webkit-animation-iteration-count: infinite;
    -moz-animation: imageZoom linear 10s;
    -moz-animation-iteration-count: infinite;
    -ms-animation: imageZoom linear 10s;
    -ms-animation-iteration-count: infinite;
    transform-origin: 50% 80%;
}

.article {
    background-color: #e6e6e6;
    overflow: hidden;
    width: 300px;
    height: 300px;
}

.imageWrapper {
    background-image: url('http://www.astutegraphics.com/images/blog/tutorials/widthscribe_patterns_18_mar_2013/floral-seamless-pattern.png');
    width: 300px;
    height: 300px;
}

HTML

<div class="article">
    <div class="imageWrapper">

    </div>
</div>

Please, could you help me?

Thanks so much


Solution

  • GOALS:
    1. Have the image animate expansion and contraction on hover
    2. Have the image animate to original state on mouseleave

    PROBLEMS:
    With CSS, I don't know how to use both an animation and a transition. The animation is the pulsing on hover. The transition is the return to default animation. The only way I could envision doing it is with JS. See each section for notes

    https://jsfiddle.net/Bushwazi/9dtqpsLa/5/

    HTML:
    notes: same as example provided

    <div class="article">
        <div class="imageWrapper"></div>
    </div>
    

    CSS:
    notes:
    1. animation removed.
    2. The scale is only fired with the existence of [data-dir='expand'].
    3. transform-origin and transition moved into the default state of .imageWrapper
    4. need to add prefixes

    .article[data-dir='expand'] .imageWrapper {
        transform:scale(1.24)
    }
    
    .article {
        background-color: #e6e6e6;
        overflow: hidden;
        width: 300px;
        height: 300px;
    }
    
    .imageWrapper {
        background-image: url('http://www.astutegraphics.com/images/blog/tutorials/widthscribe_patterns_18_mar_2013/floral-seamless-pattern.png');
        width: 300px;
        height: 300px;
        transform-origin: 50% 80%;
        transition:all 10.0s linear 0.0s;
    }
    

    JAVASCRIPT:
    notes:
    1. all new

    /*
         1. on hover aka 'mouseenter' start the animation
         2. 10 seconds in, change direction of the animation based on the `isHovering` variable
         3. on exit aka 'mouseleave', return to default
     */
    
    
    var thisArticle = document.querySelector('.article'),
        thisTimer = '',
        isHovering = false;
    
    thisArticle.addEventListener('mouseenter', function(){
        console.log('mouseenter');
        thisArticle.setAttribute('data-dir', 'expand');
        thisTimer = setInterval(fireAnimation, 10000);
        isHovering = true
    }, false);
    
    thisArticle.addEventListener('mouseleave', function(){
        console.log('mouseleave');
        thisArticle.removeAttribute('data-dir');
        isHovering = false;
        clearInterval(thisTimer);
    }, false);
    
    var fireAnimation = function(){
        if(isHovering){
            if(thisArticle.getAttribute('data-dir') === 'expand'){
                thisArticle.removeAttribute('data-dir');
            } else {
                thisArticle.setAttribute('data-dir', 'expand');
            }
        } else {
            clearInterval(thisTimer);
        }
        alert('change direction');
    }
    

    MORE IDEAS
    1. I used a data attribute, but I would prefer to use classList. Wasn't sure how to incorporate that into the fiddle in 30 seconds, so skipped it.
    2. The return to default animation has no awareness of the scale when you leave, so it takes 10 seconds no matter what. I'm sure there is a way to make this better.