James Newton
James Newton

Reputation: 7124

Forcing a CSS animation to complete

For an artist's web site, where the pictures completely fill the browser window, I want to show a strip of thumbnails which will disappear to leave only the thumbnail for the current image in the corner. When you roll the mouse over this thumbnail, the strip of thumbnails should reappear again, so that you can choose a new picture.

I've included a mockup of this effect below, and a jsFiddle where you can see this in action.

If you roll the mouse over the thumbnail and then quickly off again, the animation will stop, remain in a paused state for 1 second, and then reverse. How should I alter the CSS so that the slide out animation will always play to the end once it has started?

<html>
<head>
<style>
  html, body {
  height: 100%;
  margin:0;
  overflow: hidden;
  }
  div {
  position:absolute;
  left:0;
  width: 100px
  }
  #cue, #thumb {
  bottom:0;
  height:50px;
  }
  #cue, #thumb {
  bottom:0;
  height:50px;
  }
  #cue {
  background: none;
  opacity: 0.2;
  z-index: 2;
  }
  #thumb {
  background: blue;
  opacity: 0.5;
  }
  #strip {
  background: blue;
  opacity: 0.2;
  z-index:1;
  height: 99%;
  top: 100%;
  -webkit-transition: all 500ms cubic-bezier(0.420, 0.000, 0.580, 1.000);
  -moz-transition: all 500ms cubic-bezier(0.420, 0.000, 0.580, 1.000);
  -o-transition: all 500ms cubic-bezier(0.420, 0.000, 0.580, 1.000);
  transition: all 500ms cubic-bezier(0.420, 0.000, 0.580, 1.000);
  -webkit-transition-delay: 1s;
  transition-delay: 1s;
  }
  #cue:hover + #strip, #strip:hover {
  top: 1%;
  -webkit-transition-delay: 0s;
  transition-delay: 0s;
  }
  #thumb {
  -webkit-transition: all 300ms cubic-bezier(0.420, 0.000, 0.580, 1.000);
  -moz-transition: all 300ms cubic-bezier(0.420, 0.000, 0.580, 1.000);
  -o-transition: all 300ms cubic-bezier(0.420, 0.000, 0.580, 1.000);
  transition: all 300ms cubic-bezier(0.420, 0.000, 0.580, 1.000);
  -webkit-transition-delay: 1200ms;
  transition-delay: 1200ms;
  }
  #cue:hover ~ #thumb, #strip:hover+#thumb {
  opacity: 0;
  -webkit-transition-delay: 0s;
  transition-delay: 0s;
  }
</style>
</head>
  <div id="cue"></div>
  <div id="strip"></div>
  <div id="thumb"></div>
</html>

Upvotes: 0

Views: 878

Answers (3)

James Newton
James Newton

Reputation: 7124

On further investigation, I needed to modify the answer given by @Moogs in two ways, neither of which was specified in my question:

  • The cue div in my question had a higher z-index than the strip of thumbnails, so it was impossible to select the bottom-most thumbnail in the strip
  • If you drag your cursor off the open strip and then move it back on again before it starts to close, it should remain open

Here's a demo of my final solution, and a jsFiddle where you can test it. Many thanks to @Moogs for putting me on the right track.

<html>
<head>
    <style>
        html, body {
            height: 100%;
            margin:0;
            overflow: hidden;
        }
        div {
            position:absolute;
            left:0;
            width: 100px
        }
        #cue, #thumb {
            bottom:0;
            height:50px;
        }
         #cue {
            opacity: 0;
            z-index: 1;
        }
        #thumb {
            background: blue;
            opacity: 0.5;
        }
        #strip {
            background: blue;
            opacity: 0.2;
            z-index:1;
            height: 99%;
            top: 100%;
            -webkit-transition: all 500ms cubic-bezier(0.420, 0.000, 0.580, 1.000);
            -moz-transition: all 500ms cubic-bezier(0.420, 0.000, 0.580, 1.000);
            -o-transition: all 500ms cubic-bezier(0.420, 0.000, 0.580, 1.000);
            transition: all 500ms cubic-bezier(0.420, 0.000, 0.580, 1.000);
            -webkit-transition-delay: 1s;
            transition-delay: 1s;
        }
        #strip.hover {
            top: 1%;
            -webkit-transition-delay: 0s;
            transition-delay: 0s;
        }
        #thumb {
            -webkit-transition: all 300ms cubic-bezier(0.420, 0.000, 0.580, 1.000);
            -moz-transition: all 300ms cubic-bezier(0.420, 0.000, 0.580, 1.000);
            -o-transition: all 300ms cubic-bezier(0.420, 0.000, 0.580, 1.000);
            transition: all 300ms cubic-bezier(0.420, 0.000, 0.580, 1.000);
            -webkit-transition-delay: 1200ms;
            transition-delay: 1200ms;
        }
        #strip.hover+#thumb {
            opacity: 0;
        }
        /* .inProgress is needed to ensure that the thumb will reappear if
           you move the mouse off the strip before it is completely open.
           If the following rule is merged with the #strip.hover+#thumb rule,
           then the change from #strip.hover+#thumb to #strip+#thumb (with
           no .hover) may fail to be acted on by the #thumb.
        */
        #thumb.inProgress {
            -webkit-transition-delay: 0s;
            transition-delay: 0s;
        }
    </style>

    <script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
</head>

<body>
<div id="cue"></div>
<div id="strip"></div>
<div id="thumb"></div>

<script>
    ;(function filmroll_animation() {
        var cue = document.getElementById('cue')
        var strip = document.getElementById('strip')
        var thumb = document.getElementById('thumb')

        var hover = "hover"
        var inProgress = "inProgress"

        var mouseover = false
        var transitionDone = false

        cue.onmouseover = function triggerSlideIn() {
            transitionDone = false
            strip.classList.add(hover)
            thumb.classList.add(inProgress)
        }

        strip.onmouseleave = function viewPortLeave() {
            mouseover = false;
            if (transitionDone) {
                strip.classList.remove(hover)
            }
        }

        strip.onmouseover = function viewPortEnter() {
            mouseover = true;
            strip.classList.add(hover)
        }

        strip.addEventListener("transitionend", function viewPortShown() {
            transitionDone = true;
            thumb.classList.remove(inProgress)
            if (!mouseover) {
                strip.classList.remove(hover)
            }
        }, false)
    })()
</script>
</body>
</html>

Upvotes: 0

Miguel
Miguel

Reputation: 20633

I'm not sure how you can do this without JavaScript. You can toggle classes instead of using hover selector and use transitionend to detect when the animation has completed to toggle the hover classes.

https://jsfiddle.net/w5b1hm0w/2/

Upvotes: 1

Devan Accountero
Devan Accountero

Reputation: 1

Most obvious solution is to make your thumbnails set width/height and have the image as a css background image with background size "cover" or "contain" and background position "center center".

.thumb {
    background-image: url('some-image.png');
    background-position: center center;
    background-size: cover;
}

If you really want dynamic width/height on your thumbnails I recommend possibly looking at javascript plugin that manipulates css like masonry or isotope:

http://masonry.desandro.com/

http://isotope.metafizzy.co/

Upvotes: 0

Related Questions