CSS ripple effect on Hover?

I have a button where I'd like a slightly transparent overlay to 'glide through' the button on hover.

There is something called the 'ripple effect' that you usually can achieve by clicking on a button.

Like here: https://codepen.io/tomma5o/pen/zwyKya

HTML:

<div class="container">
    <a data-animation="ripple">Click Me</a>
</div>

CSS:

:root {
    /* if u want to change the color of
     * the ripple change this value
    */
    --color-ripple: rgba(255,255,255,0.8);
}

body {
    background: #36353c;
}

.container {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    height: 50px;
    width: 200px;
    margin: auto;
}
*[data-animation="ripple"] {
    position: relative; /*Position relative is required*/
    height: 100%;
    width: 100%;
    display: block;
    outline: none;:root {
    /* if u want to change the color of
     * the ripple change this value
    */
    --color-ripple: rgba(255, 255, 255, 0.8);
}

body {
    background: #36353c;
}

.container {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    height: 50px;
    width: 200px;
    margin: auto;
}
*[data-animation="ripple"] {
    position: relative; /*Position relative is required*/
    height: 100%;
    width: 100%;
    display: block;
    outline: none;
    padding: 20px;
    color: #fff;
    text-transform: uppercase;
    background: linear-gradient(135deg, #e570e7 0%, #79f1fc 100%);
    box-sizing: border-box;
    text-align: center;
    line-height: 14px;
    font-family: roboto, helvetica;
    font-weight: 200;
    letter-spacing: 1px;
    text-decoration: none;
    box-shadow: 0 5px 3px rgba(0, 0, 0, 0.3);
    cursor: pointer;
    /*border-radius: 50px;*/
    -webkit-tap-highlight-color: transparent;
}

*[data-animation="ripple"]:focus {
    outline: none;
}

*[data-animation="ripple"]::selection {
    background: transparent;
    pointer-events: none;
}

    padding: 20px;
    color: #fff;
    text-transform: uppercase;
    background: linear-gradient(135deg, #e570e7 0%,#79f1fc 100%);
    box-sizing: border-box;
    text-align: center;
    line-height: 14px;
    font-family: roboto, helvetica;
    font-weight: 200;
    letter-spacing: 1px;
    text-decoration: none;
    box-shadow: 0 5px 3px rgba(0, 0, 0, 0.3);
    cursor: pointer;
  /*border-radius: 50px;*/
    -webkit-tap-highlight-color: transparent;
}

*[data-animation="ripple"]:focus {
    outline: none;
}

*[data-animation="ripple"]::selection {
    background: transparent;
    pointer-events: none;
}

JS:

const isMobile = window.navigator.userAgent.match(/Mobile/) && window.navigator.userAgent.match(/Mobile/)[0] === "Mobile";
const event = isMobile ? "touchstart" : "click";

const button = document.querySelectorAll('*[data-animation="ripple"]'),
            container = document.querySelector(".container");

for (var i = 0; i < button.length; i++) {
    const currentBtn = button[i];

    currentBtn.addEventListener(event, function(e) {

        e.preventDefault();
        const button = e.target,
                    rect = button.getBoundingClientRect(),
                    originalBtn = this,
                    btnHeight = rect.height,
                    btnWidth = rect.width;
        let posMouseX = 0,
                posMouseY = 0;

        if (isMobile) {
            posMouseX = e.changedTouches[0].pageX - rect.left;
            posMouseY = e.changedTouches[0].pageY - rect.top;
        } else {
            posMouseX = e.x - rect.left;
            posMouseY = e.y - rect.top;
        }

        const baseCSS =  `position: absolute;
                                            width: ${btnWidth * 2}px;
                                            height: ${btnWidth * 2}px;
                                            transition: all linear 700ms;
                                            transition-timing-function:cubic-bezier(0.250, 0.460, 0.450, 0.940);
                                            border-radius: 50%;
                                            background: var(--color-ripple);
                                            top:${posMouseY - btnWidth}px;
                                            left:${posMouseX - btnWidth}px;
                                            pointer-events: none;
                                            transform:scale(0)`

        var rippleEffect = document.createElement("span");
        rippleEffect.style.cssText = baseCSS;

        //prepare the dom
        currentBtn.style.overflow = "hidden";
        this.appendChild(rippleEffect);

        //start animation
        setTimeout( function() { 
            rippleEffect.style.cssText = baseCSS + `transform:scale(1); opacity: 0;`;
        }, 5);

        setTimeout( function() {
            rippleEffect.remove();
            //window.location.href = currentBtn.href;
        },700);
    })
}

Is it possible to achieve something similar without having to click on the button but just hovering over it?

2 answers

  • answered 2018-01-14 20:05 Mithu Mondal

    Change line 2 of JS:

    const event = isMobile ? "touchstart" : "click";
    

    with:

    const event = isMobile ? "touchstart" : "mouseover";
    

    That would do the job.

    Hope that helps!

  • answered 2018-01-14 20:46 Facundo Corradini

    If you want the ripple origin to be fixed (e.g. from the middle) instead of from wherever the mouse enters, the answer is much simpler and requires no javascript: just stack a semi-transparent rounded pseudo-element and animate the scale on hover.

    body {
    	background: #36353c;
    }
    
    .container {
    	position: absolute;
    	top: 0;
    	left: 0;
    	right: 0;
    	bottom: 0;
    	height: 50px;
    	width: 200px;
    	margin: auto;
    }
    .ripple{
    	position: relative; /*Position relative is required*/
    	height: 100%;
    	width: 100%;
    	display: block;
    	outline: none;
    	padding: 20px;
    	color: #fff;
    	text-transform: uppercase;
    	background: linear-gradient(135deg, #e570e7 0%,#79f1fc 100%);
    	box-sizing: border-box;
    	text-align: center;
    	line-height: 14px;
    	font-family: roboto, helvetica;
    	font-weight: 200;
    	letter-spacing: 1px;
    	text-decoration: none;
    	box-shadow: 0 5px 3px rgba(0, 0, 0, 0.3);
    	cursor: pointer;
    	overflow:hidden;
    }
    
    .ripple:hover:before{
    	animation: ripple 1s ease;
    }
    
    .ripple:before{
    	content:"";
    	position:absolute; top:0; left:0;
    	width:100%; height:100%;
      background-color:rgba(255, 255, 255, 0.7);
      border-radius:50%;
    	transform:scale(0);
    }
    
    @keyframes ripple{
    	from{transform:scale(0); opacity:1;}
    	to{transform:scale(3);opacity:0;}
    }
    <div class="container">
    	<a class="ripple">Hover Me</a>
    </div>