CSS only 3D spinning text

Richard Parnaby-King picture Richard Parnaby-King · Jun 16, 2015 · Viewed 12.9k times · Source

I have a div with some text spinning. How do I get the text depth to give a better 3d effect? To clarify, at 90deg the text becomes 1px thick because we can only see it from the side - how do I make it, eg, 10px thick? Also, the appropriate amount of depth should be shown - i.e. at 0deg we don't see the depth; at 45deg we see 5px of depth; at 90deg we see the full 10px depth; etc.

I am after a CSS only solution.

Answer

tonystar picture tonystar · Jun 24, 2015

Simple text-shadow can do the trick:

body {
  perspective: 500px;
}
#spinner {
  text-align: center;
  animation-name: spin, depth;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
  animation-duration: 3s;
}
@keyframes spin {
  from { transform: rotateY(0deg); }
  to { transform: rotateY(-360deg); }
}
@keyframes depth {
  0% { text-shadow: 0 0 black; }
  25% { text-shadow: 1px 0 black, 2px 0 black, 3px 0 black, 4px 0 black, 5px 0 black; }
  50% { text-shadow: 0 0 black; }
  75% { text-shadow: -1px 0 black, -2px 0 black, -3px 0 black, -4px 0 black, -5px 0 black; }
  100% { text-shadow: 0 0 black; }
}
<p id="spinner">Stop, I'm getting dizzy!</p>

Another improvement could be to clone the text using ::before and ::after pseudo-classes:

body {
  perspective: 1000px;
}
#spinner {
  font-size: 50px;
  text-align: center;
  animation-name: spin, depth;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
  animation-duration: 3s;
  transform-style: preserve-3d;
  position: relative;
}
#spinner::before,
#spinner::after {
  content: "Stop, I'm getting dizzy!";
  display: block;
  position: absolute;
  width: 100%;
  height: 100%;
  top: 0;
  transform: rotateY(0.5deg);
  transform-origin: 0 50%;
}
#spinner::after {
  transform: rotateY(-0.5deg);
  transform-origin: 100% 50%;
}
@keyframes spin {
  from { transform: rotateY(0deg); }
  to { transform: rotateY(-360deg); }
}
@keyframes depth {
  0% { text-shadow: 0 0 black; }
  25% { text-shadow: 1px 0 black, 2px 0 black, 3px 0 black, 4px 0 black, 5px 0 black, 6px 0 black; }
  50% { text-shadow: 0 0 black; }
  75% { text-shadow: -1px 0 black, -2px 0 black, -3px 0 black, -4px 0 black, -5px 0 black, -6px 0 black; }
  100% { text-shadow: 0 0 black; }
}
<p id="spinner">Stop, I'm getting dizzy!</p>