Changing Styles in Response to Media Events

12:58:00 PM |

You can use JavaScript to modify the style of website elements in response to media events. For example, you could update a music playlist and highlight the name of the song currently being played. The example in Listing 4-1 changes the webpage styles when a movie is playin
—darkening the background and fading the rest of the webpage by making it partly transpare
—then restores things when the movie is paused or completes. Figures III-1 and III-2 show the webpage with the movie playing and paused.

Figure 4-1  Page with movie paused
Figure 4-2  Page with movie playing
The example listens for the playingpause, and ended events. When the playing event fires, a function stores the current background color, sets the background color to black, and sets the opacity of the rest of the page to 0.25. When the pause or ended event fires, a second function restores the background color and sets the opacity to 1.
Note that the <style> section of the page sets the webkit-transition-property and webkit-transition-duration for the background color and opacity, so these properties change smoothly over a few seconds instead of changing abruptly. The background color and opacity change work in any HTML5-compliant browser, but the gradual state change happens only in Safari and other WebKit-based browsers.
Alternatively, you could set a JavaScript timer and darken the background and reduce the page opacity incrementally over several steps.
Listing 4-1  Dim the lights
<!DOCTYPE html>
<html>
<head>
<title>Dim the Lights</title>
<script type="text/javascript">
var restoreColor;
function dimLights() {
restoreColor = document.body.style.backgroundColor ;
var theBody = document.body ;
theBody.style.backgroundColor = "black" ;
var theRest = document.getElementById("restofpage") ;
theRest.style.opacity = 0.25 ;
}
function lightsUp() {
var theBody = document.body ;
theBody.style.backgroundColor = restoreColor ;
var theRest = document.getElementById("restofpage") ;
theRest.style.opacity = 1 ;
}
function addListener() {
var myVideo = document.getElementsByTagName('video')[0];
myVideo.addEventListener('playing',dimLights,false);
myVideo.addEventListener('pause',lightsUp,false);
myVideo.addEventListener('ended',lightsUp,false);
}
</script>
<style>
body { background-color:#888888;
color:#ffdddd;
text-shadow: 0.1em 0.1em #333;
-webkit-transition-property: background-color;
-webkit-transition-duration: 4s;
}
#restofpage { color:#ffffff;
width: 640px;
-webkit-transition-property: opacity;
-webkit-transition-duration: 4s;
}
</style>
</head>
<body onload = "addListener()">
<div align="center">
<h1>Dim the Lights, Please</h1>
<video id="player" controls
<src="http://homepage.mac.com/qt4web/myMovie.m4v">
</video>
<div id="restofpage">
<h3 style="color:#ffdddd;" >
This webpage uses HTML5 video, JavaScript, DOM events, and CSS.
</h3>
<p>
When the video starts playing, a DOM event is fired, and a JavaScript
function "dims the lights" by fading the webpage background color
to black and lowering the opacity of the rest of the page.
</p>
<p>
When the video pauses or ends, another event is fired and a second
JavaScript function brings the lights back up.
</p>
<p>
Try it!
</p>
</div>
</div>
</body>
</html>

Adding CSS Styles to Video

You can use CSS to apply styles to the video element itself. For example, you can change the video opacity, position the video on top of another element, or add a border.

Example: Setting Opacity

To allow elements under the video to show through, set the opacity of the video. Opacity has a range from 0 (completely transparent) to 1 (completely opaque). You can set opacity directly in CSS—applying it to video generally, or to a class of video, or to a particular video element:
Declaring the opacity of the video element: video { opacity: 0.5 }
Declaring the opacity of a class: .seeThroughVideo { opacity: 0.3 }
Declaring the opacity of an element using its ID: #theVideo { opacity: 0.7 }
To change video opacity dynamically, use JavaScript. You can address the video element by ID or tag name, and you can set the opacity property either directly or by changing the element’s class name to a class with a style applied to it.
The following code snippet declares the opacity of a class. The snippet then defines a JavaScript function that sets a video element’s classname to the declared class. A second JavaScript function illustrates setting the opacity of a video element directly, instead of changing the classname.
<style>
.seeThroughVideo { opacity: 0.3 }
</style>
<script type = "text/javascript">
function makeSeeThrough() {
document.getElementById("theVideo").className = "seeThroughVideo" ;
}
function setOpacityDirectly (val) {
document.getElementsByTagName("video")[0].style.opacity = val ;
}

Using WebKit Properties

In addition to the standard CSS properties, you can apply WebKit properties to video in Safari or other WebKit-based browsers. WebKit properties are prefixed with -webkit-. Many CSS properties begin as WebKit properties, are proposed as CSS standards, and go through review before becoming standardized. When and if a WebKit property becomes a standard property, -webkit- is dropped from the name. The -webkit- prefixed version is maintained for backward compatibility, however.
You can safely add WebKit properties to your webpages. WebKit-based browsers, such as Safari and Chrome, recognize WebKit properties. Other browsers just ignore them. Use WebKit properties to enhance general websites, but verify that your site still looks good using other browsers, unless your site is Safari-specific or designed solely for iOS devices.
Three noteworthy WebKit properties are masks, reflections, and 3D rotation.
image: ../art/porthole-html.jpg

Adding a Mask

You can make a video element appear non-rectangular or discontinuous by masking part of the video out using -webkit-mask-box-image. Specify an image to use as a mask. The mask image should have the same dimensions as the video, be opaque where you want the video to show, and be transparent where you want the video to be hidden. Making areas of the mask semi-opaque makes the corresponding areas of the video proportionally semi-transparent.
The following example uses CSS to position a video over the image of a porthole, then masks the video with a circular image so the movie appears to be seen through the porthole.
image: ../art/masking.jpg
<!DOCTYPE html>
<html>
<head>
<title>porthole</title>
</head>
<body>
<h1>Masked Video</h1>
<p>
Video is positioned on top of the porthole and masked.
</p>
<img src="porthole.jpg" width="430" height="365">
<video src = "myMovie.m4v" autoplay
style = "position:relative ; top: -325px ;
-webkit-mask-box-image: url(portholemask.png) ;">
</video>
</body>
</html>


Figure 4-5  Reflection with gradient mask and color stop
image: ../art/simpleReflection.jpg

Adding a Reflection

Add a reflection of a video using the -webkit-box-reflect property. Specify whether the reflection should appear on the left, right, above, or below the video, and specify any offset space between the video and the reflection. The following snippet adds a reflection immediately below the video.
<video src = "myMovie.m4v" autoplay style = "-webkit-box-reflect: below 0px;" >
If you set the controls attribute, the video controls will also appear mirrored in the reflection. Since the mirrored controls are backwards and nonfunctional, this is not usually what you want. Video reflections are best used with a JavaScript controller.
You can mask out part of the reflection by including the url of a mask image. The following example adds a masked reflection below the video.
<html>
<head>
<title>Reflection with Mask</title>
<script type="text/javascript">
function playPause() {
var myVideo = document.getElementById('theVideo');
if (myVideo.paused)
myVideo.play();
else myVideo.pause();
}
</script>
</head>
<body align="center" style = "background-color: 404040">
<h1 style="color:#ffeeee">
Reflection with Mask
</h1>
<input type="button" value="Play/Pause" onclick="playPause()">
<BR><BR>
<video  src = "myMovie.m4v" id = "theVideo"
style = "-webkit-box-reflect: below 0px url(mask.png);">
</video>
</body>
</html>
Figure 4-3  Reflection with mask image
Important: The mask image is reflected, so flip it 180° on the axis of reflection from the way you want it to appear.

Figure 4-4  Mask image
You can specify a gradient instead of an image to mask the reflection. The following snippet creates a gradient that fades to transparency.
<video style = "-webkit-box-reflect: below 0px
-webkit-gradient(linear, left top, left bottom, from(transparent), to(black));" >
Because the gradient is reflected, it is specified from transparent to black—its reflection goes from black to transparent. Because the gradient is a mask, only its opacity matters. It could also be specified from transparent to white.
The following snippet adds a color-stop to the gradient, causing it to reach transparency at four-tenths of its length.
<video style = "-webkit-box-reflect: below 0px
-webkit-gradient(linear, left top, left bottom, from(transparent), to(black),
color-stop(0.4, transparent));">

Rotating Video in 3D

You can use WebKit CSS properties to rotate video around the x or y axis. Rotating the video 180° allows the user to see it playing from “behind”. Rotating the video 90° causes it to play edge-on, making it invisible and revealing whatever is behind it. Rotation can be set statically using CSS or dynamically using JavaScript. The following snippet sets the video rotation at 45° about the y axis.
<video style="-webkit-transform: rotateY(45deg);" src="myVideo.m4v" controls>





Dynamic rotation is best used in conjunction with the webkit-transition property. Setting webkit-transition causes the video element to rotate smoothly over a specified duration, without having to set JavaScript timers or stepper functions. You set the transition property, specify the duration, and any time you change the specified property, the change is animated smoothly over the specified duration. The property to animate for rotation is -webkit-transform. When the animation completes, a webkitTransitionEnd event is fired.
The following snippet sets the transition property to -webkit-transform and sets the animation duration to 4 seconds.
<video src="myVideo.m4v" controls
style="-webkit-transition-property: -webkit-transform;
-webkit-transition-duration: 4s">
You can add perspective to the rotation, so that parts of the video element closer to the viewer along the z axis appear larger, and parts further away appear smaller. To add perspective, set the -webkit-perspective property of one of the video element’s parents, such as a parent div or the document body.
Listing 4-2 dynamically flips a playing video 180° around its y axis, intermittently revealing the text behind the video. The video has perspective when it rotates, due to the -webkit-perspective property of the body element.
Listing 4-2  3D rotation with perspective
<html>
<head>
<title>Video Flipper</title>
<style>
video {
-webkit-transition-property: -webkit-transform;
-webkit-transition-duration: 4s;
}
body { -webkit-perspective: 500;}
</style>
<script type="text/javascript">
var flipped = 0 ;
function flipper() {
if (flipped)
myVideo.style.webkitTransform = "rotateY(0deg)";
else
myVideo.style.webkitTransform = "rotateY(180deg)";
flipped = !flipped ;
}
</script>
</head>
<body>
<h1>
Video Flipper
</h1>
<p>
Text hidden behind the video.
</p>
<div  style = " position:relative; top: -40px;" >
<video src="myMovie.m4v" id="myVideo" autoplay controls>
</video>
<input type="button" value="Flip Video" onclick="flipper()">
</div>
</body>
</html>
Figure 4-6  Video in mid-rotation