user1658560
user1658560

Reputation: 540

Applying tilt 3D Hover Effect to Multiple Divs

I have this JavaScript "3D tilt" hover effect: https://jsfiddle.net/qdc4v1jg/

The code works fine when it's applied to one div, but when it's applied to more than one div, it doesn't work.

I tried to get the code to work with multiple divs by:

However, none of these changes worked. As you can see here: https://jsfiddle.net/qdc4v1jg/1/

If anyone could help me out with this, I'd greatly appreciate it. Again, I just need this 3D hover effect to work with multiple divs (an unlimited amount).

Upvotes: 1

Views: 823

Answers (2)

kvncnls
kvncnls

Reputation: 261

Wow, that's so cool! Correct me if I'm wrong, but getElementsByClassName returns an HTML collection, right? Wouldn't you need to turn it into an array and then use 'forEach' to add an event listener to each one?

P.S. You've probably got some of the best comments on your code I've seen on Stackoverflow (I'm new, so I obviously haven't seen much haha)

EDIT: Sorry it took a while for me to reply back! Here's the solution. I've added comments to the changes I've made. I basically put the majority of your code under forEach so that everything is applied to EACH item in the array we created.

/* Store the elements with class "tilt" in elements */
let elements = Array.from(document.getElementsByClassName("tilt"));

/* For each 'item' in the "elements" array... */
elements.forEach((item) => {
  /* Assign each 'item' in the "elements" array to a variable called "el" */
  let el = item;

  /*
   * Add a listener for mousemove event
   * Which will trigger function 'handleMove'
   * On mousemove
   */
  el.addEventListener("mousemove", handleMove);

  /* Get the height and width of the element */
  const height = el.clientHeight;
  const width = el.clientWidth;

  /* Define function a */
  function handleMove(e) {
    /*
     * Get position of mouse cursor
     * With respect to the element
     * On mouseover
     */
    /* Store the x position */
    const xVal = e.layerX;
    /* Store the y position */
    const yVal = e.layerY;

    /*
     * Calculate rotation valuee along the Y-axis
     * Here the multiplier 20 is to
     * Control the rotation
     * You can change the value and see the results
     */
    const yRotation = 20 * ((xVal - width / 2) / width);

    /* Calculate the rotation along the X-axis */
    const xRotation = -20 * ((yVal - height / 2) / height);

    /* Generate string for CSS transform property */
    const string =
      "perspective(500px) scale(1.1) rotateX(" +
      xRotation +
      "deg) rotateY(" +
      yRotation +
      "deg)";

    /* Apply the calculated transformation */
    el.style.transform = string;
  }

  /* Add listener for mouseout event, remove the rotation */
  el.addEventListener("mouseout", function () {
    el.style.transform = "perspective(500px) scale(1) rotateX(0) rotateY(0)";
  });

  /* Add listener for mousedown event, to simulate click */
  el.addEventListener("mousedown", function () {
    el.style.transform = "perspective(500px) scale(0.9) rotateX(0) rotateY(0)";
  });

  /* Add listener for mouseup, simulate release of mouse click */
  el.addEventListener("mouseup", function () {
    el.style.transform = "perspective(500px) scale(1.1) rotateX(0) rotateY(0)";
  });
});
html {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
}

/* Styles for the tilt block */
.tilt {
  display: block;
  height: 200px;
  width: 300px;
  background-color: grey;
  margin: 50px auto;
  transition: box-shadow 0.1s, transform 0.1s;

  /*
     * Adding image to the background
     * No relation to the hover effect.
     */
  background-image: url(http://unsplash.it/300/200);
  background-size: 100%;
  background-repeat: no-repeat;
}

.tilt:hover {
  box-shadow: 0px 0px 30px rgba(0, 0, 0, 0.6);
  cursor: pointer;
}
  <div class="tilt">
    <!--  Container for our block  -->
  </div>

  <div class="tilt">
    <!--  Container for our block  -->
  </div>

  <div class="tilt">
    <!--  Container for our block  -->
  </div>

Upvotes: 4

Rene van der Lende
Rene van der Lende

Reputation: 5281

Javascript

  • Simply move you Javascript to a function
  • use document.querySelectorAll('.tilt') to create a list of elements
  • remove let el = document.getElementById('tilt')
  • loop the list of elements and attach the 'tilt' listeners to each element found

CSS

  • Change all ID #tilt to class .tilt
  • don't modify <HTML>, but use <body> or a .wrapper instead

HTML

  • Add as many as 'tilt elements' as you like using class="tilt"

Snippet (go 'Full-page' view on SO)

//Traverse an array and execute the passed callback function for each array element found
var forEachEntryIn = function (array, callback, scope) {
 for (var i = 0; i < array.length; i++) { callback.call(scope, i, array[i]); } };

// Create a list of 'tilted' element ojects 
var elList = document.querySelectorAll('.tilt');
// can be any comma delimited selector list, not just '.tilt'

// Attach the tilt listeners to the list of elements
forEachEntryIn(elList, function (idx,el,scope) { connectListener(el); } );

/* 
 * Packed original code in function connectListener()
 * parameter: element object to attach listenener to
 */
function connectListener(el) {

/* Store the element in el */
//let el = document.getElementById('tilt') // REMOVE

/* Get the height and width of the element */
const height = el.clientHeight;
const width = el.clientWidth;

    /*
      * Add a listener for mousemove event
      * Which will trigger function 'handleMove'
      * On mousemove
      */
    el.addEventListener('mousemove', handleMove);

    /* Define function a */
    function handleMove(e) {
      /*
        * Get position of mouse cursor
        * With respect to the element
        * On mouseover
        */
      /* Store the x position */
      const xVal = e.layerX;
      /* Store the y position */
      const yVal = e.layerY;
  
      /*
        * Calculate rotation valuee along the Y-axis
        * Here the multiplier 20 is to
        * Control the rotation
        * You can change the value and see the results
        */
      const yRotation = 20 * ((xVal - width / 2) / width);
  
      /* Calculate the rotation along the X-axis */
      const xRotation = -20 * ((yVal - height / 2) / height);
  
      /* Generate string for CSS transform property */
      const string = 'perspective(500px) scale(1.1) rotateX(' + xRotation + 'deg) rotateY(' + yRotation + 'deg)';
  
      /* Apply the calculated transformation */
      el.style.transform = string;
    }

    /* Add listener for mouseout event, remove the rotation */
    el.addEventListener('mouseout', function() {
      el.style.transform = 'perspective(500px) scale(1) rotateX(0) rotateY(0)';
    });

    /* Add listener for mousedown event, to simulate click */
    el.addEventListener('mousedown', function() {
      el.style.transform = 'perspective(500px) scale(0.9) rotateX(0) rotateY(0)';
    });

    /* Add listener for mouseup, simulate release of mouse click */
    el.addEventListener('mouseup', function() {
      el.style.transform = 'perspective(500px) scale(1.1) rotateX(0) rotateY(0)';
    });
};
body {
    display: flex;
    justify-content: center;
    align-items: center;
    align-content: center; /* CORRECTED, was 'align-contents' */
    height: 100%;
}
/*
    Changed all ID #tilt to Class .tilt 
*/
/* Styles for the tilt block */
.tilt {
    display: block;
    height: 200px;
    width: 300px;
    background-color: grey;
    margin: 3rem auto; /* MOD from '0' to add some space */

    transition: box-shadow 0.1s, transform 0.1s;
  
    /*
        Adding image to the background
        No relation to the hover effect.
    */
    background-image: url(http://unsplash.it/300/200);
    background-size: 100%;
    background-repeat: no-repeat;
}

.tilt:hover {
    box-shadow: 0px 0px 30px rgba(0,0,0, 0.6);
    cursor: pointer;
}
<div class="tilt"></div>
<div class="tilt"></div>
<div class="tilt"></div>
<div class="tilt"></div>

Upvotes: 0

Related Questions