By now, one would think there would be an easier way to transition between the visibility of an object on a page with all of the CSS and SASS tricks at the ready. Unfortunately, it is a bit frustrating to navigate this area. Between visibility and display, there is not one perfect way to transition an element smoothly without JavaScript. When and where the element is able to simply fade out a container to show another below can be tricky especially if elements should no longer be truly displayed for screen readers, selecting elements, and accidental invisible button clicks. First I will walk us through the three ways to hide content and finish with an example utilizing JavaScript to transition an element’s visibility and then truly disable the display.

Visibility

Adding visibility: hidden; to a container’s style will definitely hide it from the end user. It also works very well with CSS transitions. Unfortunately, it retains the width and height of the container while also blocking any other objects underneath. The container’s children are still selectable and viewable by screen readers.

Display

The JavaScript-friendly style attribute is display: none; which fully hides the container. While visibility means that the contents of the element will be invisible, but the element stays in its original position and size. Display hides the element — including all of it’s contents — from screen readers as well as removing width and height from the container.

Content Visibility

Another approach is rendering the contents of a container with a newer CSS feature, content-visibility: hidden;. It allows the frontend develoepr to omit large swaths of layout rendering and load on the DOM until it is visible. It enables the user agent to skip an element's rendering work (including layout and painting) until it is needed — which makes the initial page load much faster.

Timeout Transition

For this to function in React, typically there will be a handler on a select onChange event and the variable event would be passed into the function so we can call upon e.target.value, the value of the current select field. Our main component is the function chooseFilter which applies both visibility and opacity styles to our objects. The setTimeout function is transitioning our styles and applying position: absolute before revealing the selected option. This allows us to truly hide the elements and gives space for the visible cards to wrap since we are not using display for this example. You can also see the full CSS where transition: 0.2s 0s all ease-in-out; was added to each card within the entire cardBlock container.

chooseFilter(e) {
let cards = document.querySelectorAll('#cardBlock .card')
cards.forEach(card => {
card.classList.add('filtered')
setTimeout(() => {
card.classList.add('absolute')
}, 300)
})
 
cards.forEach(card => {
if (!card.getAttribute('data-type').includes(e.target.value)) {
card.classList.add('filtered')
setTimeout(() => {
card.classList.add('absolute')
}, 300)
} else {
setTimeout(() => {
card.classList.remove('filtered')
card.classList.remove('absolute')
}, 300)
}
})
}

Here you can see the full function in action with basic HTML/CSS and JavaScript.