pwshub.com

Simplifying CSS animations with the display and size properties

Until recently, only a limited number of CSS properties could be animated. For example, to create a fade-in or fade-out effect, you would typically use the opacity property instead of the display property, as the latter could not be animated. The issue, however, is that while the element becomes visually hidden, it’s still present on the page.

Simplifying CSS Animations With The `Display` And `Size` Properties

Recently, Chrome introduced new features that resolve this issue and make the development process much simpler. In this article, we’ll compare the traditional methods for animating the display and size properties with these new features.

The problem with animating display and element size

Chances are, you’ve had to create a fade-in/out effect on some element using CSS at some point. The go-to method is to apply an animation or transition to the element’s opacity. But setting the opacity to zero doesn’t actually remove the element — it just makes it invisible. Most of the time, that’s good enough.

But let’s say you’ve got a to-do list where users can delete items. If you want to create an exit animation such that the item fades out, you would normally use opacity. But if the list needs to adjust its height, you’d also need to set the display to none. The issue here is that while the item is visually gone, it still takes up space in the DOM and messes with things like layout and user interactions.

Here’s a side-by-side comparison of two approaches: one using just opacity, and the other combining opacity with display. You can try the example below to see the differences:

See the Pen
Simple Todo App Comparision
by Saleh-Mubashar (@saleh-mubashar)
on CodePen.

Notice how the layout shifts when combining display with opacity, while using opacity alone leaves gaps in the list. While the second method (opacity + display) solves the layout issue, it interferes with the smooth fade-out effect because display: none is applied before the fade finishes. This causes a sudden disappearance rather than a gradual fade.

For example, the opacity property can transition smoothly from 0 to 1. However, the display property cannot be animated because it doesn’t have a numeric range — its states are binary, like none, block, or other values. Because there’s no in-between value, CSS can’t animate the display.

Similarly, developers often face challenges when trying to animate the intrinsic size of an element, such as height: auto. This is commonly used for transitions on collapsible sections like accordions, where the height starts at 0px when closed and expands to fit the content when opened. Although size properties like height can typically be animated (because they have numeric start and end values), animating to or from auto creates issues. The browser can’t calculate the steps between 0px and auto; thereby complex workarounds must be used.

The traditional solutions for animating display and size

There are several ways to address the challenges of animating display and element sizes. In this section, we’ll discuss the most popular solutions using both CSS and JavaScript.

CSS-based solutions

There are a couple of ways to solve the issue of the display property not being animatable using CSS. The most reliable one is using opacity along with a size property such as height or width. In this case, the size property is used to effectively remove the element from the DOM. This can be done using the transition-delay property. Basically, we add a delay to the size transition, which is equal to the time set for the opacity transition. Once the element fades out, its size is immediately set to zero, effectively removing it from the layout as if display: none had been applied.

Using the to-do list as an example again, the implementation would look somewhat like this:

li {
  height: 50px; /* any measurable value, not "auto" */
  opacity: 1;
  transition: height 0ms 0ms, opacity 400ms 0ms;
}
.fade-out {
  overflow: hidden; /* Hide the element content, while height = 0 */
  height: 0;
  opacity: 0;
  padding: 0;
  transition: height 0ms 400ms, padding 0ms 400ms, opacity 400ms 0ms;
}

Here, the trick is setting the height and padding to 0 after a delay once the opacity fades to 0. The delay and length of the opacity need to be the same — in this case, 400ms. The height: 0 makes sure that the list item does not interact with the layout. As discussed earlier, height: auto adjusts dynamically based on content; hence, it cannot be animated. Therefore, you need to ensure that the element has a specific, fixed height for the animation to work properly.

Setting the visibility to hidden is another commonly used method. However, this does not remove the element from the DOM, and it still affects the layout as normal, i.e., it influences the positioning of surrounding elements.

The most common CSS solution for animating an element to or from its intrinsic size (or height: auto) is to use max-height instead of height. It’s not the cleanest implementation, but it gets the job done. You basically set the max-height to a value larger than the element will ever get. This way, it mimics a smooth transition, similar to animating a fixed height:

.collapsible {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.4s ease;
}
.collapsible.open {
  max-height: 500px;
} 

The most obvious downside to this approach is that you have to make sure the max-height is always larger than the actual content inside the element. Another issue is that the transition timing can feel inaccurate unless the content height perfectly matches the max-height value.

Let’s say that your content is 400px high but you set the max-height to 1000px. The animation will technically continue for the entire duration (let’s say two seconds). But visually, the element will stop growing as soon as it reaches the actual height of the content (400px), while the max-height keeps transitioning to 1000px. So, in this case, the transition duration will be shorter than the one you specify.

JavaScript methods

All the CSS solutions discussed above are quite complex and can lead to unpredictable results. Until recently, the most reliable way to achieve this was through JavaScript.

To apply display none after an opacity transition, we can use either the setInterval or setTimeout function to add a delay that matches the opacity transition duration. After this delay, you can set the display to none. Here’s an example:

document.getElementById("fadeButton").addEventListener("click", function () {
  const element = document.getElementById("myElement");
  element.style.opacity = "0";
  setTimeout(() => {
    element.style.display = "none";
  }, 1000); // Match this value with the duration in CSS
});

In this code, after the button is clicked, the element fades out over one second, and then its display is set to none immediately — essentially removing it from the layout.

Similarly, to animate the intrinsic size, we can calculate the height of the element in JavaScript and use that value as an endpoint for the height. This approach is much more reliable and precise. However, keep in mind that we are still animating on the height property.

The obvious benefit here is that you’re dynamically setting the height based on the element’s actual content, ensuring the transition matches the real height rather than guessing with max-height.

Here’s how you can do it:

document.getElementById("toggleButton").addEventListener("click", function () {
  const el = document.querySelector(".expandable");
  const contentHeight = el.scrollHeight;
  el.style.height = contentHeight + "px";
  el.addEventListener("transitionend", function (e) {
    el.removeEventListener("transitionend", arguments.callee);
    el.style.height = "auto";
  });
});

In this example, we’re expanding a section that starts with a height of 0. We use scrollHeight to grab the full height of the content and use that as an endpoint for the transition. After the transition completes, we switch the height to auto, which allows the browser to automatically adjust the container’s height based on its content. This step is optional, but it’s useful if you expect the content inside the container to change over time.

New CSS features for animating display and intrinsic size properties

Now let’s look at the new CSS features that have recently arrived or are on their way to browsers. These new tools eliminate the need for JavaScript in the scenarios we discussed earlier and help you write cleaner, shorter CSS.

Display and keyframes

The @keyframes at-rule lets you create animations by controlling the intermediate steps in an animation sequence. The latest update allows you to animate the display and content-visibility properties within a keyframe timeline.

We are not exactly interpolating between display none and block (because that’s not possible). Instead, we wait for all the other effects to complete and then switch the display state. This is similar to what we did with JavaScript — waiting for the transition to finish before applying display: none — but now it’s much easier with CSS.

The Chrome Dev Blog has a really cool demo that makes things clear:

See the Pen
Fade out cards – Animation
by web.dev (@web-dot-dev)
on CodePen.

First, the opacity is set to 0 over 250ms. Once this sequence is complete, the display is immediately set to none:

.fade-out {
  animation: fade-out 0.25s forwards;
}
/* Keyframe animations */
@keyframes fade-out {
  100% {
    opacity: 0;
    display: none;
  }
}

The biggest win here is that more complex animations involving the display property, which were until recently super hard to implement using CSS (or JavaScript), can now be created relatively easily.

How transition-behavior simplifies display transitions

The fade-out effect can also now be created with a transition using the new transition-behavior property. This lets you apply transitions to properties that have a discrete animation behavior, like display. By using allow-discrete, you can animate the display property. Here’s a quick example:

.card {
  transition: opacity 0.5s, display 0.5s;
  transition-behavior: allow-discrete; /* this is essential */
}
.card.fade-out {
  opacity: 0;
  display: none;
}

Entry animations with @starting-style

We have discussed the fade-out effect quite extensively in this article. But what about the opposite case? Entry animations are tricky and often only possible through JavaScript. The new @starting-style at-rule makes things much easier.

As the name suggests, we can use it to apply a style to an element that the browser can look up before the element is visible on the page. We can set the initial state of an entry animation here. Once the element renders, it transitions back to its default state.

Here’s a basic example:

.card {
  @starting-style {
    opacity: 0;
  }
  opacity: 1;
  transition: opacity 0.5s;
}

The card will fade in once the DOM loads. You can use @starting-style for all kinds of entry animations. Here’s another awesome example from the Chrome Dev team:

See the Pen
Item transitions
by web.dev (@web-dot-dev)
on CodePen.

Animating intrinsic sizes with the calc-size() function

The calc-size function, similar to calc(), was recently introduced in Chrome 129. In simple words, it allows math to be performed on intrinsic sizes safely and reliably way. It currently supports operations of four keywords: auto, min-content, max-content, and fit-content. This is especially useful for animating elements to and from their intrinsic size.

calc-size allows for animating any height that can currently be specified in CSS to zero or to/from a small fixed value. Here’s a simple example of expanding a collapsible section from height: 0 to auto:

.card { 
  height: 0; 
}
.card.open { 
  height: calc-size(auto);
}

Browser compatibility

Most of these features are primarily for enhancing animations and not essential DOM components, but because they are relatively new, it’s still worth checking browser compatibility:

  • The display property is @keyframe animatable in Chrome 116+ and Opera 102+. Firefox support is still in development, and Safari is working on it
  • The transition-behavior property was released first in Chrome 117. It is compatible with all major browsers except Firefox, where it is currently in development
  • The @starting-style at-rule was introduced in Chrome 117. It is fully supported on all major browsers besides Firefox, where it does not yet support animating from display: none
  • calc-size() is the latest feature, introduced in Chrome 129, and is currently only supported in Chrome and Edge. However, other major browsers will soon support it

Conclusion

In this article, we explored the challenges developers face when animating CSS properties like display and element sizes. Traditional methods required complex workarounds with CSS and JavaScript to achieve animations for properties that can’t be animated directly.

New features, such as animating display with keyframes, the calc-size() function, and the transition-behavior property, make these animations easier to achieve. These functions eliminate the need for JavaScript, allowing for simpler CSS animations.

Source: blog.logrocket.com

Related stories
3 days ago - Piecesjs is a lightweight JavaScript framework built upon native web components, offering a suite of tools and utilities tailored for creative websites.
1 month ago - Astro, renowned for its developer-friendly experience and focus on performance, has recently released a new version, 4.10. This version introduces […] The post Understanding env variables and containers in Astro 4.10 appeared first on...
1 month ago - Next allows you to do server-side data-fetching, but what happens when that data needs to change on the client? This brief tutorial shows how to re-fetch the props without doing a full server reload.
2 weeks ago - Our next major version of Deno combines the simplicity, security, and performance of Deno 1 with full Node and npm backwards compatibility, and much more.
1 week ago - Deep link generators guide to enhance user engagement, manage affiliate links, track marketing links and boost conversions. The post Best Deep Link Generators to Drive Higher Conversions appeared first on Geekflare.
Other stories
26 minutes ago - Are you ready to dive into the world of full-stack web development and AI-powered applications? This comprehensive tutorial takes you through the exciting process of building and deploying an intelligent, fully-featured email client from...
26 minutes ago - We've just released a comprehensive course on the freeCodeCamp.org YouTube channel to help you prepare for the Google Cloud Digital Leader certification exam – and it's completely free. This in-depth course, created by cloud expert Andrew...
26 minutes ago - Ethical hacking involves testing and finding vulnerabilities in systems. But doing this on live networks or public servers can lead to accidental damage. Setting up a virtual lab for hacking is a great way to sharpen your skills in a safe...
26 minutes ago - The SOLID Principles are five software design principles that help you to write high quality, flexible, maintainable, reusable, testable, and readable software. If you plan to work with object-oriented software, it is crucial to...
26 minutes ago - CRUD operations are the basis of every application, so it is essential to become proficient in them when learning new technologies. In this tutorial, you’ll learn how to build a CRUD application using React and Convex. We’ll cover these...