Aller au contenu principal
Partagez cette démonstration :

Bouton effet material ripple CSS

Dernière mise à jour : juin 2022

Exemple 1 :

Utilisation du pseudo-élement ::before. Transition sur les propriétés width et padding.

Cliquez sur le bouton ci-dessous :



<button>Bouton material design</button>




button{

margin: 2rem auto;
display: flex;
background-color: #6753ea;
color: white;	
cursor: pointer;
border: none;
font-size: 1.5rem;
padding: 10px;
border-radius: .25rem;	
position: relative;
overflow: hidden;
	
}

button::before {
	
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 0;
padding-top: 0;
border-radius: 50%;
background: hsla(0,0%,100%,.1);
transform: translate(-50%,-50%);
transition: width .4s ease-out,
padding .4s ease-out

}
	
	
button:active::before{
	
width: 120%;
padding-top: 120%;

	
	}
	


Exemple 2

Autre exemple, autre méthode. Nous allons cette fois-ci utiliser la propriété background pour créer une image d'arrière-plan qui va servir à produire l'effet ripple. L'astuce va être d'appliquer la propriété background-size pour augmenter la taille de l'arrière-plan.

Cliquez sur le bouton ci-dessous :



<button>Bouton material design</button>




button{

margin: 2rem auto;
display: flex;
background-color: #6753ea;
color: white;	
cursor: pointer;
border: none;
font-size: 1.5rem;
padding: 10px;
border-radius: .25rem
	
}


button {

transition: background .8s ease-out;
background: #6753ea radial-gradient(circle, transparent 1%, #6753ea 1%) center/15000%;

}
	
	
button:active {
	
  background-color: #c1b4ff;
  background-size: 100%;
  transition: background 0s;
	
}
	


Exemple 3

Dernier exemple. Un peu similaire au premier exemple, mais au lieu d'une transition, nous utilisons une animation CSS.

Cliquez sur le bouton ci-dessous :



<button>Bouton material design</button>




button{

margin: 2rem auto;
display: flex;
background-color: #6753ea;
color: white;	
cursor: pointer;
border: none;
font-size: 1.5rem;
padding: 10px;
border-radius: .25rem;
position: relative;
overflow: hidden;
	
}

.button::before {

content: '';
position: absolute;
top: 50%;
left: 50%;
width: 5px;
height: 5px;
background: hsla(0, 0%, 100%, 0.4);
opacity: 0;
border-radius: 50%;


}

@keyframes effet-ripple {
  0% {
    transform: scale(0, 0);
    opacity: 1;
  }
  20% {
    transform: scale(25, 25);
    opacity: 1;
  }
  100% {
    opacity: 0;
    transform: scale(50, 50);
  }
}

.material-ripple3:active::before {
  animation: effet-ripple .8s ease-out;
}
	



Bonus

Allons plus loin en utilisant l'API CSS paint . Cliquez n'importe où sur le bouton ci-dessous (support Chrome, Opera, Edge) :

Votre navigateur ne prend pas en charge cette démonstration.



<button class="effet-ripple">Cliquez ici</button>




.effet-ripple {

border: 0;
margin: 50px auto;
padding: 1rem 2rem;
--theme-couleur: #7d68e8;
--theme-couleur1: #3cddc4;
--bgcolor: white;
color: var(--bgcolor);
--gradient: linear-gradient(to left,var(--theme-couleur),var(--theme-couleur1));
background: var(--gradient);
cursor: pointer;
--ripple-x: 0;
--ripple-y: 0;
--ripple-speed: 1.0;
--animation-tick: 0; 
--ripple-color: rgba(255, 255, 255, 0.5);
}
	



.effet-ripple.animating {
  background-image: paint(ripple), var(--gradient);
}



	  



CSS.paintWorklet.addModule('ripple.js');
 function setupRippleButton(button) {
    let start;
    button.addEventListener('click', (ev) => {
      button.classList.add('animating');
      const [x, y] = [ev.offsetX, ev.offsetY];
      start = performance.now();
      const anim = (now) => {
        const count = Math.floor(now - start);
        button.style.cssText = `--ripple-x: ${x}; --ripple-y: ${y}; --animation-tick: ${count};`;
        if (1000 < count) {
          button.classList.remove('animating');
          button.style.cssText = `--animation-tick: 0`;
          return;
        }
        requestAnimationFrame(anim);
      };
      requestAnimationFrame(anim);
    });
  }
  document.querySelectorAll('.effet-ripple').forEach(setupRippleButton);
  


// ripple.js

let _createClass = function () {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);}}
return function (Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);return Constructor;};}();
function _classCallCheck(instance, Constructor) {if (!(instance instanceof Constructor)) {throw new TypeError("Cannot call a class as a function");}}if (typeof registerPaint === 'undefined') {
  // No action

} else {
registerPaint('ripple', function () {function _class() {_classCallCheck(this, _class);}_createClass(_class, [{ key: 'paint', value: function paint(


ctx, geom, props) {
        var maxTick = 1000;

        var bgColor = props.get('background-color').toString();
        var rippleColor = props.get('--ripple-color').toString();
        var x = parseFloat(props.get('--ripple-x').toString());
        var y = parseFloat(props.get('--ripple-y').toString());
        var speed = parseFloat(props.get('--ripple-speed').toString());

        var tick = speed * parseFloat(props.get('--animation-tick').toString());
        if (tick < 0) {
          tick = 0;
        }
        if (maxTick < tick) {
          tick = maxTick;
        }
        var tickProgress = tick / maxTick;

        ctx.fillStyle = bgColor;
        ctx.fillRect(0, 0, geom.width, geom.height);

        ctx.fillStyle = rippleColor;
        ctx.globalAlpha = 1.0 - tickProgress;
        ctx.arc(x, y, geom.width * tickProgress, 0, 2 * Math.PI);
        ctx.fill();
      } }], [{ key: 'inputProperties', get: function get() {return ['background-color', '--ripple-color', '--animation-tick', '--ripple-x', '--ripple-y', '--ripple-speed'];} }]);return _class;}());

}
;


Et grâce aux propriétés CSS personnalisées, nous allons pouvoir créer quelques variantes (vitesse de l'animation, changement de couleur...) :

Votre navigateur ne prend pas en charge cette démonstration.



.effet-ripple {

border: 0;
margin: 50px auto;
padding: 1rem 2rem;
--theme-couleur: #7d68e8;
--theme-couleur1: #3cddc4;
--bgcolor: white;
color: var(--bgcolor);
--gradient: linear-gradient(to left,var(--theme-couleur),var(--theme-couleur1));
background: var(--gradient);
cursor: pointer;
--ripple-x: 0;
--ripple-y: 0;
--ripple-speed: 1.0;
--animation-tick: 0; 
--ripple-color: rgba(255, 255, 255, 0.5);
}
	



.effet-ripple.animating {
  background-image: paint(ripple), var(--gradient);
}


.variante{ 

--ripple-speed: 2.0;
--ripple-color:rgba(0, 0, 0, 0.39);
	
	}	
	  




Vous rencontrez un problème avec cette démonstration ?

Vous avez constaté un oubli ou une erreur dans le code ? N'hésitez pas à me le signaler par mail (contact@guyom-design.com). Vous ne parvenez pas à faire fonctionner la démonstration ? Vous pouvez également me contacter et je vous aiderai si je le peux.