Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I remove the bounce effect when translating away from the screen with css transition?

It's kind of hard to explain in words what I'm looking for without a visual example, so here's the basic idea: https://codepen.io/jwiggiff/full/xxwvVbr

var cube = $('.cube');
var wrapper = $('.wrapper');

$(document).mousemove((e) => {
  if(!cube.hasClass('locked')) {
    var deltaX = e.pageX - (wrapper.offset().left+(wrapper.width()/2));
    var deltaY = e.pageY - (wrapper.offset().top+(wrapper.height()/2));
    var rotateY = deltaX/($(document).width()/2) * 90;
    var rotateX = deltaY/(($(document).height()/2)) * -90;
    cube.css("transform", " rotateY("+rotateY+"deg) rotateX("+rotateX+"deg)");
  }
});

$('.top-label').click((e) => {
  cube.toggleClass('locked locked-bottom');
  $('.labels div:not(.top-label)').fadeToggle();
});
$('.bottom-label').click((e) => {
  cube.toggleClass('locked locked-top');
  $('.labels div:not(.bottom-label)').fadeToggle();
});
$('.left-label').click((e) => {
  cube.toggleClass('locked locked-right');
  $('.labels div:not(.left-label)').fadeToggle();
});
$('.right-label').click((e) => {
  cube.toggleClass('locked locked-left');
  $('.labels div:not(.right-label)').fadeToggle();
});
/* Variables */
:root {
  --cube-scale: 60vh;
}


/* Styles */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  font-family: "Montserrat", sans-serif;
  overflow: hidden;
}

.cube div {
  padding: 10vh;
  border: 5px solid blue;
  transition: all 500ms ease-in-out;
}

.cube div h1 {
  font-family: "Carter One", cursive;
}

.cube div p {
  font-size: 14px;
}


/* Labels */
.labels {
  color: black;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

.labels div {
  transition: all 500ms ease-in-out;
}

.left-label {
  position: absolute;
  top: 50%;
  left: 0;
  transform: translate(0, -50%);
  padding: 20px 10px;
}

.right-label {
  position: absolute;
  top: 50%;
  right: 0;
  transform: translate(0, -50%);
  padding: 20px 10px;
}

.top-label {
  position: absolute;
  top: 0;
  left: 50%;
  width: 100%;
  text-align: center;
  transform: translate(-50%, 0);
  padding: 10px 20px;
}

.bottom-label {
  position: absolute;
  bottom: 0;
  left: 50%;
  width: 100%;
  text-align: center;
  transform: translate(-50%, 0);
  padding: 10px 20px;
}


/* 3D Cube */
.wrapper {
  width: var(--cube-scale);
  height: var(--cube-scale);
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  perspective: calc(var(--cube-scale)*4);
}

.cube {
  width: 100%;
  height: 100%;
  position: relative;
  transform-style: preserve-3d;
}

.cube.locked.locked-bottom {
  transition: all 500ms ease-in-out;
  transform: rotateX(90deg) translateY(calc(var(--cube-scale) / -2)) !important;
}
.locked-bottom .bottom {
  height: 100vh;
  width: 100vw;
  transform: rotateX(-90deg) translateZ(calc(var(--cube-scale) / 2)) translate(calc(((100vw/2) - (var(--cube-scale)/2)) * -1), calc(((100vh/2) - (var(--cube-scale)/2)) * -1));
}

.cube.locked.locked-top {
  transition: all 500ms ease-in-out;
  transform: rotateX(-90deg) translateY(calc(var(--cube-scale) / 2)) !important;
}
.locked-top .top {
  height: 100vh;
  width: 100vw;
  transform: rotateX(90deg) translateZ(calc(var(--cube-scale) / 2)) translate(calc(((100vw/2) - (var(--cube-scale)/2)) * -1), calc(((100vh/2) - (var(--cube-scale)/2)) * -1));
}

.cube.locked.locked-right {
  transition: all 500ms ease-in-out;
  transform: rotateY(-90deg) translateX(calc(var(--cube-scale) / -2)) !important;
}
.locked-right .right {
  height: 100vh;
  width: 100vw;
  transform: rotateY(90deg) translateZ(calc(var(--cube-scale) / 2)) translate(calc(((100vw/2) - (var(--cube-scale)/2)) * -1), calc(((100vh/2) - (var(--cube-scale)/2)) * -1));
}

.cube.locked.locked-left {
  transition: all 500ms ease-in-out;
  transform: rotateY(90deg) translateX(calc(var(--cube-scale) / 2)) !important;
}
.locked-left .left {
  height: 100vh;
  width: 100vw;
  transform: rotateY(-90deg) translateZ(calc(var(--cube-scale) / 2)) translate(calc(((100vw/2) - (var(--cube-scale)/2)) * -1), calc(((100vh/2) - (var(--cube-scale)/2)) * -1));
}

.cube div {
  transform-origin: calc(var(--cube-scale)/2) calc(var(--cube-scale)/2);
	position: absolute;
	width: var(--cube-scale);
	height: var(--cube-scale);
}

.front {
  background: rgba(255,0,0,0.7);
  transform: rotateY(0deg) translateZ(calc(var(--cube-scale) / 2));
}

.right {
  background-color: rgba(0,255,0,0.7);
  transform: rotateY(90deg) translateZ(calc(var(--cube-scale) / 2));
}

.back {
  background-color: rgba(0,0,255,0.7);
  transform: rotateY(180deg) translateZ(calc(var(--cube-scale) / 2));
}

.left {
  background-color: rgba(255,165,0,0.7);
  transform: rotateY(-90deg) translateZ(calc(var(--cube-scale) / 2));
}

.top {
  background-color: rgba(128,0,128,0.7);
  transform: rotateX(90deg) translateZ(calc(var(--cube-scale) / 2));
}

.bottom {
  background-color: rgba(255,0,255,0.7);
  transform: rotateX(-90deg) translateZ(calc(var(--cube-scale) / 2));
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wrapper">
  <div class="cube">
    <div class="front"></div>
    <div class="back"></div>
    <div class="left"></div>
    <div class="right"></div>
    <div class="top"></div>
    <div class="bottom"></div>
  </div>
</div>
<div class="labels">
  <div class="left-label"><span>Right</span></div>
  <div class="right-label"><span>Left</span></div>
  <div class="top-label"><span>Bottom</span></div>
  <div class="bottom-label"><span>Top</span></div>
</div>

In the codepen, if you click the text on the edge of the screen, it moves the current face to cover the entire window. When you click the left or right text, it has the expected result. However, if you click the top or the bottom text, you can see the cube has a bit of an arc when translating away from the screen, whereas the left/right ones do not. Any ideas as to what is causing this bounce/arc and how to fix it would be much appreciated!

like image 636
Jwiggiff Avatar asked May 29 '20 21:05

Jwiggiff


People also ask

How do I make text bounce up and down in CSS?

The text we’re about to create gives off the illusion of bouncing up and down on the viewport. The bounce effect is created using CSS animations and by manipulated CSS’s text-shadow property.

How to prevent bounce scroll in the browser on a website?

Bounce scroll in the browser is a feature of some versions of iOS / macOS. To prevent it from happening on a website we can use the following: html, body { height: 100%; overflow: hidden; } #main-container { position: absolute; top: 0; bottom: 0; left: 0; right: 0; overflow: auto; } While the accepted answer works.

Can I change the speed of the bouncing animation?

As you read through the tutorial, keep in mind that just about every stylistic choice you see, from font families to colors to even the speed of the bouncing animation are totally customizable and can always be changed to suit the needs of any project. The effect in this tutorial is adapted from this CodePen.

What is the use of a bounce animation?

Bounce Animation effect is used to move the element quick up, back, or away from a surface after hitting it.


1 Answers

Add rotateY(0) to .cube.locked.locked-bottom and to .cube.locked.locked-top to avoid this issue.

It's a bit tricky but this is due to the fact that you are applying a dynamic transformation using rotateY(a) rotateX(b) and this will not transition the same way to rotateX() translateZ() and to rotateY() translateZ(). If you make rotateX() translateZ() equal to rotateY(0) rotateX() translateZ() you will have the same transition:

var cube = $('.cube');
var wrapper = $('.wrapper');

$(document).mousemove((e) => {
  if(!cube.hasClass('locked')) {
    var deltaX = e.pageX - (wrapper.offset().left+(wrapper.width()/2));
    var deltaY = e.pageY - (wrapper.offset().top+(wrapper.height()/2));
    var rotateY = deltaX/($(document).width()/2) * 90;
    var rotateX = deltaY/(($(document).height()/2)) * -90;
    cube.css("transform", " rotateY("+rotateY+"deg) rotateX("+rotateX+"deg)");
  }
});

$('.top-label').click((e) => {
  cube.toggleClass('locked locked-bottom');
  $('.labels div:not(.top-label)').fadeToggle();
});
$('.bottom-label').click((e) => {
  cube.toggleClass('locked locked-top');
  $('.labels div:not(.bottom-label)').fadeToggle();
});
$('.left-label').click((e) => {
  cube.toggleClass('locked locked-right');
  $('.labels div:not(.left-label)').fadeToggle();
});
$('.right-label').click((e) => {
  cube.toggleClass('locked locked-left');
  $('.labels div:not(.right-label)').fadeToggle();
});
/* Variables */
:root {
  --cube-scale: 60vh;
}


/* Styles */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  font-family: "Montserrat", sans-serif;
  overflow: hidden;
}

.cube div {
  padding: 10vh;
  border: 5px solid blue;
  transition: all 500ms ease-in-out;
}

.cube div h1 {
  font-family: "Carter One", cursive;
}

.cube div p {
  font-size: 14px;
}


/* Labels */
.labels {
  color: black;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

.labels div {
  transition: all 500ms ease-in-out;
}

.left-label {
  position: absolute;
  top: 50%;
  left: 0;
  transform: translate(0, -50%);
  padding: 20px 10px;
}

.right-label {
  position: absolute;
  top: 50%;
  right: 0;
  transform: translate(0, -50%);
  padding: 20px 10px;
}

.top-label {
  position: absolute;
  top: 0;
  left: 50%;
  width: 100%;
  text-align: center;
  transform: translate(-50%, 0);
  padding: 10px 20px;
}

.bottom-label {
  position: absolute;
  bottom: 0;
  left: 50%;
  width: 100%;
  text-align: center;
  transform: translate(-50%, 0);
  padding: 10px 20px;
}


/* 3D Cube */
.wrapper {
  width: var(--cube-scale);
  height: var(--cube-scale);
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  perspective: calc(var(--cube-scale)*4);
}

.cube {
  width: 100%;
  height: 100%;
  position: relative;
  transform-style: preserve-3d;
}

/*here*/
.cube.locked.locked-bottom {
  transition: all 500ms ease-in-out;
  transform:rotateY(0) rotateX(90deg) translateY(calc(var(--cube-scale) / -2)) !important;
}
.locked-bottom .bottom {
  height: 100vh;
  width: 100vw;
  transform: rotateX(-90deg) translateZ(calc(var(--cube-scale) / 2)) translate(calc(((100vw/2) - (var(--cube-scale)/2)) * -1), calc(((100vh/2) - (var(--cube-scale)/2)) * -1));
}

/* here */
.cube.locked.locked-top {
  transition: all 500ms ease-in-out;
  transform:rotateY(0) rotateX(-90deg) translateY(calc(var(--cube-scale) / 2)) !important;
}
.locked-top .top {
  height: 100vh;
  width: 100vw;
  transform:rotateY(0) rotateX(90deg) translateZ(calc(var(--cube-scale) / 2)) translate(calc(((100vw/2) - (var(--cube-scale)/2)) * -1), calc(((100vh/2) - (var(--cube-scale)/2)) * -1));
}

.cube.locked.locked-right {
  transition: all 500ms ease-in-out;
  transform: rotateY(-90deg) translateX(calc(var(--cube-scale) / -2)) !important;
}
.locked-right .right {
  height: 100vh;
  width: 100vw;
  transform: rotateY(90deg) translateZ(calc(var(--cube-scale) / 2)) translate(calc(((100vw/2) - (var(--cube-scale)/2)) * -1), calc(((100vh/2) - (var(--cube-scale)/2)) * -1));
}

.cube.locked.locked-left {
  transition: all 500ms ease-in-out;
  transform: rotateY(90deg) translateX(calc(var(--cube-scale) / 2)) !important;
}
.locked-left .left {
  height: 100vh;
  width: 100vw;
  transform: rotateY(-90deg) translateZ(calc(var(--cube-scale) / 2)) translate(calc(((100vw/2) - (var(--cube-scale)/2)) * -1), calc(((100vh/2) - (var(--cube-scale)/2)) * -1));
}

.cube div {
  transform-origin: calc(var(--cube-scale)/2) calc(var(--cube-scale)/2);
	position: absolute;
	width: var(--cube-scale);
	height: var(--cube-scale);
}

.front {
  background: rgba(255,0,0,0.7);
  transform: rotateY(0deg) translateZ(calc(var(--cube-scale) / 2));
}

.right {
  background-color: rgba(0,255,0,0.7);
  transform: rotateY(90deg) translateZ(calc(var(--cube-scale) / 2));
}

.back {
  background-color: rgba(0,0,255,0.7);
  transform: rotateY(180deg) translateZ(calc(var(--cube-scale) / 2));
}

.left {
  background-color: rgba(255,165,0,0.7);
  transform: rotateY(-90deg) translateZ(calc(var(--cube-scale) / 2));
}

.top {
  background-color: rgba(128,0,128,0.7);
  transform:  rotateX(90deg) translateZ(calc(var(--cube-scale) / 2));
}

.bottom {
  background-color: rgba(255,0,255,0.7);
  transform: rotateX(-90deg) translateZ(calc(var(--cube-scale) / 2));
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wrapper">
  <div class="cube">
    <div class="front"></div>
    <div class="back"></div>
    <div class="left"></div>
    <div class="right"></div>
    <div class="top"></div>
    <div class="bottom"></div>
  </div>
</div>
<div class="labels">
  <div class="left-label"><span>Right</span></div>
  <div class="right-label"><span>Left</span></div>
  <div class="top-label"><span>Bottom</span></div>
  <div class="bottom-label"><span>Top</span></div>
</div>

Related question to get more details about how interpolation is done between transform: Weird behavior when rotating an element on hover

like image 103
Temani Afif Avatar answered Oct 22 '22 17:10

Temani Afif