A video is one of the most effective ways to introduce an app to an audience. Users often want to see how the app works before even deciding whether to download it or not. A screenshot could do the work, but with motion being a fundamental part of todays apps user experience, an animated gif and video elements make a difference. A great example is Pinterest Messages website.
Therefore we created a customisable, responsive template which turns into video slider on desktop screen ;)
Note: all videos in the demo have been created in Adobe After Effects, and exported as .mp4 using Adobe Media Encoder. While Miro Video Converter app has been used to get the .webm video format.
Creating the structure
The HTML is structured in 2 main <div>
elements (.cd-product-intro
and #cd-product-tour
) - the first containing the app intro (title, action buttons..) and the second the app features slider - wrapped inside a <main>
element.
<main class="cd-main-content">
<div class="cd-product-intro">
<h1><!-- app name --></h1>
<p><!-- brief description --></p>
<div class="cd-triggers">
<a href="#0" class="btn">Download</a>
<a href="#cd-product-tour" class="btn salmon" data-type="cd-tour">Start</a>
</div>
</div> <!-- cd-product-intro -->
<div id="cd-product-tour">
<ul>
<li class="cd-single-item cd-active">
<!-- single slider content -->
</li>
<!-- ..... -->
</ul>
</div> <!-- cd-product-tour -->
</main>
The app features slider is an unordered list: each item of the list contains a .cd-caption
element (feature title and description) and a .cd-image-container
element (feature image/video).
<div id="cd-product-tour">
<ul>
<li class="cd-single-item cd-active">
<div class="cd-caption">
<h2><!-- Feature title --></h2>
<p><!-- Feature description --></p>
</div>
<div class="cd-image-container">
<div>
<div class="cd-phone-frame"></div> <!-- this is the external phone -->
<div class="cd-image-wrapper">
<img src="img/screen-1.png" data-video="video/video-1">
</div>
</div>
</div>
</li>
<!-- ... -->
</ul>
</div> <!-- cd-product-tour -->
The video is not directly inserted in the HTML structure, but will be loaded using jQuery.
Two additional <div>
elements (.cd-slider-nav
for the app features slider navigation and the .cd-loader
for the top loading bar) have been added to the main.cd-main-content
.
Adding style
On small devices, the CSS is pretty straightforward (you can check the code for more details/comments).
On desktop devices (viewport width more than 1070px), we assigned a position: absolute
and width: 50%
to the .cd-product-intro
and placed it on the left side of the screen.
For the #cd-product-tour
element, we set width: 100%
and left: 0
but assigned it a translateX(75%)
so that only the phone image is visible.
@media only screen and (min-width: 1070px) {
.cd-product-intro {
position: absolute;
top: 50%;
transform: translateY(-50%);
left: 10%;
width: 50%;
transition: transform 0.3s, opacity 0.3s;
}
#cd-product-tour {
width: 100%;
max-width: 850px;
margin: 0 auto;
top: 50%;
left: 0;
transform: translateY(-50%) translateX(75%);
transition: transform 0.3s;
}
}
Here is an image to show you the initial positioning of the template components:
When user clicks the Start button, we add the .is-product-tour
class to the .cd-single-item
element: a translateX(-50%)
is assigned to the .cd-product-intro
(to hide it from the viewport) and a translateX(0)
to the #cd-product-tour
(so that both .cd-caption
and .cd-image-container
are visible). CSS3 transitions to the transform and opacity values have been added in order to achieve the smooth animation.
As for the li.cd-single-item
elements, we assigned them a position: absolute
, a width: 100%
and left: 0
(they occupy the same space) and used the visibility
and opacity
property to show only the the active slider.
@media only screen and (min-width: 1070px) {
.cd-single-item {
position: absolute;
top: 50%;
transform: translateY(-50%);
left: 0;
width: 100%;
visibility: visible;
}
.cd-single-item.cd-not-visible {
/*need to create a specific class to change visibility value due to a Firefox bug*/
/*CSS transition/animation fails when parent element changes visibility attribute*/
visibility: hidden;
}
.cd-single-item .cd-caption {
width: 60%;
float: right;
opacity: 0;
transition: transform 0.3s, opacity 0.3s;
}
.is-product-tour .cd-single-item.cd-active .cd-caption {
opacity: 1;
}
.cd-single-item.cd-move-right .cd-caption {
transform: translateX(100px);
}
.cd-image-container {
width: 35%;
float: left;
}
.cd-image-container img {
transition: transform 0.3s;
transform: translateZ(0);
}
.cd-move-right .cd-image-container img {
transform: translateX(100%);
}
}
Note that we set height: 100%
to <body>
and <html>
in order to have a full page content.
Events handling
The videos showing the app features are not inserted directly into the HTML, but loaded only when the corresponding slider is shown for the first time. The data-video
of the selected slider image is used to retrieve the video url. Two video formats have been used to support all the browsers: .mp4 and .webm. As soon as the video is inserted in the HTML, the loading bar animation starts. When the video is ready to be played (canplaythrough
event occurs), the loading bar animation is completed and the video is played.
If you want to learn more about the HTML5 video element, check this article on HTML5Rocks.
function uploadVideo(selected) {
// selected is the .cd-single-item.cd-active slider element
selected.siblings('.cd-single-item').find('video').each(function(){
//pause videos user is not watching
$(this).get(0).pause();
});
if(selected.find('video').length > 0) {
//video has been already loaded - play it
selected.find('video').eq(0).show().get(0).play();
} else {
//load video - the name of the video is the data-video of the image
var videoUrl = selected.find('.cd-image-container img').data('video'),
video = $('<video loop="loop"><source src="'+videoUrl+'.mp4" type="video/mp4" /><source src="'+videoUrl+'.webm" type="video/webm" />Sorry, your browser does not support HTML5 video.</video>');
video.appendTo(selected.find('.cd-image-wrapper')).hide();
var loaded = 'false';
//check if the canplaythrough event occurs - video is ready to be played
selected.on('canplaythrough', 'video', function() {
loaded = 'true';
});
//animate the loading bar
$('.cd-loader').show().animate({width: '50%'}, 1500, function(){
var timeout = setInterval(function(){
if( loaded ){
//this means the video is ready - complete .cd-loader and play the video
$('.cd-loader').animate({width: '100%'}, 100, function(){
$('.cd-loader').css('width', 0);
selected.find('video').show().get(0).play();
selected.find('img').css('opacity', 0);
clearInterval(timeout);
});
} else {
//video is not ready yet
var windowWidth = $(window).width(),
widthNew = $('.cd-loader').width() + 10;
if(widthNew < windowWidth ) {
$('.cd-loader').show().animate({width: widthNew+'px'}, 500);
}
}
}, 500);
}
}
One important note: if you check the code, you can see that the videos we have been using have an aspect ratio higher than 1 ( width > height). The videos are inserted in the HTML and then rotated (90deg) using a CSS3 rotation in order to fit the phone frame (awkward, I know!). Actually we started using videos with an aspect ratio smaller than 1 (same aspect ratio of the phone) but they were not shown in IE 9+. It looks like (or at least this is the conclusion we drew after some tries) IE (9+) has issues showing videos with an aspect ration smaller than 1.
If you guys have more details/info about this problem, please leave a comment!