Within the earlier chapter, we constructed a primary 3D layered textual content impact utilizing nothing however HTML and CSS. It seems nice and has a strong visible presence, nevertheless it’s utterly static. That’s about to vary.
On this chapter, we’ll discover methods to animate the impact, add transitions, and play with totally different variations. We’ll have a look at how movement can improve depth, and the way delicate tweaks can create an entire new vibe.
3D Layered Textual content Article Collection
- The Fundamentals
- Movement and Variations (you’re right here!)
- Interactivity and Dynamism (coming August 22)
⚠️ Movement Warning: This text accommodates a number of animated examples that will embody flashing or fast-paced visuals. In case you are delicate to movement, please proceed with warning.
‘Counter’ Animation
Let’s begin issues off with a fast animation tip that pairs completely with layered 3D textual content. Generally, we need to rotate the factor with out really altering the orientation of the textual content so it stays readable. The trick right here is to mix a number of rotations throughout two axes. First, rotate the textual content on the z-axis. Then, add a tilt on the x-axis. Lastly, rotate the textual content again on the z-axis.
@keyframes wobble {
from { rework: rotate(0deg) rotateX(20deg) rotate(360deg); }
to { rework: rotate(360deg) rotateX(20deg) rotate(0deg); }
}
Since we rotate on the z-axis after which reverse that rotation, the textual content retains its unique orientation. However as a result of we add a tilt on the x-axis within the center, and the x-axis itself retains rotating, the angle of the lean modifications as nicely. This creates a sort of wobble impact that reveals off the textual content from each angle and emphasizes the sense of depth.
If we need to take this a number of steps additional, we will mix the wobble with a floating impact. We’ll animate the .layers
barely alongside the z-axis:
.layers {
animation: hover 2s infinite ease-in-out alternate;
}
@keyframes hover {
from { rework: translateZ(0.3em); }
to { rework: translateZ(0.6em); }
}
To actually promote the impact, we’ll depart the unique span in place — like a shadowed anchor — change its colour to clear, and animate the blur issue of its text-shadow
:
span {
colour: clear;
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; }
}
Syncing these two animations collectively offers the entire thing a extra practical really feel:
Splitting Letters
OK, that is beginning to look rather a lot higher now that issues are shifting. However the entire phrase remains to be shifting as one. Can we make every letter transfer independently? The reply, as ordinary, is “sure, however…”
It’s completely potential to separate every phrase right into a separate letters and animate them individually. But it surely additionally means much more parts shifting on the display, and that may result in efficiency points. In case you go this route, strive to not animate too many letters without delay, and contemplate lowering the variety of layers.
Within the subsequent instance, for example, I lowered the layer rely to sixteen. There are 5 letters, and to put them aspect by aspect, I gave the .scene
a show: flex
, then added a small delay to every letter utilizing :nth-child
:
New Angles
Till now, we now have solely been shifting the textual content alongside the z-axis, however we will positively take it additional. Every layer could be moved or rotated in any route you want, and if we base these transformations on the --n
variable, we will create all types of attention-grabbing results. Listed here are a number of I performed with, simply to present you some concepts.
Within the first one, I’m animating the translateX
to create a shifting impact:
Within the others, I’m including a little bit of rotation. The primary one is utilized to the y-axis for the sloping impact:
This subsequent instance applies rotation on the x-axis for the tilting:
And, lastly, we will apply it on the z-axis for a rotating instance:
Layer Delay
Working with separate layers doesn’t simply allow us to tweak the animation for every one; it additionally lets us alter the animation-delay
for each layer individually, which may result in some actually attention-grabbing results. Allow us to take this pulsing instance:
Proper now, the animation is utilized to the .layeredText
factor itself, and I’m merely altering its scale:
.layeredText {
animation: pulsing 2s infinite ease-out;
}
@keyframes pulsing {
0%, 100% { scale: 1; }
20% { scale: 1.2; }
}
However we will apply the animation to every layer individually and provides every one a slight delay. Be aware that the span
is a part of the stack. It’s a layer, too, and generally you’ll want to embody it within the animation:
.layer {
--delay: calc(var(--n) * 0.3s);
}
:is(span, .layer) {
animation: pulsing 2s var(--delay, 0s) infinite ease-out;
}
Right here I’m utilizing the :is
selector to focus on each the person layers and the span
itself with the identical animation. The result’s a way more vigorous and fascinating impact:
Pseudo Decorations
Within the earlier chapter, I discussed that I normally choose to avoid wasting pseudo parts for ornamental functions. That is positively a way value utilizing. We can provide every layer one or two pseudo parts, add some content material, place them nonetheless we like, and the 3D impact will already be there.
It may be something from easy outlines to extra playful shapes. Like arrows, for instance:
Discover that I’m utilizing the :is
selector to incorporate the span
right here, too, however generally we won’t need to goal all of the layers — solely a particular portion of them. In that case, we will use :nth-child
to pick out simply a part of the stack. For instance, if I need to goal solely the underside twelve layers (out of twenty 4 complete), the ornament solely covers half the peak of the textual content. I can do one thing like :nth-child(-n + 12)
, and the total selector could be:
:is(span, .layer:nth-child(-n + 12))::earlier than {
/* pseudo model */
}
That is particularly helpful when the ornament overlaps with the textual content, and you do not need to cowl it or make it onerous to learn.
After all, you may animate these pseudo parts too. So how a couple of 3D “Loading” textual content with a built-in spinner?
I made a number of modifications to tug this off. First, I chosen twelve layers from the center of the stack utilizing a barely extra superior selector: .layer:nth-child(n + 6):nth-child(-n + 18)
. This targets the layers from quantity six to eighteen.
Second, to pretend the shadow, I added a blur filter to the span
‘s pseudo factor. This creates a pleasant mushy impact, however it may possibly trigger efficiency points in some instances, so use it with care.
:is(span, .layer:nth-child(n + 6):nth-child(-n + 18))::earlier than {
/* spinner model */
}
span {
/* span model */
&::earlier than {
filter: blur(0.1em);
}
}
Face Portray
However you don’t have to make use of pseudo parts so as to add some visible curiosity. You can even model any textual content with a customized sample utilizing background-image
. Simply choose the highest layer with the :last-child
selector, set its textual content colour to clear
so the background reveals by way of, and use background-clip: textual content
.
.layer {
/* layer model */
&:last-child {
colour: clear;
background-clip: textual content;
background-image: ... /* use your creativeness */
}
}
Here’s a small demo utilizing striped traces with repeating-linear-gradient
, and rings made with repeating-radial-gradient
:
And, sure, you may completely use an picture too:
Animating Patterns
Allow us to take the earlier thought a few steps additional. As a substitute of making use of a sample simply to the highest layer, we’ll apply it to all of the layers, making a full 3D sample impact. Then we’ll animate it.
We’ll begin with the colours. First, we give all of the layers a clear
textual content colour. The colour we used earlier than will now be saved in a customized property known as --color
, which we’ll use in only a second.
.layer {
--n: calc(var(--i) / var(--layers-count));
--color: hsl(200 30% calc(var(--n) * 100%));
colour: clear;
}
Now let’s outline the background, and we’ll say we would like a shifting checkerboard sample. We will create it utilizing repeating-conic-gradient
with two colours. The primary can be our --color
variable, and the second may very well be clear
. However on this case, I believe black with very low opacity works higher.
We simply must set the background-size
to regulate the sample scale, and naturally, be certain to use background-clip: textual content
right here too:
.layer {
--n: calc(var(--i) / var(--layers-count));
--color: hsl(200 30% calc(var(--n) * 100%));
colour: clear;
background-image:
repeating-conic-gradient(var(--color) 0 90deg, hsl(0 0% 0% / 5%) 0 180deg);
background-size: 0.2em 0.2em;
background-clip: textual content;
rework: translateZ(calc(var(--i) * var(--layer-offset)));
animation: checkers 24s infinite linear;
}
@keyframes checkers {
to { background-position: 1em 0.4em; }
}
As you may see, I’ve already added the animation
property. On this case, it is rather easy to animate the sample. Simply slowly transfer the background-position
, and that’s it. Now we now have textual content with a shifting 3D sample:
Variable Fonts
Up to now, we now have been utilizing a single font, and as I discussed earlier, font selection is usually a matter of style or model pointers. However since we’re already working with layered textual content, we completely must strive it with variable fonts. The concept behind variable fonts is that every one consists of axes you may manipulate to vary its look. These can embody width, weight, slant, or absolutely anything else.
Listed here are a number of examples I actually like. The primary one makes use of the Local weather Disaster font, which has a YEAR
axis that ranges from 1979 to 2025. With annually, the letters soften barely and shrink a bit. It’s a highly effective ecological assertion, and while you stack the textual content in layers, you may really see the modifications and get a reasonably putting 3D impact:
One other nice choice is Bitcount, a variable font with a traditional weight axis starting from 100 to 900. By altering the burden based mostly on the layer index, you get a layered impact that appears like peaks rising throughout the textual content:
And right here is an instance which may give your browser a little bit of a exercise. The font Kablammo features a MORF
axis, and adjusting it utterly modifications the form of every letter. So, I figured it will be enjoyable to animate that axis (sure, font-variation-settings
is animatable), and add a brief delay between the layers, like we noticed earlier, to present the animation a extra dynamic and vigorous really feel.
Delayed Place
Earlier than we wrap up this second chapter, I need to present you another animation. By now you will have most likely observed that there’s all the time a couple of method to do issues, and generally it’s only a matter of discovering the suitable strategy. Even the positioning of the layers, which we now have been dealing with statically with translateZ
, could be finished a little bit in another way.
If we animate the layers to maneuver alongside the z-axis, from zero to the total top of the textual content, and add an equal delay between every one, we find yourself with the identical visible 3D impact, solely in movement.
.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 { rework: translateZ(0); }
to { rework: translateZ(calc(var(--layers-count) * var(--layer-offset))); }
}
It is a extra superior approach, fitted to extra complicated animations. It’s not one thing you want for each use case, however for sure results, it may possibly look very cool.
Wrapping Up
Up to now, we now have introduced the layered textual content impact to life with motion, variation, and inventive styling. We additionally noticed how even small modifications can have an enormous visible influence when utilized throughout layers.
However every little thing we now have finished to date has been pre outlined and self contained. Within the subsequent chapter, we’re going to add a layer of interactivity. Actually. From easy :hover
transitions to utilizing JavaScript to trace the mouse place, we’ll apply real-time transformations and construct a totally responsive bulging impact.
3D Layered Textual content Article Collection
- The Fundamentals
- Movement and Variations (you’re right here!)
- Interactivity and Dynamism (coming August 22)