Because the <video>
element is standard HTML, you can modify its appearance and behavior using CSS styles. You can modify the opacity, add a reflection, rotate the video in three dimensions, and much more. You can also use CSS styles to enhance elements that interact with audio or video, such as custom controllers and progress bars.
Note: You may want to create your own stylish movie controller—including a progress bar and a time scrubber—that slides smoothly out of the way when not in use. To see an example of just that, download the ConcertDemo sample code from http://developer.apple.com/safari/library/samplecode/HTML5VideoPlayer/index.html
. The sample code contains complete HTML, JavaScript, CSS, and video.
This chapter illustrates some methods of adding CSS styles to video, as well as how to add a styled progress bar and play/pause button. For more information on using CSS styles in Safari, see Safari CSS Visual Effects Guide, Safari Graphics, Media, and Visual Effects Coding How-To's, and Safari CSS Reference.
The example in Listing 3-1 shows how to rotate video in three dimensions, hide and reveal content underlying the video, and change the opacity to composite video over a background. All the changes can be applied dynamically while the video is playing. The example uses a combination of HTML, CSS, and JavaScript to achieve these effects. Each part is explained individually in the following sections.
In the body of the document, the example first defines content to go under the video:
<div id="back"> |
<p style="position:relative;top:50%;" align="center"> |
This is hidden behind the video |
</p> |
</div> |
The content is a div
element just a little smaller than the video with text centered horizontally and vertically.
The example then adds the video, inside a div
element named “overlay”:
<div id="overlay" > |
<video class="video-player" id="player" |
height="348" width="680" controls |
src="myMov.mp4" |
> |
</video> |
Because the overlay is declared after the background, CSS naturally puts it in the layer above the background if they overlap later.
Finally, the example adds buttons to flip the video, reveal the hidden content, and fade the video in or out by changing its opacity, along with a button that displays the current opacity:
<input type=button value="flip backward" onclick="flipVideo()" |
id="flipflop"> |
<input type=button value="show back" onclick="toggleBack()" |
id="backer"> |
<input type=button value="fade out" onclick="fadeTo(0)"> |
<input type=button value="fade mid" onclick="fadeTo(.5)"> |
<input type=button value="fade in" onclick="fadeTo(1)"> |
<input type=button value="opacity: 100%" id="showfade"> |
</div> |
The “overlay” div
element is then closed—it includes the buttons and the video, so the buttons stay with the video when they are repositioned.
In the style
section of the head, the example sets the background content to the size of the video, gives it a background color, and makes it hidden:
#back{ |
height:330px; |
width:670px; |
background-color:gray; |
visibility:hidden; } |
The example then positions the div
containing the video and buttons at the top of the page (with a 5-pixel pad for aesthetics), covering the background content:
#overlay{ |
position:absolute; |
top:5px; } |
Finally, the example adds styles to the video itself. First it adds a background color. Then it specifies that any change in the webkit-transform
or opacity
properties should be animated by specifying them in webkit-transition-property
. The animation timing is set to start gradually (ease in) and take one second to complete:
#player { |
background-color:black; |
-webkit-transition-property: -webkit-transform, opacity; |
-webkit-transition-timing-function: ease-in; |
-webkit-transition-duration: 1s; } |
The CSS style declarations begin with #
because they are each applied to a single element, based on its unique id
attribute. Style declarations that begin with a dot (for example .back
) are applied based on the class
attribute, which multiple elements may share.
The JavaScript section of the head defines three functions: flipVideo()
, toggleBack()
, and fadetTo(val)
.
The flipVideo()
function rotates the video in 3D, flipping it 180° around the vertical axis by setting the style.webkitTransform
property to rotateY(0deg)
, or rotateY(180deg)
. Because the function is a toggle, it checks the button text to see what it should do—flip forward or flip backward—then changes the text of the button to show what it does next time.
function flipVideo() { |
var myVideo = document.getElementById('player'); |
var myButton = document.getElementById('flipflop'); |
if (myButton.value=="flip backward"){ |
myVideo.style.webkitTransform = "rotateY(180deg)"; |
myButton.value="flip forward"; |
}else{ |
myVideo.style.webkitTransform = "rotateY(0deg)"; |
myButton.value="flip backward"; |
} } |
The toggleBack()
function also rotates the video in 3D, this time 90° around the vertical axis, so it is edge-on to the viewer and therefore invisible. It also changes the style.visibility
property of the background content from hidden
to visible
. Because the function is a toggle, it then changes the text of the button from “show back” to “hide back”. When called again, it resets the Y rotation to 0° and sets the background content back to hidden
:
function toggleBack() { |
if (myButton.value=="show back"){ |
myVideo.style.webkitTransform = "rotateY(90deg)"; |
myButton.value="hide back"; |
backContent.style.visibility="visible"; |
}else{ |
myVideo.style.webkitTransform = "rotateY(0deg)"; |
myButton.value="show back"; |
backContent.style.visibility="hidden"; |
} } |
The fadeTo(opacityVal)
function takes one parameter: the desired opacity value. It sets the video’s style.opacity
property to that value and changes the text in a button to display the current opacity as a percent.:
function fadeTo(opacityVal) { |
document.getElementById('player').style.opacity=opacityVal; |
var showPercent= ("opacity "+ (opacityVal * 100) + "%"); |
document.getElementById('showfade').value= showPercent; |
} |
Notice that JavaScript is not used to animate the effects on the video. JavaScript just changes the style property values. The animation parameters are specified in CSS and the effects are rendered automatically.
Listing 3-1 is a complete working example, incorporating all the material in the previous three section, illustrating how to combine HTML, CSS, and JavaScript to add style to video dynamically.
Listing 3-1 Adding dynamic 3D rotation, hiding, and opacity to video
<!DOCTYPE html> |
<html> |
<head> |
<title>Flipping and Fading Video</title> |
<meta http-equiv="content-type" content="text/html; charset=utf-8"> |
<style> |
#back{ |
height:330px; |
width:670px; |
background-color:gray; |
visibility:hidden; |
} |
#overlay{ |
position:absolute; |
top:5px; |
} |
#player { |
background-color:black; |
-webkit-transform:rotateY(0deg); |
-webkit-transition-property: -webkit-transform, opacity; |
-webkit-transition-duration: 1s; |
-webkit-transition-timing-function: ease-in; |
} |
</style> |
<script type="text/javascript"> |
function flipVideo() { |
var myVideo = document.getElementById('player'); |
var myButton = document.getElementById('flipflop'); |
if (myButton.value=="flip backward"){ |
myVideo.style.webkitTransform = "rotateY(180deg)"; |
myButton.value="flip forward"; |
}else{ |
myVideo.style.webkitTransform = "rotateY(0deg)"; |
myButton.value="flip backward"; |
} |
} |
function toggleBack() { |
var backContent=document.getElementById('back'); |
var myVideo = document.getElementById('player'); |
var myButton = document.getElementById('backer'); |
if (myButton.value=="show back"){ |
myVideo.style.webkitTransform = "rotateY(90deg)"; |
myButton.value="hide back"; |
backContent.style.visibility="visible"; |
}else{ |
myVideo.style.webkitTransform = "rotateY(0deg)"; |
myButton.value="show back"; |
backContent.style.visibility="hidden"; |
} |
} |
function fadeTo(opacityVal) { |
document.getElementById('player').style.opacity=opacityVal; |
var showPercent= ("opacity "+ (opacityVal * 100) + "%"); |
document.getElementById('showfade').value= showPercent; |
} |
</script> |
</head> |
<body style="background-color:#C0C0C0;"> |
<div id="back"> |
<p style="position:relative;top:50%;" align="center"> |
This is hidden behind the video |
</p> |
</div> |
<div id="overlay"> |
<video id="player" |
height="348" width="680" controls |
src="myMov.m4v" |
> |
</video> |
<br> |
<input type=button value="flip backward" onclick="flipVideo()" |
id="flipflop"> |
<input type=button value="show back" onclick="toggleBack()" |
id="backer"> |
<input type=button value="fade out" onclick="fadeTo(0)"> |
<input type=button value="fade mid" onclick="fadeTo(.5)"> |
<input type=button value="fade in" onclick="fadeTo(1)"> |
<input type=button value="opacity: 100%" id="showfade"> |
</div> |
</body> |
</html> |
As shown in “Using DOM Events to Monitor Load Progress,” it’s fairly easy to monitor the movie loading process and show what percentage has downloaded using JavaScript alone. By integrating CSS styles, you can create a real progress bar.
The following example, Listing 3-2, creates a div
element named video-player
whose height is the height of the video plus the progress bar. It puts the video
element inside the video-player
, then adds a background bar by creating a nested div
element and styling it with a size, color, and shadow. Inside the bar it adds a partly transparent progress indicator, positioning it on top of the background bar but setting its width to 0%. Because the bar and progress indicator are inside the video-player
element, they inherit its width. That way when the progress indicator’s width goes from 0 to 100%, it grows to the width of the video. The progress indicator is translucent, so the background bar shows through.
A listener function on the progress
event updates the width
property of the progress indicator. An installer function installs the listener and is called on page load.
Listing 3-2 Adding a styled progress bar
<!DOCTYPE html> |
<html> |
<head> |
<title>Styled Progress Bar</title> |
<meta http-equiv="content-type" content="text/html; charset=utf-8"> |
<style> |
#video-player { |
width: 680px; |
height: 366px; |
background-color: black; |
} |
#background-bar { |
height: 18px; |
width: 680px; |
background-color: #D4D4D4; |
-webkit-box-shadow: 0px 2px 4px rgba(0,0,0,0.8); |
} |
#loader { |
height: 18px; |
width: 1%; |
opacity:.25; |
background-color: blue; |
} |
</style> |
<script type="text/javascript"> |
function showLoad() { |
var myVideo = document.getElementsByTagName('video')[0]; |
var soFar = parseInt(((myVideo.buffered.end(0) / myVideo.duration) * 100)); |
myLoader=document.getElementById("loader"); |
myLoader.style.width=(soFar + '%'); |
} |
function myAddListener() { |
var myVideo = document.getElementsByTagName('video')[0]; |
myVideo.addEventListener('progress',showLoad,false); |
} |
function playVideo() { |
var myVideo = document.getElementsByTagName('video')[0]; |
myVideo.play(); |
} |
</script> |
</head> |
<body onload="myAddListener()" > |
<div id="video-player"> |
<video height="348" width="680" autoplay |
src="http://homepage.mac.com/qt4web/myMovie.m4v" |
> |
</video> |
<br> |
<div id="background-bar"> |
<div id="loader"> |
</div> |
</div> |
<div> |
<p> </p> |
<input type="button" value="play" onclick="playVideo()"> |
</div> |
</body> |
</html> |
Note that the previous example includes a simple JavaScript play button. If the controls
attribute is omitted and no JavaScript controls are provided, a user on the iPad has no way to play the movie.
The final example, Listing 3-3, creates a video-player element that surrounds the video with a black background and puts a play/pause button under the video, centered horizontally. The play/pause button is styled with 24-point white text on a dark grey background, at 50% opacity.
When the user presses the play/pause button, it plays or pauses the movie. It also toggles the button’s value between “>” and “||”. The opacity is set to 50% when the video is paused and 20% when it’s playing, so the button is less distracting from the playing video.
Finally, a call to reset the play/pause button is added as an event listener to the video element’s ended
event.
Listing 3-3 Adding a styled play/pause button
<!DOCTYPE html> |
<html> |
<head> |
<title>Styled Play/Pause Button</title> |
<meta http-equiv="content-type" content="text/html; charset=utf-8"> |
<style> |
#video-player { |
width:50%; |
margin-left:25%; |
margin-right:25%; |
background-color: black; |
} |
#videobutton { |
line-height: 24pt; |
border: 3px solid white; |
-webkit-border-radius: 16px; |
opacity: 0.5; |
font-size: 24pt; |
color: white; |
background-color: #404040; |
cursor: pointer; |
text-align: center; |
z-index: 1; |
opacity:.5; |
} |
</style> |
<script type="text/javascript"> |
function pauseButton() { |
var myButton = document.getElementById("videobutton"); |
myButton.value = "||"; |
myButton.style.opacity=".2"; |
} |
function playButton() { |
var myButton = document.getElementById("videobutton"); |
myButton.value = ">"; |
myButton.style.opacity=".5"; |
} |
function playPause() { |
var myVideo = document.getElementsByTagName('video')[0]; |
if (myVideo.paused) { |
myVideo.play(); |
pauseButton(); |
}else{ |
myVideo.pause(); |
playButton(); |
} |
} |
function myAddListener() { |
var myVideo = document.getElementsByTagName('video')[0]; |
myVideo.addEventListener('ended',playButton,false); |
} |
</script> |
</head> |
<body onload="myAddListener()"> |
<div id="video-player"> |
<video src="http://homepage.mac.com/qt4web/myMovie.m4v" |
height="270" width="480"> |
</video> |
<P align=center> |
<input id="videobutton" type=button onclick="playPause()" value=">"> |
</p> |
</div> |
</body> |
</html> |
Last updated: 2010-03-18