3D Layered text: Movement and variations CSS tricks

3D Layered text: Movement and variations CSS tricks

9 minutes, 53 seconds Read

In the previous chapter we have built a simple 3D layered text effect with nothing but HTML and CSS. It looks great and has a solid visual presence, but it is completely static. That will change.

In this chapter we will investigate ways to animate, add transitions and play with different variations. We will see how movement can improve the depth and how subtle tweaks can create a completely new atmosphere.

3D Layered text articles series

  1. Base
  2. Motion and variations ((you are here!)
  3. Interactivity and dynamics (next August 22)

⚠️ Motion warning: This article contains several animated examples that can include flashy or fast -moving visuals. If you are sensitive to movement, go with caution.

‘Counter’ animation

Let’s start with a fast animation tip that perfectly combines with layered 3D text. Sometimes we want to rotate the element without changing the orientation of the text so that it remains readable. The trick here is to combine several rotations over two axes. First turn the text on the Z-axis. Then add a tilt to the X-axis. Finally, turn the text back on the Z-axis.

@keyframes wobble {
  from { transform: rotate(0deg) rotateX(20deg) rotate(360deg); }
  to { transform: rotate(360deg) rotateX(20deg) rotate(0deg); }
}

Because we turn on the Z-axis and then reverse that rotation, the text retains its original orientation. But because we add a tilt on the X-axis in the middle and keeps rotating the X-axis itself, the angle of the tilt changes. This creates a kind of wobble Effect that the text shows from every corner and emphasizes the feeling of depth.

If we want to take this a few more steps, we can combine the Wiebel with a floating effect. We’ll be the .layers Something along the Z-axis:

.layers {
  animation: hover 2s infinite ease-in-out alternate;
}

@keyframes hover {
  from { transform: translateZ(0.3em); }
  to { transform: translateZ(0.6em); }
}

In order to really sell the effect, we will let the original span in place – as a shady anchor – change color in transparent and animate the degradation factor of his text-shadow:

span {
  color: transparent;
  animation: shadow 2s infinite ease-in-out alternate;
}

@keyframes shadow {
  from { text-shadow: 0 0 0.1em #000; }
  to { text-shadow: 0 0 0.2em #000; }
}

Synchronizing those two animations together gives the whole thing a more realistic feeling:

Split

Ok, this starts to look a lot better now that things are moving. But the whole word still moves like one. Can we make every letter move independently? The answer, as usual, is “yes, but …”

It is absolutely possible to split each word into a separate letters and to animate separately. But it also means many more elements that go on the screen, and that can lead to performance problems. If you go this route, don’t try to animate too many letters in one go and consider reducing the number of layers.

In the following example, for example, I reduced the number of layers to sixteen. There are five letters, and to place them next to each other, I gave the .scene A display: flexthen added a small delay to each letter using :nth-child:

New corners

So far we have only moved the text along the Z-axis, but we can certainly continue. Each layer can be moved or turned in any direction you want, and if we base those transformations on the --n We can create all kinds of interesting effects variable. Here there are a few with which I played, just to give you some ideas.

In the first I animer the translateX To one shifting effect:

In the others I add a little rotation. The first is applied to the Y-axis for the rolling effect:

This following example applies rotation to the X-axis for the tilt:

And finally we can apply it to the Z-axis for one rotively Example:

Low -delay

By working with individual layers, we do not only leave the animation for each adjustment; It can also us the animation-delay For each layer individually, which can lead to some really interesting effects. Let’s take this pulsating Example:

The animation is currently being applied to the .layeredText Element itself, and I just change his scale:

.layeredText {
  animation: pulsing 2s infinite ease-out;
}

@keyframes pulsing {
  0%, 100% { scale: 1; }
  20% { scale: 1.2; }
}

But we can apply the animation separately on each layer and each give a small delay. Note that the span is part of the stack. It is also a low, and sometimes you want to include it in the animation:

.layer {
  --delay: calc(var(--n) * 0.3s);
}

:is(span, .layer) {
  animation: pulsing 2s var(--delay, 0s) infinite ease-out;
}

Here I use the :is selector to both the individual layers and the span itself with the same animation. The result is a much livelier and fascinating effect:

Pseudo -decorations

In the previous chapter I said that I usually prefer to save pseudo elements for decorative purposes. This is definitely a technique that is worth using. We can give each layer one or two pseudo elements, add some content, position them as we like, and the 3D effect will already be there.

It can be anything from simple contours to more playful forms. Pretend arrowFor example:

Note that I am the :is Selector to the span Here too, but sometimes we don’t want to focus all layers – just a specific part of it. In that case we can use :nth-child To only select part of the stack. For example, if I only want to target the lower twelve layers (of the twenty -four in total), the decoration includes only half the height of the text. I can do something like that :nth-child(-n + 12) And the full selector would be:

:is(span, .layer:nth-child(-n + 12))::before {
  /* pseudo style */
}

This is especially useful when the decoration overlaps with the text, and you do not want to cover it or make it difficult to read.

Of course you can also animate this pseudo elements. So how about a 3D “Load“Text with a built -in spinner?

I have made a few changes to get this done. First I selected twelve layers from the center of the stack with the help of a slightly more advanced selector: .layer:nth-child(n + 6):nth-child(-n + 18). This focuses on the layers of number six to eighteen.

Secondly, to falsify the shadow, I added a blurring filter to the span‘s Pseudo element. This creates a nice soft effect, but in some cases it can cause performance problems, so use it with care.

:is(span, .layer:nth-child(n + 6):nth-child(-n + 18))::before {
  /* spinner style */
}

span {
  /* span style */

  &::before {
    filter: blur(0.1em);
  }
}

Make -up

But you don’t have to use pseudo elements to add some visual interest. You can also style any text with an adapted pattern using background-image. Just select the top layer with the :last-child selector, set the text color to transparent So the background shows and use background-clip: text.

.layer {
  /* layer style */
    
  &:last-child {
    color: transparent;
    background-clip: text;
    background-image: ... /* use your imagination */
  }
}

Here is a small demo with striped lines of repeating-linear-gradientAnd rings made with repeating-radial-gradient:

And yes, you can definitely be one image at:

Animating patterns

Let’s take the previous idea a few steps further. Instead of applying a pattern to the top layer, we will apply it on all layers, creating a full 3D pattern effect. Then we will animate it.

We start with the colors. First, we give all layers one transparent Text color. The color we have used before is now stored in an adapted feature called --colorwhich we will use in just one moment.

.layer {
  --n: calc(var(--i) / var(--layers-count));
  --color: hsl(200 30% calc(var(--n) * 100%));

  color: transparent;
}

Now let’s define the background, and we will say we want a move chessboard cartridge. We can make it with the help of repeating-conic-gradient With two colors. The first will be our --color variable, and the second could be transparent. But in this case I think that black works better with very low coverage.

We just have to background-size To arrange the pattern scale, and of course make sure you apply background-clip: text Also here:

.layer {
  --n: calc(var(--i) / var(--layers-count));
  --color: hsl(200 30% calc(var(--n) * 100%));

  color: transparent;
  background-image:
    repeating-conic-gradient(var(--color) 0 90deg, hsl(0 0% 0% / 5%) 0 180deg);
  background-size: 0.2em 0.2em;
  background-clip: text;
  transform: translateZ(calc(var(--i) * var(--layer-offset)));
  animation: checkers 24s infinite linear;
}

@keyframes checkers {
  to { background-position: 1em 0.4em; }
}

As you can see, I have the animation property. In this case it is very easy to animate the pattern. Just move the background-positionAnd that’s it. Now we have text with a moving 3D pattern:

Variable fonts

So far we have used a single font, and as I said before, the letter choice is usually a matter of taste or brand guidelines. But because we already work with layered text, we absolutely have to try it with variable fonts. The idea behind variable fonts is that each axes contains that you can manipulate to change the appearance. These can include width, weight, impact or just about everything.

Here are a few examples that I really like. The first uses the Climate crisis font, that one YEAR Axis that varies from 1979 to 2025. With every year the letters melt somewhat and shrink a little. It is a powerful ecological explanation, and when you stack the text in layers, you can actually see the changes and get a pretty striking 3D effect:

Another great option is BitcountA variable font with a traditional weight axis ranging from 100 to 900. By changing the weight based on the layer index, you get a layered effect that looks like peaks that rise over the text:

And here is an example that your browser can give a bit of a training. The font Kablammo Includes one MORF Axis, and adjusting it changes completely the shape of each letter. So I thought it would be nice to animate that ashes (yes, font-variation-settings Is animated), and add a short delay between the layers, as we saw earlier, to give the animation a more dynamic and lively feeling.

Delayed position

Before we complete this second chapter, I want to show you an animation. In the meantime you have probably noticed that there is always more than one way to do things, and sometimes it is just a matter of finding the right approach. Even the positioning of the layers, with which we have been statically dealt with translateZCan be done a little differently.

If we animate the layers to move along the Z-axis, from zero to the full height of the text, and an equal delay between each add, we end up with the same visual 3D effect, only in motion.

.layer {
  --n: calc(var(--i) / var(--layers-count));
  --delay: calc(var(--n) * -3s);

  animation: layer 3s var(--delay) infinite ease-in-out;
}

@keyframes layer {
  from { transform: translateZ(0); }
  to { transform: translateZ(calc(var(--layers-count) * var(--layer-offset))); }
}

This is a more advanced technique, suitable for more complex animations. It is not something you need for every use case, but for certain effects it can look very cool.

Shutdown

So far we have brought the layered text effect to life with movement, variation and creative styling. We have also seen how even small changes can have a huge visual impact when they are applied over layers.

But everything we have done so far is defined and independent in advance. In the next chapter we will add a low interactivity. Literal. From simple :hover Transitions to the use of JavaScript to follow the mous position, we will apply real -time transformations and build a fully responsive bulging effect.

3D Layered text articles series

  1. Base
  2. Motion and variations ((you are here!)
  3. Interactivity and dynamics (next August 22)

#Layered #text #Movement #variations #CSS #tricks

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *