Direction-Aware 3D Hover Animation With JavaScript And CSS3

Category: Animation , Javascript | February 17, 2017
Author:noeldelgado
Views Total:885 views
Official Page:Go to website
Last Update:February 17, 2017
License:MIT

Preview:

Direction-Aware 3D Hover Animation With JavaScript And CSS3

Description:

A Pure JavaScript & CSS3 solution to apply a direction-aware 3D rotation effect to cubes on hover over.

How to use it:

Add cubes to the webpage as follows:

<ul class='-center'>
  <li>
    <div class='w'>
      <div class='f'>
        <svg viewBox='0 0 180 180'>
          <image height='100%' preserveAspectRatio='xMidYMid slice' width='100%' xlink:href='https://s3-us-west-2.amazonaws.com/s.cdpn.io/9473/i-angus.png'></image>
        </svg>
      </div>
      <div class='b'>
        <h3>
          Angus Young
        </h3>
      </div>
    </div>
  </li>
  <li>
    <div class='w'>
      <div class='f'>
        <svg viewBox='0 0 180 180'>
          <image height='100%' preserveAspectRatio='xMidYMid slice' width='100%' xlink:href='https://s3-us-west-2.amazonaws.com/s.cdpn.io/9473/i-aurora.png'></image>
        </svg>
      </div>
      <div class='b'>
        <h3>
          Aurora
        </h3>
      </div>
    </div>
  </li>
  <li>
    <div class='w'>
      <div class='f'>
        <svg viewBox='0 0 180 180'>
          <image height='100%' preserveAspectRatio='xMidYMid slice' width='100%' xlink:href='https://s3-us-west-2.amazonaws.com/s.cdpn.io/9473/i-bride.png'></image>
        </svg>
      </div>
      <div class='b'>
        <h3>
          Bride of Frankenstein
        </h3>
      </div>
    </div>
  </li>
  <li>
    <div class='w'>
      <div class='f'>
        <svg viewBox='0 0 180 180'>
          <image height='100%' preserveAspectRatio='xMidYMid slice' width='100%' xlink:href='https://s3-us-west-2.amazonaws.com/s.cdpn.io/9473/i-d.png'></image>
        </svg>
      </div>
      <div class='b'>
        <h3>
          Dracula
        </h3>
      </div>
    </div>
  </li>
</ul>

The main CSS/CSS3 rules.

li {
  margin: 5px;
  position: relative;
  width: 180px;
  height: 180px;
  display: inline-block;
  vertical-align: top;
  -webkit-perspective: 300px;
          perspective: 300px;
  -webkit-transform-origin: 50% 50% 90px;
          transform-origin: 50% 50% 90px;
}
.w {
  font-size: medium;
  font-size: initial;
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  pointer-events: none;
  -webkit-transform-style: preserve-3d;
          transform-style: preserve-3d;
  -webkit-transform-origin: 50% 50% -90px;
          transform-origin: 50% 50% -90px;
  will-change: transform;
  -webkit-animation: 200ms ease-out 0ms 1 normal forwards paused;
          animation: 200ms ease-out 0ms 1 normal forwards paused;
}
.f,
.b {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  color: white;
  -webkit-transition: none;
  transition: none;
}
.f {
  background-color: #00BCD4;
  background: -webkit-linear-gradient(#00BCD4, #673AB7);
  background: linear-gradient(#00BCD4, #673AB7);
  -webkit-transform: translate3d(0,0,0);
          transform: translate3d(0,0,0)
}
.f > svg{
  mix-blend-mode: luminosity;
}
.b {
  padding: 16px;
  padding: 1rem;
  background-image: -webkit-radial-gradient(circle, #333, #000 160%);
  background-image: radial-gradient(circle, #333, #000 160%);
  -webkit-transform: translate3d(0,0,-1px);
          transform: translate3d(0,0,-1px);
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-align: center;
      -ms-flex-align: center;
          align-items: center;
  -webkit-box-pack: center;
      -ms-flex-pack: center;
          justify-content: center;
  text-shadow: 0 20px 20px black;
  text-align: center;
}
.in-top .b,
.out-top .b {
  -webkit-transform-origin: 0% 100%;
          transform-origin: 0% 100%;
  -webkit-transform: translate3d(0, -100%, 0) rotate3d(1,0,0,90deg);
          transform: translate3d(0, -100%, 0) rotate3d(1,0,0,90deg);
}
.in-right .b,
.out-right .b {
  -webkit-transform-origin: 0% 0%;
          transform-origin: 0% 0%;
  -webkit-transform: translate3d(100%, 0, 0) rotate3d(0,1,0,90deg);
          transform: translate3d(100%, 0, 0) rotate3d(0,1,0,90deg);
}
.in-bottom .b,
.out-bottom .b {
  -webkit-transform-origin: 0% 0%;
          transform-origin: 0% 0%;
  -webkit-transform: translate3d(0, 100%, 0) rotate3d(-1,0,0,90deg);
          transform: translate3d(0, 100%, 0) rotate3d(-1,0,0,90deg);
}
.in-left .b,
.out-left .b {
  -webkit-transform-origin: 100% 0;
          transform-origin: 100% 0;
  -webkit-transform: translate3d(-100%,0,0) rotate3d(0,-1,0,90deg);
          transform: translate3d(-100%,0,0) rotate3d(0,-1,0,90deg);
}
.in {
}
.in-top .w{
  -webkit-animation-name: in-top;
          animation-name: in-top;
  -webkit-animation-play-state: running;
          animation-play-state: running;
}
.in-right .w{
  -webkit-animation-name: in-right;
          animation-name: in-right;
  -webkit-animation-play-state: running;
          animation-play-state: running;
}
.in-bottom .w{
  -webkit-animation-name: in-bottom;
          animation-name: in-bottom;
  -webkit-animation-play-state: running;
          animation-play-state: running;
}
.in-left .w{
  -webkit-animation-name: in-left;
          animation-name: in-left;
  -webkit-animation-play-state: running;
          animation-play-state: running;
}
.out {
}
.out-top .w{
  -webkit-animation-name: out-top;
          animation-name: out-top;
  -webkit-animation-play-state: running;
          animation-play-state: running;
}
.out-right .w{
  -webkit-animation-name: out-right;
          animation-name: out-right;
  -webkit-animation-play-state: running;
          animation-play-state: running;
}
.out-bottom .w{
  -webkit-animation-name: out-bottom;
          animation-name: out-bottom;
  -webkit-animation-play-state: running;
          animation-play-state: running;
}
.out-left .w{
  -webkit-animation-name: out-left;
          animation-name: out-left;
  -webkit-animation-play-state: running;
          animation-play-state: running;
}

The main CSS3 powered animations:

@-webkit-keyframes in-top {
  from  {-webkit-transform: rotate3d(0,0,0,0deg);transform: rotate3d(0,0,0,0deg)}
  to    {-webkit-transform: rotate3d(-1,0,0,90deg);transform: rotate3d(-1,0,0,90deg)}
}
@keyframes in-top {
  from  {-webkit-transform: rotate3d(0,0,0,0deg);transform: rotate3d(0,0,0,0deg)}
  to    {-webkit-transform: rotate3d(-1,0,0,90deg);transform: rotate3d(-1,0,0,90deg)}
}
@-webkit-keyframes out-top {
  from {-webkit-transform: rotate3d(-1,0,0,90deg);transform: rotate3d(-1,0,0,90deg)}
  to   {-webkit-transform: rotate3d(0,0,0,0deg);transform: rotate3d(0,0,0,0deg)}
}
@keyframes out-top {
  from {-webkit-transform: rotate3d(-1,0,0,90deg);transform: rotate3d(-1,0,0,90deg)}
  to   {-webkit-transform: rotate3d(0,0,0,0deg);transform: rotate3d(0,0,0,0deg)}
}
@-webkit-keyframes in-right {
  from  {-webkit-transform: rotate3d(0,0,0,0deg);transform: rotate3d(0,0,0,0deg)}
  to    {-webkit-transform: rotate3d(0,-1,0,90deg);transform: rotate3d(0,-1,0,90deg)}
}
@keyframes in-right {
  from  {-webkit-transform: rotate3d(0,0,0,0deg);transform: rotate3d(0,0,0,0deg)}
  to    {-webkit-transform: rotate3d(0,-1,0,90deg);transform: rotate3d(0,-1,0,90deg)}
}
@-webkit-keyframes out-right {
  from  {-webkit-transform: rotate3d(0,-1,0,90deg);transform: rotate3d(0,-1,0,90deg)}
  to    {-webkit-transform: rotate3d(0,0,0,0deg);transform: rotate3d(0,0,0,0deg)}
}
@keyframes out-right {
  from  {-webkit-transform: rotate3d(0,-1,0,90deg);transform: rotate3d(0,-1,0,90deg)}
  to    {-webkit-transform: rotate3d(0,0,0,0deg);transform: rotate3d(0,0,0,0deg)}
}
@-webkit-keyframes in-bottom {
  from  {-webkit-transform: rotate3d(0,0,0,0deg);transform: rotate3d(0,0,0,0deg)}
  to    {-webkit-transform: rotate3d(1,0,0,90deg);transform: rotate3d(1,0,0,90deg)}
}
@keyframes in-bottom {
  from  {-webkit-transform: rotate3d(0,0,0,0deg);transform: rotate3d(0,0,0,0deg)}
  to    {-webkit-transform: rotate3d(1,0,0,90deg);transform: rotate3d(1,0,0,90deg)}
}
@-webkit-keyframes out-bottom {
  from  {-webkit-transform: rotate3d(1,0,0,90deg);transform: rotate3d(1,0,0,90deg)}
  to    {-webkit-transform: rotate3d(0,0,0,0deg);transform: rotate3d(0,0,0,0deg)}
}
@keyframes out-bottom {
  from  {-webkit-transform: rotate3d(1,0,0,90deg);transform: rotate3d(1,0,0,90deg)}
  to    {-webkit-transform: rotate3d(0,0,0,0deg);transform: rotate3d(0,0,0,0deg)}
}
@-webkit-keyframes in-left {
  from  {-webkit-transform: rotate3d(0,0,0,0deg);transform: rotate3d(0,0,0,0deg)}
  to    {-webkit-transform: rotate3d(0,1,0,90deg);transform: rotate3d(0,1,0,90deg)}
}
@keyframes in-left {
  from  {-webkit-transform: rotate3d(0,0,0,0deg);transform: rotate3d(0,0,0,0deg)}
  to    {-webkit-transform: rotate3d(0,1,0,90deg);transform: rotate3d(0,1,0,90deg)}
}
@-webkit-keyframes out-left {
  from  {-webkit-transform: rotate3d(0,1,0,90deg);transform: rotate3d(0,1,0,90deg)}
  to    {-webkit-transform: rotate3d(0,0,0,0deg);transform: rotate3d(0,0,0,0deg)}
}
@keyframes out-left {
  from  {-webkit-transform: rotate3d(0,1,0,90deg);transform: rotate3d(0,1,0,90deg)}
  to    {-webkit-transform: rotate3d(0,0,0,0deg);transform: rotate3d(0,0,0,0deg)}
}

The core JavaScript to active the effect.

class DAH {
  constructor(nodes) {
    this.nodes = [];
    Array.prototype.slice.call(nodes, 0).forEach(node => {
      this.nodes.push(new Node(node));
    });
    this._bindEvents();
  }
  _bindEvents() {
    ['_resizeHandler'].forEach(fn => this[fn] = this[fn].bind(this));
    window.addEventListener('resize', this._resizeHandler, false);
  }
  _resizeHandler() {
    this.nodes.forEach(node => node.update());
  }
}
class Node {
  constructor(node) {
    this.element = node;
    this._bindEvents().update();
  }
  update() {
    // const bcr = this.element.getBoundingClientRect();
    // this.l = bcr.left;
    // this.t = bcr.top;
    this.w = this.element.offsetWidth;
    this.h = this.element.offsetHeight;
    this.l = this.element.offsetLeft;
    this.t = this.element.offsetTop;
  }
  _bindEvents() {
    ['_mouseEnterHandler', '_mouseOutHandler'].forEach(fn => this[fn] = this[fn].bind(this));
    this.element.addEventListener('mouseenter', this._mouseEnterHandler, false);
    this.element.addEventListener('mouseout', this._mouseOutHandler, false);
    return this;
  }
  
  _mouseEnterHandler(ev) {
    this._addClass(ev, 'in');
  }
  _mouseOutHandler(ev) {
    this._addClass(ev, 'out');
  }
  _addClass(ev, state) {
    const direction = this._getDirection(ev);
    let class_suffix = '';
    switch (direction) {
      case 0: class_suffix = '-top'; break;
      case 1: class_suffix = '-right'; break;
      case 2: class_suffix = '-bottom'; break;
      case 3: class_suffix = '-left'; break;
    }
    this.element.className = '';
    this.element.classList.add(state + class_suffix);
  }
  _getDirection(ev) {
    const w = this.w,
      h = this.h,
      x = (ev.pageX - this.l - (w / 2) * (w > h ? (h / w) : 1)),
      y = (ev.pageY - this.t - (h / 2) * (h > w ? (w / h) : 1)),
      d = Math.round(Math.atan2(y, x) / 1.57079633 + 5) % 4;
    return d;
  }
}
new DAH(document.querySelectorAll('li'));

 

You Might Be Interested In:


One thought on “Direction-Aware 3D Hover Animation With JavaScript And CSS3

Leave a Reply