Skip to content

Instantly share code, notes, and snippets.

@yrokhlin

yrokhlin/blog.md Secret

Created April 24, 2017 21:08
Show Gist options
  • Save yrokhlin/ac25dd157ab7b503d553eae3de94478b to your computer and use it in GitHub Desktop.
Save yrokhlin/ac25dd157ab7b503d553eae3de94478b to your computer and use it in GitHub Desktop.

Spiffy UI and Design

How to make an effective video comparison component using react and CSS in JS

When we were in the design stages of our website, and we were still trying to figure out a way to explain our product, I created 2 animated videos, that illustrated edgemesh's capabilities and the difference between a traditional network and our mesh network. The issue however became, how to seamlessly display this content on our page. Stacking it side by didn't make sense, because we wanted to display the full resolution of the video, and stacking the videos one on top of the other made the information lose a bit of context, and in general just took up too much space. The only other option left, was overlaying the videos seamlessly directly one on top of the other, and being able to somehow interactively mouse between them.

option1

option2

option3

This task presents us with a few challenges:

  • Preparing your content

  • Overlaying 2 video elements

  • Using the onMouseMove event to determine mouse position

  • Figuring out how we are going to animate

  • Puting it all together, and making it performant

  • Making it work on mobile

Preparing your video content

The first thing you will want to do is prepare your video content, before anything else. I personally recommend, for compatability reasons, to get your video content into at least 3 formats.

Recommended video content formats:

  • .webm
  • .mp4
  • .gif

For performance reasons, I will typically take my source footage and I will first convet it to a .webm. This format was developed by Google to be extremely lightweight, and create high quality and low file size videos very well, but is not compatabile with all browsers. More information about the .webp format can be found here on its official Google developer page.

Typically I will use the .webm as my primary source, and fallback to .mp4 if the browser does not support .webm -- the .gif only needs to be generated if you plan on mobile compatability (more on that later.)

You can use a service like Cloudconvert to do your video conversions, and it supports all the format that I have mentioned.

Overlaying 2 video elements

We will start off by creating a simple class extending the generic react component. Inside of our component, we will define some props (basically just the paths to our 2 videos) and we will render both <video/> containers.

Please note, I use the HTML5 <video/> tag because it allows us to easily create fallbacks, for unsupported formats.

We will also start defining some styles above our class.

For this example, I use aphrodite inline style library. You can use regular CSS, or another library, but this is what I will be using for all of the examples.

https://gist.github.com/dde37e23b79df4ea0b165fd685163a9d

Figuring out how we are going to animate

Okay, so we have our two videos overlayed one on top of the other, and our mouse position relative to the image, now what? Let's take a moment to visualize what we are trying to achieve. Basically we want to crop the top image based on our mouse/touch position to reveal the image underneath.


First we will start off by applying the mouses X position, which we figured out in the previous step, and apply it as a translational X value to the Video A Container (that's the video that is absolutely positioned on top of the other video.) This should move the Video A Container and the Video A inside the countainer with the mouse cursor to reveal the Video B underneath.

anim1

We can then take the mouse position, and reverse it by multiplying it by -1 to, get a direct opposite direction. We then take this opposite direction value and plug it in to the translation of Video A inside of the Video A Container making sure that the Video A Container has style property overflow: hidden causing it to clip Video A as it travels outside of its bounds.

anim2

When we combine both animations, they end up sort of cancelling each other out, and we get the desired effect, hooray! Now let's put it all together and make it work on mobile as well!

anim3

Puting it all together, and making it performant

Now that we have a good idea of where all the pieces will be moving, we can begin putting it all together. Now there are numerous ways we can do the actual animation using CSS properties, but I recommened using transform: translateX() for several reasons. Transform will always give a smoother experience on mobile, and will keep up better with lower end CPUs. Transitioning the left property will lead to extreme stuttering in animation on mobile devices.

https://gist.github.com/0e4c3c0f2fe13a7b86db9c3e41b6bcc4

You may have noticed that I plug the transform values in to the style prop instead of the className prop, it's because I don't want aphrodite to create a new stylesheet on every single state update. Various css-in-js libraries handle this in different ways, and for something like Radium you would stick everything in to the style prop.

Making it work on mobile

Through out this tutorial, we have done our best to keep mobile in mind. Our mouse movement handler can detect mobile touches for instance, and we are using transform: translateX() instead of left which should create a smooth animation even on most mobile devices. However, we seem to run into a small problem when attempting to render this component on mobile, which becomes apparent immediately when you try.

** MOST MOBILE DEVICES WILL ONLY RENDER ONE VIDEO AT A TIME **

Yup, and even worse, video autoplay is disabled in most mobile browsers due to battery saving measures. Even though now browser vendors are starting to see the light a little bit and even the new Apple OS allows for muted video to autoplay on a browser without a user gesture. there is still only one classic way to make your component bulletproof on most mobile devices.

GIFS, SWEET WONDERFUL GIFS!

gif

By converting our video to .gif we can get around the pesky <video/> limitations on most mobile browsers. You can use a library like is.js to do a simple check to detect when the user is on a mobile browsers, and simply switch out your <video/> tags with <picture/> or <img/> tags.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment