You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现文字环绕固定图片的3D旋转视觉效果

解决方案:让图片固定静止,文字环绕旋转

问题根源

你的.phone_static容器嵌套在.preloader内部,而.preloader应用了tiltSpin旋转动画——父元素的3D变换会传递给所有子元素,所以无论给.phone_static设置position:fixed还是反向动画,都会被父容器的动画覆盖,导致图片跟着旋转。

修复步骤

  1. 移出图片容器:把.phone_static从.preloader中剥离,作为body的直接子元素,脱离父容器的动画上下文。
  2. 重新定位图片:调整.phone_static的CSS,让它居中显示在文字旋转的中心位置,同时设置合适的z-index保证文字能在图片前后穿梭。
  3. 修正CSS错误:清理原代码里的无效语法(比如多余的闭合大括号、reversespin动画里的rotateY(deg)错误值)。

修改后的完整代码

HTML

<body>
  <div class="preloader">
    <div class="preloader__ring">
      <div class="preloader__sector"></div>
      <div class="preloader__sector">S</div>
      <div class="preloader__sector">E</div>
      <div class="preloader__sector">A</div>
      <div class="preloader__sector">M</div>
      <div class="preloader__sector">L</div>
      <div class="preloader__sector">E</div>
      <div class="preloader__sector">S</div>
      <div class="preloader__sector">S</div>
      <div class="preloader__sector"></div>
      <div class="preloader__sector"></div>
      <div class="preloader__sector"></div>
      <div class="preloader__sector"></div>
      <div class="preloader__sector"></div>
      <div class="preloader__sector"></div>
      <div class="preloader__sector"></div>
      <div class="preloader__sector"></div>
      <div class="preloader__sector"></div>
      <div class="preloader__sector"></div>
      <div class="preloader__sector"></div>
      <div class="preloader__sector"></div>
      <div class="preloader__sector"></div>
      <div class="preloader__sector"></div>
      <div class="preloader__sector"></div>
      <div class="preloader__sector"></div>
      <div class="preloader__sector"></div>
      <div class="preloader__sector"></div>
      <div class="preloader__sector"></div>
      <div class="preloader__sector"></div>
      <div class="preloader__sector"></div>
      <div class="preloader__sector"></div>
    </div>
    <div class="preloader__ring">
      <div class="preloader__sector">U</div>
      <div class="preloader__sector">S</div>
      <div class="preloader__sector">E</div>
      <div class="preloader__sector">R</div>
      <div class="preloader__sector"></div>
      <div class="preloader__sector">E</div>
      <div class="preloader__sector">X</div>
      <div class="preloader__sector">P</div>
      <div class="preloader__sector">E</div>
      <div class="preloader__sector">R</div>
      <div class="preloader__sector">I</div>
      <div class="preloader__sector">E</div>
      <div class="preloader__sector">N</div>
      <div class="preloader__sector">C</div>
      <div class="preloader__sector">S</div>
      <div class="preloader__sector"></div>
      <div class="preloader__sector"></div>
      <div class="preloader__sector"></div>
      <div class="preloader__sector"></div>
      <div class="preloader__sector"></div>
      <div class="preloader__sector"></div>
      <div class="preloader__sector"></div>
      <div class="preloader__sector"></div>
      <div class="preloader__sector"></div>
      <div class="preloader__sector"></div>
      <div class="preloader__sector"></div>
      <div class="preloader__sector"></div>
      <div class="preloader__sector"></div>
      <div class="preloader__sector"></div>
      <div class="preloader__sector"></div>
    </div>
  </div>
  <div class="phone_static">
    <img src="https://github.com/Jitlclarke/ux_portfolio/blob/main/images/small_version_mockup.png?raw=true" alt="" height=560 width=300>
  </div>
</body>

CSS

body {
  background-color: #333;
  background: #313030;
  color: #D3E2C0;
  font: 1em Dosis, sans-serif;
  height: 100vh;
  line-height: 1.5;
  perspective: 40em;
  margin: 0;
  position: relative;
}

:root {
  font-size: calc(16px + (24 - 16)*(100vw - 320px)/ (1280 - 320));
}

.preloader {
  animation: tiltSpin 10s linear infinite;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  margin: auto;
  width: 17em;
  height: 17em;
  display: flex;
}

.preloader,
.preloader__ring {
  transform-style: preserve-3d;
}

.preloader__ring {
  animation-name: spin;
  animation-duration: 70s;
  animation-timing-function: inherit;
  animation-iteration-count: inherit;
  font-size: 2em;
  position: relative;
  top: 100px;
  height: 3rem;
  width: 1.5rem;
}

.phone_static {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 1;
}

.preloader__ring:nth-child(even) {
  animation-direction: forward;
}
.second_preloader:nth-child(even) {
  animation-direction: forward;
  animation-duration: 100s;
}
.preloader__sector {
  font-weight: 600;
  position: absolute;
  top: 0;
  left: 0;
  text-align: center;
  text-transform: uppercase;
  transform: translateZ(7rem);
}
.preloader__sector,
.preloader__sector:empty:before {
  display: inline-block;
  width: 100%;
  height: 100%;
}
.preloader__sector:empty:before {
  background: linear-gradient(transparent 45%, currentColor 45% 55%, transparent 55%);
  content: "";
}
.preloader__sector:nth-child(2) {
  transform: rotateY(12deg) translateZ(7rem);
}
.preloader__sector:nth-child(3) {
  transform: rotateY(24deg) translateZ(7rem);
}
.preloader__sector:nth-child(4) {
  transform: rotateY(36deg) translateZ(7rem);
}
.preloader__sector:nth-child(5) {
  transform: rotateY(48deg) translateZ(7rem);
}
.preloader__sector:nth-child(6) {
  transform: rotateY(60deg) translateZ(7rem);
}
.preloader__sector:nth-child(7) {
  transform: rotateY(72deg) translateZ(7rem);
}
.preloader__sector:nth-child(8) {
  transform: rotateY(84deg) translateZ(7rem);
}
.preloader__sector:nth-child(9) {
  transform: rotateY(96deg) translateZ(7rem);
}
.preloader__sector:nth-child(10) {
  transform: rotateY(108deg) translateZ(7rem);
}
.preloader__sector:nth-child(11) {
  transform: rotateY(120deg) translateZ(7rem);
}
.preloader__sector:nth-child(12) {
  transform: rotateY(132deg) translateZ(7rem);
}
.preloader__sector:nth-child(13) {
  transform: rotateY(144deg) translateZ(7rem);
}
.preloader__sector:nth-child(14) {
  transform: rotateY(156deg) translateZ(7rem);
}
.preloader__sector:nth-child(15) {
  transform: rotateY(168deg) translateZ(7rem);
}
.preloader__sector:nth-child(16) {
  transform: rotateY(180deg) translateZ(7rem);
}
.preloader__sector:nth-child(17) {
  transform: rotateY(192deg) translateZ(7rem);
}
.preloader__sector:nth-child(18) {
  transform: rotateY(204deg) translateZ(7rem);
}
.preloader__sector:nth-child(19) {
  transform: rotateY(216deg) translateZ(7rem);
}
.preloader__sector:nth-child(20) {
  transform: rotateY(228deg) translateZ(7rem);
}
.preloader__sector:nth-child(21) {
  transform: rotateY(240deg) translateZ(7rem);
}
.preloader__sector:nth-child(22) {
  transform: rotateY(252deg) translateZ(7rem);
}
.preloader__sector:nth-child(23) {
  transform: rotateY(264deg) translateZ(7rem);
}
.preloader__sector:nth-child(24) {
  transform: rotateY(276deg) translateZ(7rem);
}
.preloader__sector:nth-child(25) {
  transform: rotateY(288deg) translateZ(7rem);
}
.preloader__sector:nth-child(26) {
  transform: rotateY(300deg) translateZ(7rem);
}
.preloader__sector:nth-child(27) {
  transform: rotateY(312deg) translateZ(7rem);
}
.preloader__sector:nth-child(28) {
  transform: rotateY(324deg) translateZ(7rem);
}
.preloader__sector:nth-child(29) {
  transform: rotateY(336deg) translateZ(7rem);
}
.preloader__sector:nth-child(30) {
  transform: rotateY(348deg) translateZ(7rem);
}

/* Animations */
@keyframes tiltSpin {
  from {
    transform: rotateY(0) rotateX(30deg);
  }
  
  to {
    transform: rotateY(1turn) rotateX(30deg);
  }
}
@keyframes spin {
  from {
    transform: rotateY(0deg);
  }
  
  to {
    transform: rotateY(360deg);
  }
}
@keyframes reversespin {
  from {
    transform: rotateY(0deg);
  }
  
  to {
    transform: rotateY(-360deg);
  }
}

额外说明

  • 调整了body的样式,合并了原代码里重复的背景和字体设置,添加position:relative让.phone_static的绝对定位以body为基准。
  • 把.phone_static的left从70%改为50%,确保它完全居中在文字旋转环的中心。
  • 修正了reversespin动画里的无效值,将rotateY(deg)改为rotateY(0deg)。

内容的提问来源于stack exchange,提问作者Justin Clarke

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 01:03:13