CSS 3D动画轮子偏离中心

2022-03-10 00:00:00 javascript html css css-animations

我有一个沿x轴旋转的3D CSS轮子/圆柱体动画。我的问题是动画似乎在容器之外上下移动。下面的GIF示例.

上面的代码可以在这里找到:https://jsfiddle.net/thelevicole/bkt0v1mc/

(function($) {

  const $wheel = $('.wheel .wheel__inner');
  const items = 28;
  const diameter = $wheel.height();
  const radius = diameter / 2;
  const angle = 360 / items;
  const circumference = Math.PI * diameter;
  const height = circumference / items;

  for (let i = 0; i < items; i++) {
    var transform = `rotateX(${ angle * i }deg) translateZ(${ radius }px)`;

    $('<div>', {
      class: 'wheel__segment'
    }).css({
      'transform': transform,
      'height': height,
    }).html(`<span>Item ${ i }</span>`).appendTo($wheel);
  }

})(jQuery);
*,
*:before,
*:after {
  box-sizing: border-box;
}

.wheel {
  perspective: 1000px;
  border: 1px solid #333;
  margin: 50px;
}

.wheel .wheel__inner {
  background-color: red;
  position: relative;
  width: 200px;
  height: 350px;
  margin: 0 auto;
  transform-style: preserve-3d;
  animation-iteration-count: infinite;
  animation-timing-function: linear;
  animation-name: spin;
  animation-duration: 6s;
}

.wheel .wheel__inner .wheel__segment {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 40px;
  position: absolute;
  top: 50%;
  background-color: #ccc;
}

.wheel .wheel__inner .wheel__segment:nth-child(even) {
  background-color: #ddd;
}

@-webkit-keyframes spin {
  0% {
    transform: rotateX(360deg);
  }
  50% {
    transform: rotateX(180deg);
  }
  100% {
    transform: rotateX(0deg);
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wheel">
  <div class="wheel__inner">
  </div>
</div>

红色窗格是片段容器,这是带有CSS动画的元素。红色窗格保留在容器内,但是,线段垂直偏移,从而将它们推出容器。

我可以通过向每个段添加transform-origin: 50% 0;来停止这种上下移动,但这会带来一个新问题。两段之间的缝隙!请参见下面.

上述代码:https://jsfiddle.net/thelevicole/bkt0v1mc/1/

( function( $ ) {

    const $wheel = $( '.wheel .wheel__inner' );
    const items = 28;
    const diameter = $wheel.height();
    const radius = diameter / 2;
    const angle = 360 / items;
    const circumference = Math.PI * diameter;
    const height = circumference / items;
    
    for ( let i = 0; i < items; i++ ) {
        var transform = `rotateX(${ angle * i }deg) translateZ(${ radius }px)`;

        $( '<div>', {
            class: 'wheel__segment'
        } ).css( {
            'transform': transform,
            'height': height,
        } ).html( `<span>Item ${ i }</span>` ).appendTo( $wheel );
    }
    
} )( jQuery );
*, *:before, *:after {
  box-sizing: border-box;
}

.wheel {
  perspective: 1000px;
  border: 1px solid #333;
  margin: 50px;
}
.wheel .wheel__inner {
  background-color: red;
  position: relative;
  width: 200px;
  height: 350px;
  margin: 0 auto;
  transform-style: preserve-3d;
  animation-iteration-count: infinite;
  animation-timing-function: linear;
  animation-name: spin;
  animation-duration: 6s;
}
.wheel .wheel__inner .wheel__segment {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 40px;
  position: absolute;
  top: 50%;
  background-color: #ccc;
  transform-origin: 50% 0;
}
.wheel .wheel__inner .wheel__segment:nth-child(even) {
  background-color: #ddd;
}

@-webkit-keyframes spin {
  0% {
    transform: rotateX(360deg);
  }
  50% {
    transform: rotateX(180deg);
  }
  100% {
    transform: rotateX(0deg);
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wheel">
    <div class="wheel__inner">
    </div>
</div>

任何帮助都是最好的!


解决方案

您可以通过调整旋转元素的transform-origin来纠正此问题,如下所示:

transform-origin: 50% calc(50% + height/2);
( function( $ ) {

    const $wheel = $( '.wheel .wheel__inner' );
    const items = 28;
    const diameter = $wheel.height();
    const radius = diameter / 2;
    const angle = 360 / items;
    const circumference = Math.PI * diameter;
    const height = circumference / items;
    
    for ( let i = 0; i < items; i++ ) {
        var transform = `rotateX(${ angle * i }deg) translateZ(${ radius }px)`;

        $( '<div>', {
            class: 'wheel__segment'
        } ).css( {
            'transform': transform,
            'height': height,
        } ).html( `<span>Item ${ i }</span>` ).appendTo( $wheel );
    }
  $wheel.css('transform-origin','50% calc(50% + '+height/2+'px)');
  $wheel.css('margin-top','-'+height+'px'); /* negative margin here to keep the element into the center */
    
} )( jQuery );
*, *:before, *:after {
  box-sizing: border-box;
}

.wheel {
  perspective: 1000px;
  border: 1px solid #333;
  margin: 50px;
}
.wheel .wheel__inner {
  background-color: red;
  position: relative;
  width: 200px;
  height: 350px;
  margin: 0 auto ; 
  transform-style: preserve-3d;
  animation-iteration-count: infinite;
  animation-timing-function: linear;
  animation-name: spin;
  animation-duration: 6s;
}
.wheel .wheel__inner .wheel__segment {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 40px;
  position: absolute;
  top: 50%;
  background-color: #ccc;
}
.wheel .wheel__inner .wheel__segment:nth-child(even) {
  background-color: #ddd;
}

@-webkit-keyframes spin {
  0% {
    transform: rotateX(360deg);
  }
  50% {
    transform: rotateX(180deg);
  }
  100% {
    transform: rotateX(0deg);
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wheel">
    <div class="wheel__inner">
    </div>
</div>

相关文章