"hover menu animation"
Bootstrap 3.0.0 Snippet by evarevirus

<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css"> <script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script> <script src="//code.jquery.com/jquery-1.11.1.min.js"></script> <!------ Include the above in your HEAD tag ----------> <div id="container" class="container"> <div class="item"> <a class="item__link" href="javascript:void(0)"> <div class="item__thumbs"> <div class="item__thumb-container"> <img src="http://res.cloudinary.com/jasonheecs/image/upload/v1479968760/reflection-menu/hand-crafted.svg" alt="Hand Crafted" class="item__thumb js-thumb"> </div> <div class="item__reflection-wrapper"> <div class="item__reflection-container"> <img src="http://res.cloudinary.com/jasonheecs/image/upload/v1479968760/reflection-menu/hand-crafted.svg" alt="Hand Crafted" class="item__thumb item__reflection js-reflection"> </div> </div> </div> <div class="item__caption"> Hand <span class="item__caption--em">Crafted</span> </div> </a> </div> <div class="item"> <a class="item__link" href="javascript:void(0)"> <div class="item__thumbs"> <div class="item__thumb-container"> <img src="http://res.cloudinary.com/jasonheecs/image/upload/v1479699693/reflection-menu/rainforest_guardian.svg" alt="Rainforest Guardian" class="item__thumb js-thumb"> </div> <div class="item__reflection-wrapper"> <div class="item__reflection-container"> <img src="http://res.cloudinary.com/jasonheecs/image/upload/v1479699693/reflection-menu/rainforest_guardian.svg" alt="Rainforest Guardian" class="item__thumb item__reflection js-reflection"> </div> </div> </div> <div class="item__caption"> Rainforest <span class="item__caption--em">Guardian</span> </div> </a> </div> <div class="item"> <a class="item__link" href="javascript:void(0)"> <div class="item__thumbs"> <div class="item__thumb-container"> <img src="http://res.cloudinary.com/jasonheecs/image/upload/v1479699692/reflection-menu/sleep.svg" alt="Sleep Benefits" class="item__thumb js-thumb"> </div> <div class="item__reflection-wrapper"> <div class="item__reflection-container"> <img src="http://res.cloudinary.com/jasonheecs/image/upload/v1479699692/reflection-menu/sleep.svg" alt="Sleep Benefits" class="item__thumb item__reflection js-reflection"> </div> </div> </div> <div class="item__caption"> Sleep <span class="item__caption--em">Benefits</span> </div> </a> </div> <div class="item"> <a class="item__link" href="javascript:void(0)"> <div class="item__thumbs"> <div class="item__thumb-container"> <img src="http://res.cloudinary.com/jasonheecs/image/upload/v1479699693/reflection-menu/videos.svg" alt="Videos Showreel" class="item__thumb js-thumb"> </div> <div class="item__reflection-wrapper"> <div class="item__reflection-container"> <img src="http://res.cloudinary.com/jasonheecs/image/upload/v1479699693/reflection-menu/videos.svg" alt="Videos Showreel" class="item__thumb item__reflection js-reflection"> </div> </div> </div> <div class="item__caption"> Videos <span class="item__caption--em">Showreel</span> </div> </a> </div> </div> <script> 'use strict'; class Menu { /** * @constructor * @param {Element} containerEl * @return {void} */ constructor(containerEl) { this.containerEl = containerEl; this.init(); } /** * Find the height of the tallest element in a NodeList of elements * @param {NodeList} els * @return {number} */ findMaxHeight(els) { let tallestEl = Array.from(els).reduce((tallestEl, currentEl) => { return tallestEl.offsetHeight > currentEl.offsetHeight ? tallestEl : currentEl; }); return tallestEl.offsetHeight; } /** * Equalise all the heights of a NodeList of elements based on the tallest element * @param {NodeList} els * @return {void} */ matchElsHeight(els) { let maxHeight = this.findMaxHeight(els); Array.from(els).forEach((el) => { el.style.height = maxHeight + 'px'; }); } /** * Set the hover animations of the thumbnails */ setHover() { Array.from(this.containerEl.querySelectorAll('.item__link')).forEach((el) => { let thumbEl = el.querySelector('.js-thumb'); let reflectionEl = el.querySelector('.js-reflection'); el.addEventListener('mouseenter', (evt) => { evt.stopPropagation(); thumbMouseEnterAnimation(thumbEl); thumbMouseEnterAnimation(reflectionEl, true); }); el.addEventListener('mouseleave', (evt) => { evt.stopPropagation(); if (thumbEl.classList.contains('velocity-animating')) { thumbMouseOutAnimation(thumbEl); } if (reflectionEl.classList.contains('velocity-animating')) { thumbMouseOutAnimation(reflectionEl); } }); }); /** * Animation that happens when mouseenter event fires * @param {Element} thumbEl * @param {Boolean} isReflection if thumbEl meant to have scaleY(-1) applied to it before the animation * @return {void} */ function thumbMouseEnterAnimation(thumbEl, isReflection) { isReflection = isReflection || false; if (isReflection) { Velocity.hook(thumbEl, "scaleY", "-1"); } Velocity(thumbEl, { translateZ: 0, translateY: '-18px' }, {duration: 1000}) .then( Velocity(thumbEl, { translateZ: 0, translateY: '-5px' }, { duration: 1000, loop: true }) ); } /** * Animation that happens when mouseleave event fires * @param {Element} thumbEl * @return {void} */ function thumbMouseOutAnimation(thumbEl) { Velocity(thumbEl, "stop", true).then( Velocity(thumbEl, { translateZ: 0, translateY: 0 }, { duration: 800, easing: 'easeOutCubic' }) ); } } static create(containerEl) { return new Menu(containerEl); } /** * Initialize the menu * @return {void} */ init() { imagesLoaded(this.containerEl, () => { this.matchElsHeight(this.containerEl.querySelectorAll('.item__thumb-container')); this.matchElsHeight(this.containerEl.querySelectorAll('.item__reflection-container')); this.setHover(); }); } } Menu.create(document.getElementById('container')); </script>
body { display: flex; align-items: center; height: 100vh; background: #ede9e5; font-family: 'Raleway', sans-serif; } a { outline: 0; } .container { display: flex; width: 100%; max-width: 960px; margin: 100px auto 0; padding: 0 20px; border-radius: 30px; background: #fff; } @media screen and (min-width: 768px) { .container { padding: 0 40px; } } .item { flex: 1 1 25%; margin-top: -100px; text-align: center; } .item__link { display: inline-block; position: relative; text-decoration: none; } .item__thumb-container { display: flex; align-items: flex-end; justify-content: center; } .item__thumb { position: relative; max-width: 100%; height: auto; border: 0; box-sizing: border-box; } .item__reflection-wrapper { position: relative; height: 155px; overflow: hidden; } .item__reflection-container { display: flex; position: absolute; left: 0; align-items: flex-start; justify-content: center; width: 100%; } .item__reflection-container::after { position: absolute; top: -10px; left: -5%; width: 110%; height: 120%; border-radius: 30px; background: linear-gradient(to bottom, rgba(255, 255, 255, 0.75) 0%, #fff 60%, #fff 100%); content: ''; } .item__reflection { transform: scale3d(1, -1, 1); filter: blur(2px); } .item__caption { position: absolute; left: 50%; transform: translate3d(-50%, -80px, 0); color: #ad998a; font-size: 1rem; font-weight: 500; text-align: left; text-transform: uppercase; word-spacing: 100px; } @media screen and (min-width: 768px) { .item__caption { font-size: 1.5rem; } } .item__caption--em { color: #7b685a; font-weight: 700; }

Related: See More


Questions / Comments: