@import url("https://fonts.googleapis.com/css?family=Inconsolata:400,700");
$black: #000;
$white: #fff;
$shocking-pink: #ff1ead;
html, body {
width: 100%;
height: 100%;
}
body {
font-family: Inconsolata, monospace;
font-size: 24px;
background-color: $black;
display: grid;
place-items: center;
}
.ti-btn {
color: $white;
font: inherit;
background-color: $black;
border: solid 4px $white;
padding: 20px 30px;
outline: 0;
overflow: hidden;
display: inline-block;
position: relative;
user-select: none;
box-shadow: 0 0 0 0 rgba($white, 0.5);
transition: box-shadow 150ms ease-out;
&:focus {
box-shadow: 0 0 0 8px rgba($white, 0.5);
}
}
.ripple {
background-color: $shocking-pink;
width: 1rem;
height: 1rem;
position: absolute;
border-radius: 50%;
transform: translateX(-100%) translateY(-100%);
mix-blend-mode: screen;
animation: ripple 1250ms ease-out forwards, fade 1500ms ease-out forwards;
}
@keyframes ripple {
0% { transform: translate(-100%, -100%); }
80% { transform: translate(-100%, -100%) scale(50); }
100% { transform: translate(-100%, -100%) scale(50); opacity: 0; }
}
@keyframes fade {
0% { opacity: 1; }
100% { opacity: 0; }
}
View Compiled
Vue.component('ti-ripple-button', {
props: ['text'],
data: function() {
return {
ripples: []
}
},
methods: {
animateRipple: function(e) {
let el = this.$refs.tiBtn;
let pos = el.getBoundingClientRect();
this.ripples.push({
x: e.clientX - pos.left,
y: e.clientY - pos.top,
show: true
});
},
rippleEnd: function(i) {
this.ripples[i].show = false;
}
},
template: `
<button class="ti-btn" ref="tiBtn" v-on:click="animateRipple">
{{text}}
<transition-group>
<span
class="ripple"
v-bind:ref="'ripple-' + i"
v-bind:key="'ripple' + i"
v-for="(val, i) in ripples"
v-if="val.show === true"
v-bind:style="{'top': val.y + 'px', 'left': val.x + 'px'}"
v-on:animationend="rippleEnd(i)">
</span>
</transition-group>
</button>
`
});
var app = new Vue({
el: '#app'
});
View Compiled