Animated Buttons Experiment
animated buttons experiment
by Travis Almand
HTML
<p>CSS Effects</p>
<button class="primary-btn" data-anibtn="expand">expand</button>
<button class="primary-btn" data-anibtn="stretch">stretch</button>
<button class="primary-btn" data-anibtn="fall">fall</button>
<button class="primary-btn" data-anibtn="blur">blur</button>
<button class="primary-btn" data-anibtn="bounceExpand">bounceExpand</button>
<br />
<button class="secondary-btn" data-anibtn="shake">shake</button>
<br />
<p>SVG filters</p>
<button class="primary-btn" data-anibtn="displaceSvg">svg displace</button>
<button class="primary-btn" data-anibtn="explodeSvg">svg explode</button>
<svg id="svg-filters">
<filter id="displaceFilter">
<feTurbulence type="turbulence" baseFrequency="0.05" numOctaves="4" result="turbulence" stitchTiles="stitch" />
<feDisplacementMap id="displaceSvgMap" in2="turbulence" in="SourceGraphic" scale="0" xChannelSelector="R" yChannelSelector="G" />
</filter>
<filter id="explodeFilter">
<feTurbulence type="turbulence" baseFrequency="0.75" numOctaves="4" result="turbulence" stitchTiles="stitch" />
<feDisplacementMap id="explodeSvgMap" in2="turbulence" in="SourceGraphic" scale="0" xChannelSelector="R" yChannelSelector="G" />
</filter>
</svg>
SCSS
$primary-color: green;
$secondary-color: red;
@mixin btns($color) {
background-color: $color;
border: 1px solid darken($color, 10%);
color: #fff;
&:hover {
background-color: darken($color, 10%);
}
}
#svg-filters {
position: absolute;
}
button {
background: none;
border: none;
border-radius: 4px;
cursor: pointer;
display: inline-block;
margin: 10px;
opacity: 1;
padding: 5px 10px;
}
.primary-btn {
@include btns($primary-color);
}
.secondary-btn {
@include btns($secondary-color);
}
[class*="BtnDup"] {
pointer-events: none;
position: absolute;
z-index: 666;
}
.expandBtnDup {
animation: expandBtn 0.25s;
}
@keyframes expandBtn {
0% {
opacity: 1;
transform: scale3d(1, 1, 1);
}
100% {
opacity: 0;
transform: scale3d(2, 2, 1);
}
}
.stretchBtnDup {
animation: stretchBtn 0.25s;
}
@keyframes stretchBtn {
0% {
opacity: 1;
transform: scale3d(1, 1, 1);
}
100% {
opacity: 0;
transform: scale3d(3, 0.25, 1);
}
}
.fallBtnDup {
animation: fallBtn 0.25s;
}
@keyframes fallBtn {
0% {
opacity: 1;
transform: translate3d(0, 0, 0) rotate3d(0, 0, 0, 0deg);
}
100% {
opacity: 0;
transform: translate3d(0, 100%, 0) rotate3d(0, 0, 1, 10deg);
}
}
.bounceExpandBtnDup {
animation: bounceExpandBtn 0.25s forwards;
}
@keyframes bounceExpandBtn {
0% {
transform: scale3d(1, 1, 1);
}
25% {
transform: scale3d(1.25, 1.25, 1);
}
50% {
opacity: 1;
transform: scale3d(1, 1, 1);
}
100% {
opacity: 0;
transform: scale3d(1.5, 1.5, 1);
}
}
.shakeBtnDup {
animation: shakeBtn 0.5s forwards;
}
@keyframes shakeBtn {
0% {
transform: translate3d(0, 0, 0) scale3d(1.25, 1.25, 1);
}
20% {
transform: translate3d(-50%, 0, 0) scale3d(1.25, 1.25, 1);
}
40% {
transform: translate3d(50%, 0, 0) scale3d(1.25, 1.25, 1);
}
50% {
opacity: 1;
}
60% {
transform: translate3d(-50%, 0, 0) scale3d(1.25, 1.25, 1);
}
80% {
...
JavaScript
(function animateTheBtns () {
let $aniBtns = document.querySelectorAll('[data-anibtn]');
for (let i = 0; i < $aniBtns.length; i++) {
let $element = $aniBtns[i];
let type = $aniBtns[i].dataset.anibtn
let $map = document.querySelector('#' + type + 'Map');
let svgTimer;
$element.addEventListener('click', function () {
let xPos = this.getBoundingClientRect().left;
let yPos = this.getBoundingClientRect().top;
let marginLeft = parseFloat(window.getComputedStyle(this, null).getPropertyValue('margin-left'));
let marginTop = parseFloat(window.getComputedStyle(this, null).getPropertyValue('margin-top'));
let $dup = this.cloneNode('deep');
this.style.pointerEvents = "none";
$dup.classList.add(type + 'BtnDup');
$dup.style.left = (xPos - marginLeft) + 'px';
$dup.style.top = (yPos - marginTop) + 'px';
document.body.appendChild($dup);
if ($map) {
$map.scale.baseVal = 0;
}
window.clearInterval(svgTimer);
$dup.addEventListener('animationend', function () {
$element.style.pointerEvents = "auto";
document.body.removeChild($dup);
if (svgTimer) {
$map.scale.baseVal = 0;
window.clearInterval(svgTimer);
}
});
if ($map) {
svgTimer = window.setInterval(function () {
$map.scale.baseVal += 1;
}, 10);
}
});
}
})();