Vue Sci-Fi Scanner Transition
Tags: scanner, space, vue, transition
Published: 2020-05-18 15:28:16

---
title: Vue Sci-Fi Scanner Transition
published: true
description: How to build a sci-fi scanning effect using Vue transition
tags: scanner, space, vue, transition
---

I recently had the opportunity to launch [Shelter In Space](https://space.airkhruang.com) for the band Khruangbin which allows users to generate a Spotify or Apple Music playlist (curated by them) for a home activity of their choosing. The design of this app was inspired by the guide animations from the 1980's BBC television adaption of The Hitchhiker's Guide to the Galaxy. One of the key components I tried to recreate was the vertical scanning effect which transitioned between content. Click the image in the Codepen below to see the final solution and read on to better understand how it was developed.

{% codepen https://codepen.io/leemartin/pen/oNjQNqm %}

First, the structure. `.scanner` holds two divs which both have background images. One is a pair of touching hands and another is Buddah. Both of these are absolutely positioned on top of each other. There is a single Vue property of state which allows toggling between the two via a click event on the `.scanner` div. 

Let's first talk about the clipping transition which clips one image out of frame while showing the other. Vue has great [documentation](https://vuejs.org/v2/guide/transitions.html) on ways to apply enter/leave transitions which an item is removed or added from the DOM. In our case, we'll be using the transition classes which Vue applies automatically. The `clip-path` CSS property allows you to _clip_ an element in all sorts of shapes and sizes. We're only interested in an inset rectangular shape. 

For example, if you wanted to clip 50% of a div from the top.

```
clip-path: inset(50% 0 0 0)
```

What about 75% from the bottom?

```
clip-path: inset(0 0 75% 0)
```

The `clip-path` property is also animatable. With this knowledge, we can setup our transition classes accordingly.

```css
/* Clip 100% from bottom before shown */
.scan-enter{
  clip-path: inset(0 0 100% 0);
}

/* Transition to no clipping from bottom */
.scan-enter-to{
  clip-path: inset(0 0 0 0);
}

/* Start from no clipping */
.scan-leave{
  clip-path: inset(0 0 0 0);
}

/* Transition to 100% clipping from top */
.scan-leave-to{
  clip-path: inset(100% 0 0 0);
}

/* Set time and easing */
.scan-enter-active, .scan-leave-action{
  transition: clip-path 2s linear;
}
```

Make sure to add `key` attributes to your content and clicking should show the `clip-path` transition. Now, let's discuss the scanner line itself. In the source material, the scanner lines sits over both the incoming and outgoing content at the point of transition and turns content beneath it white without affecting the black background. CSS has a property called `backdrop-filter` which allows you to apply CSS filters such as blur or brightness to elements _beneath_ the styled div. While most folks might use this to create blurred overlays, let's use it to **brighten** the illustrations. Rather than create a new div for the line, we'll add a `::before` pseudo element to each image div and position it absolutely.

```css
.scanner div::before{
  backdrop-filter: blur(1px) brightness(1000%) grayscale(100%);
  -webkit-backdrop-filter: blur(1px) brightness(1000%) grayscale(100%);
  content: "";
  display: block;
  height: 100%;
  position: absolute;
  transform: translateY(-50%);
  width: 100%;
}
```

Note: I'm using the transform here to make sure the line isn't present before or after transition. There's probably a smarter way to do this but it works.

With the pseudo element in place, we can expand on our transition classes to simply move the position of the line.

```css
/* Start at the top */
.scan-enter::before, .scan-leave::before{
  top: 0%;
}

/* Transition to the bottom */
.scan-enter-to::before, .scan-leave-to::before{
  top: 100%;
}

/* Set timing and ease */
.scan-enter-active::before, .scan-leave-active::before{
  transition: top 2s linear;
}
```

And that's about it. As a Vue <transition> beginner, I was very happy with this result and I think it adds a lot of magic to our [project](https://space.airkhruang.com) without adding much complexity.