HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

Google material ripple button effect

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
rippleeffectgooglematerialbutton

Problem

I have "translated" this example built with jQuery in vanilla JavaScript, but I'd like to know if there are better ways to do it.

The jQuery version uses offset() function and on() for every events, while I've used this function for offset:

function offset(elt) {
    var rect = elt.getBoundingClientRect(), bodyElt = document.body;
    return {
        top: rect.top + bodyElt .scrollTop,
        left: rect.left + bodyElt .scrollLeft
    }
}


and this one to prefix AnimationEnd event :

var pfx = ["webkit", "moz", "MS", "o", ""];
function prefixedEvent(element, type, callback) {
    for (var p = 0; p < pfx.length; p++) {
        if (!pfx[p]) type = type.toLowerCase();
        element.addEventListener(pfx[p]+type, callback, false);
    }
}


From this sitepoint article

My entire code is visible here at Codepen.

Otherwise, here is my example code:

HTML




Test



Test



Test



SCSS (without prefixes):

`button {
height: 100px;
width: 100px;
background-color: gray;
border-style:solid;
color: #fff;
position: relative;
display: inline-block;
padding: 12px 24px;
margin-top: 0;
margin-bottom: 0;
vertical-align: middle;
transition: all .25s ease;

&:focus {
outline: 0;
}

&:hover {
background-color: darken(gray, 5%);
}
}

.ripples {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
overflow: hidden;
background-color: transparent;

&.is-active {
.ripples-circle {
animation: ripples .4s ease-in;
}
}

.ripples-circle {
background-color: rgba(255,255,255,.5);
position: absolute;
top: 50%;
left: 50%;
opacity: 0;
width: 0;
height: 0;
border-radius: 50%;
transform: translate(-50%, -50%);
}
}

@keyframes ripples {
0% {
opacity: 0;
}
25% {

Solution

Some things that I would do differently in this for loop

for(var i=0; i < ripples.length;i++ ){
     ripples[i].addEventListener('click', function(e){
        var rippleThis = this;
        var parentOffset = offset(rippleThis.parentNode);
        var x = e.pageX - parentOffset.left;
        var y = e.pageY + parentOffset.top;
        var j;
        var childrenLength = rippleThis.childNodes.length;
        var targetChild;
        for(j = 0; j < childrenLength; j++){
          if(rippleThis.childNodes[j].className == 'ripples-circle') targetChild = rippleThis.childNodes[j];
        }

        targetChild.style.top = y + 'px';
        targetChild.style.left = x + 'px';

        rippleThis.className = 'ripples is-active';
    }, false);
    prefixedEvent(ripples[i], "AnimationEnd", function(e){
        e.currentTarget.className = 'ripples';
    });
}


First thing I saw was that you created an increment variable outside of the for loop declaration, that just makes things a little messy, there isn't any reason for var j; outside of the for loop.

rippleThis isn't a good variable name, I would name this variable thisRipple because it is literally this ripple object.

You should also give your code some breathing room, like in the for loop declaration

var i = 0; i < ripples.length; i++ looks better than var i=0; i < ripples.length;i++

After all these changes it would look like this

for(var i = 0; i < ripples.length; i++ ){
    ripples[i].addEventListener('click', function(e){
        var thisRipple = this;
        var parentOffset = offset(thisRipple.parentNode);
        var x = e.pageX - parentOffset.left;
        var y = e.pageY + parentOffset.top;
        var childrenLength = thisRipple.childNodes.length;
        var targetChild;
        for(var j = 0; j < childrenLength; j++){
            if(thisRipple.childNodes[j].className == 'ripples-circle') targetChild = thisRipple.childNodes[j];
        }

        targetChild.style.top = y + 'px';
        targetChild.style.left = x + 'px';

        thisRipple.className = 'ripples is-active';
    }, false);
    prefixedEvent(ripples[i], "AnimationEnd", function(e){
        e.currentTarget.className = 'ripples';
    });
}

Code Snippets

for(var i=0; i < ripples.length;i++ ){
     ripples[i].addEventListener('click', function(e){
        var rippleThis = this;
        var parentOffset = offset(rippleThis.parentNode);
        var x = e.pageX - parentOffset.left;
        var y = e.pageY + parentOffset.top;
        var j;
        var childrenLength = rippleThis.childNodes.length;
        var targetChild;
        for(j = 0; j < childrenLength; j++){
          if(rippleThis.childNodes[j].className == 'ripples-circle') targetChild = rippleThis.childNodes[j];
        }

        targetChild.style.top = y + 'px';
        targetChild.style.left = x + 'px';

        rippleThis.className = 'ripples is-active';
    }, false);
    prefixedEvent(ripples[i], "AnimationEnd", function(e){
        e.currentTarget.className = 'ripples';
    });
}
for(var i = 0; i < ripples.length; i++ ){
    ripples[i].addEventListener('click', function(e){
        var thisRipple = this;
        var parentOffset = offset(thisRipple.parentNode);
        var x = e.pageX - parentOffset.left;
        var y = e.pageY + parentOffset.top;
        var childrenLength = thisRipple.childNodes.length;
        var targetChild;
        for(var j = 0; j < childrenLength; j++){
            if(thisRipple.childNodes[j].className == 'ripples-circle') targetChild = thisRipple.childNodes[j];
        }

        targetChild.style.top = y + 'px';
        targetChild.style.left = x + 'px';

        thisRipple.className = 'ripples is-active';
    }, false);
    prefixedEvent(ripples[i], "AnimationEnd", function(e){
        e.currentTarget.className = 'ripples';
    });
}

Context

StackExchange Code Review Q#82060, answer score: 3

Revisions (0)

No revisions yet.