I like the truth that CSS is lastly reclaiming management over visible interactions, taking cost of the styling, the animation, and the accessibility precisely because it ought to. As we speak, native browser capabilities permit us to maneuver the heavy lifting away from the JavaScript predominant thread and nearer to the GPU. By letting the browser’s engine optimize efficiency underneath the hood, we save vitality and processing energy whereas constructing code that’s sturdy, accessible, and impartial of exterior libraries which may deprecate tomorrow.
We now have 3D, trendy format strategies, clip-paths, transforms, customized properties, scroll-driven animations, view-transitions, @property — and we will animate nearly something, even to auto-height!
And, in fact, there’s SVG, which isn’t new, however permits us to construct complete web sites via illustrations and animations. Take the instance beneath: it’s responsive, light-weight, accessible, and powered primarily by CSS Grid + SVG.
We are able to even construct an complete online game together with the UI utilizing solely SVG:
What follows shouldn’t be a whole information to trendy CSS, however an opinionated choice of strategies I attain for after I need a website to really feel alive and be remembered. There are various methods to create memorable experiences. Typically it’s so simple as a kind that completes easily. However right here I’m within the expressive finish of the spectrum.
Movement as Communication: Defining Your Intent
Earlier than we dive into the technical aspect, I wish to make clear one thing: we shouldn’t transfer issues simply because we will.
Every little thing communicates, and our animations are not any exception. We should take the time to design actions that assist the message we wish to convey to be able to maintain our intents tightly scoped with out overdoing it.
Right here’s a technique I take advantage of when planning the design and animation of a website.
Think about we’re engaged on a venture for a nature occasion targeted on mushrooms. The design language modifications fully relying on the “vibe”: promoting a “Psychedelic Mushroom Rave” is worlds aside from a “Non secular Mushroom Retreat” targeted on ancestral drugs.
Each design choice communicates. I wish to create what I name key phrase lists to outline my intent and scope. For instance, I would break issues down into totally different choices:
Choice A: The Psychedelic Occasion
- Visuals: Colourful, saturated, high-contrast, illustrations, distortions
- Motion: Quick, frantic, unpredictable, morphing, rhythmic, synced loops, hypnotic
- Feeling: Enjoyable, chaotic, energetic, stimulating, shocking
- Typography: Funk, “psych-rock”
- Fashion References: Pop Artwork, 60s/70s op artwork, rave flyers
- Actions: Dancing
- Extras: Emojis, movies (e.g., Concern and Loathing in Las Vegas)
Choice B: The Non secular Retreat
- Visuals: Earth tones, impartial tones, de-saturated, photograph-heavy, nature, whitespace
- Motion: Gradual, fluid, natural, respiration, delicate parallax, easy scrolling.
- Feeling: Calm, serene, introspective, contemplative, protected
- Typography: Elegant Serif, minimalist sans-serif, large spacing, legible
- Fashion References: Scandinavian design, Japanese Wabi-sabi, wellness/spa aesthetics, botanical books
- Actions: Respiratory
- Extras: Therapeutic sounds, movie (e.g., Eat Pray Love)
That is the type of train I do to information my design and animation selections. The lists will assist me choose every little thing from which CSS properties I plan to make use of and the way to use them. I even share them with the shopper and, collectively, we select a path.
Let’s say we go along with Choice A and have a look at a couple of examples of what I feel are important elements for creating memorable consumer experiences.
Cut up Textual content Animations
These animations grew to become standard because of the GSAP SplitText plugin. It splits textual content by character (or phrases, or traces in the event you like) so we will create fascinating textual content results, like staggered animations.
This method wraps every letter in “Hola” in a span. From there, every span is inline-styled with a customized property indexing the spans so as. Which is one thing that may get rather a lot simpler when the sibling-index() perform beneficial properties broad browser assist.
However for now, every customized property worth acts as a multiplier that will increase an animation-delay, staggering every span. On this case we fade in every character because it strikes up.
.reveal-text span {
animation: slideUp 0.6s ease-out forwards;
animation-delay: calc(var(--i) * 0.1s);
show: inline-block;
opacity: 0;
remodel: translateY(3rem);
}
@keyframes slideUp {
to {
opacity: 1;
remodel: translateY(0);
}
}
Accessibility is the tough half right here. The intuition is to cover all the person spans from assistive expertise with aria-hidden="true" and add a visually hidden model of the total phrase for display readers:
.sr-only {
place: absolute;
width: 1px;
top: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
However be warned: this sample doesn’t assure a great expertise throughout all display readers. Adrian Roselli examined GSAP’s SplitText throughout eight display reader and browser mixtures and located it solely labored accurately in two of them. In case you ship this system, take a look at it with actual assistive expertise.
If that threat feels too excessive, there’s a really intelligent different from Preethi price realizing that makes use of the letter-spacing property. It accepts adverse values that collapse characters on prime of one another, hiding them with out touching the DOM in any respect. Animate it again to 0 and also you get an analogous reveal impact with out accessibility overhead.
What can be nice is a pseudo-selector like ::nth-letter to focus on particular person glyphs instantly from CSS the way in which ::first-letter selects the primary character. However sadly, there’s no ::nth-letter… at the least but.
Bear in mind to respect the consumer’s movement preferences on each animation:
@media (prefers-reduced-motion: scale back) {
.reveal-text span {
animation: none; /* or a softer animation */
}
}
And right here we go:
It won't scale an excessive amount of when we have now a number of textual content and totally different animations we wish to apply. For the psychedelic occasion, I wished to attempt splitting textual content with SMIL, however it was verbose. That is the code for animating two letters alone:
Add position="img" and a to the , and wrap the person letters in . That offers display readers one clear label to learn. It really works effectively in some mixtures and badly in others, so if the textual content is crucial, don’t animate it.
Right here is the whole code. It’s simpler to put in writing it when you have got an AI to do it for you:
For longer textual content, a library like GSAP provides you extra management, however the identical accessibility dangers we mentioned earlier apply, and the outcomes throughout display readers are inconsistent:
const splitFirst = SplitText.create('.splitfirst', {
kind: "chars",
});
const splitLast = SplitText.create('.splitlast', {
kind: "chars, traces",
masks: "traces"
});
const tween = gsap.timeline()
.from(splitFirst.chars, {
xPercent: 100,
stagger: 0.1,
opacity: 0,
period: 1,
})
.from(splitLast.chars, {
yPercent: 100,
stagger: 0.1,
opacity: 0,
period: 1,
});
This may be a pleasant method for Choice B if we had gone that route. See how “serene” issues really feel because the textual content fades in.
Masking & Clipping
The clip-path and masks properties permit us to cover parts of a component, however they work on essentially totally different rules. Clipping is a binary choice: pixels are both totally seen or fully gone, making it the best alternative for clear geometric shapes, like polygons, circles, or SVG paths, the place the browser may optimize rendering extra effectively. Masking, however, makes use of luminance or alpha channel values: white reveals, black hides, and every little thing in between produces partial transparency. This makes it the instrument for gentle edges, gradient fades, and irregular textures. Remember the fact that in case you have a really advanced vector form, it could be extra performant to make use of a masks than a vector clip-path. Sarah Drasner has a pleasant write-up on when it is sensible to make use of one over the opposite.
Our venture is a really clear use case for clip-path. We now have a circle form that begins with clip-path: circle(0%), which makes the aspect invisible (the clipping circle has zero radius). Over the period of the animation it expands to circle(100%), which totally reveals the aspect because the circle grows outward from its heart. In the meantime, we fade issues in with the assistance of opacity.
#rainbow, #ground, #mushroom, #flores {
opacity: 0;
animation: maskAnim 2s ease-in forwards;
}
@keyframes maskAnim {
0%, 1% {
clip-path: circle(0%);
opacity: 1;
}
100% {
clip-path: circle(100%);
opacity: 1;
}
}
Be aware: The 1% keyframe is there to verify the browser begins the clip-path interpolation from circle(0%) moderately than from no matter worth the aspect may have already got. With out it, some browsers will unexpectedly bounce on the very begin. A cleaner different is to make use of animation-fill-mode: each as a result of it locks the aspect in its from state earlier than the animation begins.
From there, we apply the identical animation to the totally different SVG teams in our illustration:
...
...
...
...
How psychedelic is that this?!
Scroll-driven animations are nice as a result of we will join an animation’s progress to the consumer’s scrolling as a substitute of a typical timeline that runs and stops.
We are able to use it for delicate and considerably “trippy” motion, like a light-weight parallax impact. On this case, we will make issues that seem nearer to the consumer transfer quicker than those which can be extra distant.
That is the total CSS:
#estrellas, #arcoiris, .text-line, #fecha, #arco, #flores, #dir, #piso, #barras {
animation: moveUp each;
animation-timeline: view();
}
@keyframes moveUp {
from { remodel: translateY(var(--offset)); opacity: 0; }
to { remodel: translateY(0); opacity: 1; }
}
#estrellas { --offset: 10vh; }
#arcoiris { --offset: 20vh; }
#fecha { --offset: 45vh; }
#arco { --offset: 50vh; }
#dir { --offset: 50vh; }
#flores { --offset: 65vh; }
#piso { --offset: 85vh; }
#barras { --offset: 90vh; }
The animation-timeline: view() says that issues ought to begin the animation as quickly as a component enters the scrollport when the consumer scrolls into it, and totally completes when it scrolls out of view. To make issues transfer at totally different velocities, we place them at totally different offsets utilizing an listed --offset customized property like we did earlier for splitting textual content.
3D Transforms
This one is trickier and we have to keep watch over efficiency. A instrument like Layoutit may help carry the carry as a result of it has a voxels and terrain generator constructed fully with CSS 3D. It will probably go even additional when it’s complemented with VoxCSS, a full voxel engine that renders 3D cuboids utilizing solely CSS Grid layers and transforms with out the complexity of Canvas or WebGL.
Let’s put collectively some mixture scrolling and 3D results. It’s the form of factor that helps the “hypnotic” and “dancing” concepts within the Choice A key phrase record. Verify this out:
Right here, I’ve arrange a scene with depth utilizing the perspective property after which wrap all of the little one parts contained in the scene in a 3D area with transform-style: preserve-3d. This fashion, all of the little one picture parts rotate and translate alongside the depth axis (or z-axis).
Let’s join that to a scroll-driven animation that makes use of remodel: rotateY:
.scene {
perspective: 1200px;
}
.img-wrapper {
transform-style: preserve-3d;
animation: rotateImg linear;
animation-timeline: scroll();
> img {
remodel: rotateY(270deg) translate3d(0, 50px, var(--distance));
}
> img:nth-child(2) {
remodel: rotateY(180deg) translate3d(0, 50px, var(--distance));
}
}
/* and so on. */
@keyframes rotateImg {
to { remodel: rotateY(360deg); }
}
Customized Cursors
cursor could be one of the unused CSS properties. There are many cursor varieties we will use, though there are undoubtedly opinions on simply how far to go along with this.
And we will use it to mess around with the photographs, displaying totally different cursors on totally different containers when the consumer hovers them. I might personally use an SVG and PNG picture for transparency assist, although the property helps any raster picture.
It’s price noting that cursor sizes differ by browser: Firefox caps customized cursors at 32×32px, whereas Chrome helps as much as 128×128px. Most browsers refuse to show — or will downscale — cursors which can be bigger than 32×32px on high-DPI (retina) screens. Preserving your cursor at 32×32px is the most secure alternative to make sure consistency.
For instance:
.box1 {
cursor: url(knowledge:picture/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB0AAAAZCAMAAAD63NUrAAAACVBMVEX///8AAAD///9+749PAAAAAXRSTlMAQObYZgAAAFZJREFUeNqdzksKwDAIAFHH+x+6lIYOVPOhs5OHJnES/5UkYKEkU7xjijSIm50iFh4fAXgYDd/yumVVRSwsqq/nRA3xVK0oo06d5U6DpQZ7PV7lMxH7LkaQAbYFwryzAAAAAElFTkSuQmCC),auto;
}
We are able to even set a number of fallbacks to make sure the widest degree of browser assist:
physique {
cursor: url('path-to-image.png'), url('path-to-image-2.svg'), url('path-to-image-3.jpeg'), auto;
}
Whereas that is cool and all, we have now to maintain accessibility in thoughts for one thing that modifications default internet conduct like this. Customized cursors might be enjoyable to use to very particular parts moderately than wholesale throughout the board.
Bonus: Anchor Positioning
Another factor earlier than we wrap up. I’ve been enjoying with CSS Anchor Positioning, impressed by a Kevin Powell demo. We are able to use it to connect a single pseudo-element to a currently-hovered merchandise as a substitute of attaching a pseudo-element for each merchandise. In different phrases, we create a single aspect and anchor it to a hovered aspect, like highlighting playing cards:
That opens up fascinating potentialities, like with the ability to transition the hover state between playing cards. On this case, I’m utilizing the linear() perform to get that pure bounce with assist from Easing Wizard.
Conclusion
The technical obstacles for creating memorable internet experiences are principally gone now. I hope every little thing we’ve lined right here provides you an thought of simply how far we will go along with trendy CSS options that fully take away the necessity for extra JavaScript. We now have extra potentialities than ever earlier than, all with out the necessity for advanced technical overhead like days previous.
So, as a substitute of asking, is that this potential?, an important query turns into, does this motion inform a greater story? If sure, ship it. Use these instruments not as a result of you possibly can, however as a result of they assist you inform a greater story, one which can be accessible and performant.
And, in fact, every little thing in right here is only a handful of how to do this. However what kind of memorable experiences have you ever utilized in your work? Or what have you ever seen on different websites?
