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 :
Bouton effet ripple
<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 :
Bouton effet ripple
<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 :
Bouton effet ripple
<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.
Cliquez ici
<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.
Cliquez ici
.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);
}