Using Vue's "Transition" component to create crossfades

If you’ve ever used Vue’s built-in Transition component before, chances are that this looks very familiar to you:

<template>
<Transition mode="out-in" name="fade">
<div v-if="show" key="show">Showing</div>
<div v-else key="hide">Hiding</div>
</Transition>
</template>
<style>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
</style>

This works well, but the animation involves fading the leaving element out completely, before then fading in the entering element so that the two are never on the screen at the same time.

But what if you want to crossfade two images so that the entering element fades over the leaving element?

For this, we need to use the rarely-used transition mode of in-out. We’re also going to use Tailwind utility classes to control our transition rather than manually writing out a named transition (fade) as above.

<template>
<div class="relative">
<Transition
mode="in-out"
enter-active-class="transition-all duration-1000 absolute inset-0"
leave-active-class="transition-none absolute hidden"
enter-from-class="opacity-0"
>
<img v-if="showFirst" key="image-1" src="https://picsum.photos/seed/the-end-is-the-beginning/1920/1080" />
<img v-else key="image-2" src="https://picsum.photos/seed/tannhaus/1920/1080" />
</Transition>
</div>
</template>

In-Out mode explained

The lesser-used mode pretty much does what it says. It brings the entering element in first before then removing the leaving element from the view. The caveat here is that while out-in ensures that only one single element is rendered in the HTML document at a time, in in-out mode, during the length of the transition, both the entering and the leaving elements will be visible. This can cause a significant reflow and is the reason the mode is seldom used.

However, since we need our entering element to show at the same time as the leaving one to successfully crossfade them, it is the mode we need.

Positioning absolutely

To combat the HTML reflow, we need to ensure that one element is removed from the document flow, we can do this via the position: absolute style rule. We’ve also added the inset-0 class (shorthand for top:0;bottom:0;left:0;right:0) to our entering element to size it the same as the other image. The parent container of the images would have a position:relative style rule on it.

Hiding the leaving element

Because our entering element appears fully over the other element, we don’t need to have a leaving animation at all. Hence why we just disable transitions and hide the departing element. Without the leave-active-class classes declared above, the exiting element would momentarily flicker since all Vue transitions take at least 2 frames to complete. Since the entered element is now part of the document flow, we can remove the leaving element from the document flow by applying absolute to it instead.

Conclusion

For more information on using CSS classes in Vue transitions, see https://vuejs.org/guide/built-ins/transition.html#css-based-transitions

Get in Touch

Get in touch with us today 01202 790300

monday 09:00 - 17:00
tuesday 09:00 - 17:00
wednesday 09:00 - 17:00
thursday 09:00 - 17:00
friday 09:00 - 16:00
saturday Closed
sunday Closed