Skip to content

Instantly share code, notes, and snippets.

@GersonLazaro
Last active November 13, 2022 11:24
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save GersonLazaro/d32bcbe009a95d8f89b2 to your computer and use it in GitHub Desktop.
Save GersonLazaro/d32bcbe009a95d8f89b2 to your computer and use it in GitHub Desktop.
Efecto Ripple - Material Design
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<title>Efecto Ripple - Material Design</title>
<link href="styles.css" rel="stylesheet">
</head>
<body>
<div class="container">
<button class="btn btn-circle">
<div class="ripple-container">
<span class="ripple-effect"></span>
</div>
+
</button>
<button class="btn btn-rectangle btn-raised">
<div class="ripple-container">
<span class="ripple-effect"></span>
</div>
Botón Raised
</button>
<button class="btn btn-rectangle btn-flat">
<div class="ripple-container">
<span class="ripple-effect"></span>
</div>
Botón Flat
</button>
<div class="block">
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/5/55/Sasso_lungo_da_passo_pordoi.jpg/270px-Sasso_lungo_da_passo_pordoi.jpg" alt="Paisaje muy bonito" />
<div class="ripple-container">
<span class="ripple-effect"></span>
</div>
</div>
</div>
<script src="ripple.js"></script>
</body>
</html>
var ripple = document.querySelectorAll('.ripple-container'); //Guardamos un array con todos los botones. Para compatibilidad con navegadores antiguos puedes reemplazar el querySelectorAll con un getElementsByClassName
[].forEach.call(ripple, function(e) {
e.addEventListener('click', function(e) {
/*Esto se activará cada vez que haya un click en un botón*/
var offset = this.parentNode.getBoundingClientRect(); //Toma los limites del padre (el padre es el <button> para los botones, o el <div> principal en la imagen
var effect = this.querySelector('.ripple-effect'); //Toma SOLO el span ripple-effect que está dentro del boton clicado
/*pageX y pageY devuelven el punto de la página en el cual se hizo clic, siendo el origen la esquina superior izquierda. En offset.top y offset.left tenemos almacenados la distancia al origen de la esquina superior izquierda del botón. La resta de estos elementos nos indicará el punto en el cual se hizo clic, teniendo como origen la esquina superior izquierda del botón*/
effect.style.top = (e.pageY - offset.top) + "px";
effect.style.left = (e.pageX - offset.left) + "px";
this.classList.add('ripple-effect-animation'); //Agregamos la clase con la animación
}, false);
/*Cuando la animación finalice, se disparan eventos llamando a removeAnimation, este método eliminará la clase ripple-effect-animation*/
e.addEventListener('animationend', removeAnimation);
e.addEventListener('webkitAnimationEnd', removeAnimation);
e.addEventListener('oanimationend', removeAnimation);
e.addEventListener('MSAnimationEnd', removeAnimation);
});
function removeAnimation() {
if (this.classList) {
this.classList.remove('ripple-effect-animation');
} else {
this.className = this.className.replace(new RegExp('(^|\\b)' + 'ripple-effect-animation'.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
}
}
.container{
text-align: center;
}
button{
outline: 0px;
}
.btn{
border: none; /*Quita los bordes asperos que tienen los botones por defecto*/
background-color: #2196F3;
margin: .5rem;
position: relative;
transform: rotateZ(360deg);
transition: all .2s ease;
overflow: hidden;
cursor: pointer;
}
.btn-circle{
border-radius: 50%; /*Redondear bordes*/
width: 50px; /*Ancho del botón*/
height: 50px; /*Alto del botón*/
font-size: 26px;
box-shadow: 0 3px 5px rgba(0,0,0,.4);
}
.btn-circle:hover, .btn-circle:active{
box-shadow: 0 4px 7px rgba(0,0,0,.4);
}
.btn-rectangle{
border-radius: 2px; /*Leve redondeo*/
padding: .5rem 1.5rem; /*Espaciado interno*/
}
.btn-circle, .btn-raised{
color: #FFF;
}
.btn-raised{
box-shadow: 0 1px 5px rgba(0,0,0,.4); /*Sombra leve*/
}
.btn-raised:hover, .btn-raised:active{
box-shadow: 0 4px 6px rgba(0,0,0,.4);
}
.btn-flat{
font-weight: 700; /*Negrilla*/
color: #2196F3;
background-color: transparent;
}
.block{
position: relative;
width: 270px;
height: 178px;
margin: 20px auto;
}
.ripple-container {
/*Con los siguientes valores de position, top, left, width y height aseguramos que el div tome todo el tamaño de su padre*/
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
background: transparent;
}
.ripple-effect {
position: absolute;
/*En javascript colocaremos el top y left de este span en el punto donde hizo click el usuario. Por eso es necesario trasladarlo en -50% en ambos ejes, para que el centro del efecto coincida con el click*/
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
opacity: 0;
width: 0;
height: 0;
border-radius: 50%;
background: rgba(255,255,255, 0.4);
}
.btn-flat .ripple-effect{
background: rgba(33,150,243, 0.4);
}
.ripple-container.ripple-effect-animation .ripple-effect{
/*Aplicamos la animación que mas adelante definiremos con @keyframes*/
-webkit-animation: ripple .4s ease-in;
animation: ripple .4s ease-in;
}
@-webkit-keyframes ripple {
0% {
opacity: 0;
}
30% {
opacity: 1;
}
100% {
opacity: 0;
padding-bottom: 200%;
width: 200%;
}
}
@-webkit-keyframes ripple {
0% {
opacity: 0;
}
30% {
opacity: 1;
}
100% {
opacity: 0;
padding-bottom: 200%;
width: 200%;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment