DEV Community 👩‍💻👨‍💻

Cover image for Build a CSS Transition Tool for your editors
Mads Stoumann
Mads Stoumann

Posted on

Build a CSS Transition Tool for your editors

I love building small tools to help editors and marketeers create more engaging content.

Typically, these tools are super-simple. Often, it's just updating a few CSS Custom Properties, a list of class-names, data-attributes or similar.

I recently build a CSS Transition Tool, so editors can fine-tune how an element, or group of elements, enters the screen when scrolling.

A typical example of this is fade up:

Fade up

The tool also allows editors to fine-control the transition of each element in the group:

Zoom in/out

If you want to build a similar tool, read on.


Creating the CSS

First things first. The tool needs a lot of CSS-classes, that'll control the individual transform-properties. To run the transitions (on scroll, using intersection observer), we'll just add a trs-class to the outermost (parent) element.

We'll be using easings from Open Props, so let's start, by importing those:

@import 'https://unpkg.com/open-props@1.4.14/src/props.easing.css';
Enter fullscreen mode Exit fullscreen mode

Next, we need some variables:

:where([class*="trs-"]) {
  --dg: 100deg;
  --tx: 55px;
  --ty: 110px;
  --zi: 0.6;
  --zo: 1.2;
}
Enter fullscreen mode Exit fullscreen mode

--dg is for transitions with degrees, --tx is x-offset, --ty is y-offset, and zi and zois used for zoom-transitions.

For the transition-classes, we'll use all of these properties, example "fade-down":

.trs-fdd { opacity: 0; transform: translate3d(0px, calc(-1 * var(--ty)), 0); }
Enter fullscreen mode Exit fullscreen mode

... or "flip-down":

.trs-fld { backface-visibility: hidden; transform: perspective(2500px) rotateX(var(--dg)); }
Enter fullscreen mode Exit fullscreen mode

For delays, durations and easings, we'll add a bunch of micro-classes:

.trsde-25 { --delay: 25ms; }
.trsde-50 { --delay: 50ms; }
/* .etc */
Enter fullscreen mode Exit fullscreen mode

When one of the transition-classes has the trs-class, we'll run a transition:

:is([class*="trs-"].trs) {
  opacity: 1;
  transform: translateZ(0) scale(1);
  transition: all var(--duration, 400ms) var(--delay, 0ms) var(--easing, var(--ease-1, ease));
}
Enter fullscreen mode Exit fullscreen mode

For any child-element within a trs-class, we'll use:

:is(.trs [class*="trs-"]) {
  opacity: 1;
  transform: translateZ(0);
  transition-timing-function: var(--easing, ease-in-out);
  transition-delay: var(--delay, 0ms);
  transition-duration: var(--duration, 400ms);
}
Enter fullscreen mode Exit fullscreen mode

You can see all the necessary styles in the demo at the end of this tutorial.


HTML

Now for some simple markup for previewing the transitions:

<div id="demo">
  <div id="demo1">
    <img src="image1.jpg" />
  </div>
  <div id="demo2">
    <img src="image2.jpg" />
  </div>
  <div id="demo3">
    <img src="image3.jpg" />
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

For all the properties we want the editors to play around with, we'll add a <select>, with the CSS class-names as <option value>.

Example:

<select>
  <option value="trsde-0" selected>0ms</option>
  <option value="trsde-25">25ms</option>
  <option value="trsde-50">50ms</option>
  ...
</select>
Enter fullscreen mode Exit fullscreen mode

We'll group the <select>-elements in <fieldset>s, one for each child-element in the preview-markup:

<fieldset name="demo"> ...
Enter fullscreen mode Exit fullscreen mode

Notice the name="demo"-part. We'll use that in JavaScript, so all the controls within this fieldset will target the element in the preview-markup with id="demo".

Finally, wrap all the editor-markup within a <form id="app">.


JavaScript

Since we have a <form>, we just need a single input-event:

app.addEventListener('input', event => {
  const node = event.target;
  const group = node.closest('fieldset');
  document.getElementById(group.name).className = [...group.elements].map(input => input.value).join(' ').replace(/  +/g, ' ');
  playIt();
})
Enter fullscreen mode Exit fullscreen mode

All there's left to add, is the code for playIt, a simple method that removes the trs-class, and adds it again after a timeout:

const playIt = () => { demo.classList.remove('trs'); setTimeout(() => { demo.classList.add('trs'); }, 400); }
Enter fullscreen mode Exit fullscreen mode

To help our editors re-trigger the animation, let's add a <button id="play">, that'll also run playIt()

play.addEventListener('click', () => playIt());
Enter fullscreen mode Exit fullscreen mode

And that's it. Very little code, but a great help for editors and marketeers!


Demo

Here's the demo. I recommend you click on "Edit on Codepen", and then choose "Full Screen View":

As soon as you change something in the editor, click on the "See code".

Example:

Code snippet

Here, you can see, that some of the classes we created in the beginning of this tutorial, has been added to the main wrapper.

Now, change the transitions of one or more of the child-elements, and see the code update.


Feel free to implement the editor in a CMS — or have the editors copy the code-snippet, if you want to implement the transitions manually.

Most of the transitions are inspired by AOS.

Top comments (0)

Need a better mental model for async/await?

Check out this classic DEV post on the subject.

⭐️🎀 JavaScript Visualized: Promises & Async/Await

async await