9. Styling HTML5 Media and Forms

Some HTML5 features not only provide new capabilities to allow you to create richer, better functionality more easily and natively, but they also bring with them new visual controls for your users to interact with. These include <video> and <audio>, as well as some new HTML5 form features. However, they present a host of styling problems: As with many older, less-nascent HTML features, the specs don’t dictate how they should be styled, so browsers have different default styling for such elements.

It’s a pain to style such elements across browsers consistently, especially if you also need to consider styling fallbacks that might be written in Flash. The information in this chapter will ease your pain by providing you with techniques for cross-browser styling consistency.

Customizing <video> and <audio>

The HTML5 <video> and <audio> elements provide a great way to embed media onto your page without having to use plug-in content like Flash; although, for older browser support you’ll want to consider providing a Flash movie fallback.

One of the main pain points of the HTML5 media elements is that they look different across browsers, as illustrated in Figure 9.1.

image

Figure 9.1 The visuals of different browsers’ HTML media implementations are a real drag for designers.

To remedy this, you can remove the native controls provided by the controls attribute, create your own simple buttons using HTML and CSS, and then use the HTMLMediaElement JavaScript API to wire those buttons to the right functions. You’ll learn how to do this in the next few sections.

Creating Simple Control Buttons

Let’s start by creating some nicer-looking video controls using your old friends HTML and CSS. You can do this in any way you want, but here I’ve used styled HTML <button> elements to create Play/Pause, Stop, Fast Forward, and Rewind buttons, and a timer. The HTML looks like this:

<div id="controls">
    <button id="play" data-icon="P"></button>
    <button id="stop" data-icon="S"></button>
    <div id="timer">00:00</div>
    <button id="rwd" data-icon="B"></button>
    <button id="fwd" data-icon="F"></button>
</div>

Styling Your Control Buttons

Styling your control buttons using the preceding code is nothing special, and you’ve already seen this CSS earlier in the book, so I won’t spell it all out in detail. The main items to note are that I’ve used a web font to create the icons for the buttons (the glyphs are read from HTML5 data- attributes and are added to the page using generated content; you saw this in Chapter 6), and the different button depressing and depth effects have simply been made using various text shadows, box shadows, and gradients.

The styling results in the visual effect shown in Figure 9.2—a much better cross-browser look!

image

Figure 9.2 The custom controls styled. Note that in this image I’ve removed the video controls attribute so the default browser controls are not rendered.

Wiring the Buttons Up with JavaScript

Now it’s time to make your custom buttons actually do something. This is fairly simple, because HTML5 provides a convenient API you can use to give your controls real functionality. Let’s explore! You can find my finished JavaScript in the file custom-player.js in the chapter9 code download folder. You should first set up some variables so it is easy to reference the <video>/<audio> player, the buttons, and the timer:

var media = document.getElementById('custom-player');
var play = document.getElementById('play');
var stop = document.getElementById('stop');
var timer = document.getElementById('timer');
var seekbar = document.getElementById('seek-inner');
var rwd = document.getElementById('rwd');
var fwd = document.getElementById('fwd');

Next, you’ll remove the default video controls (my HTML examples include the controls attribute so the native browsers’ controls are used if JavaScript isn’t available), and make the custom controls visible:

seekbar.value = 0;
media.removeAttribute("controls");
controls.style.visibility = "visible";

Then you add some event listeners:

play.addEventListener("click", playPauseMedia, false);
stop.addEventListener("click", stopMedia, false);
media.addEventListener("ended", stopMedia, false);
media.addEventListener("timeupdate", setTime, false);
rwd.addEventListener("mousedown", mediaBackward, false);
rwd.addEventListener("mouseup", normalPlay, false);
fwd.addEventListener("mousedown", mediaForward, false);
fwd.addEventListener("mouseup", normalPlay, false);

Here, listeners are added to the buttons to make the relevant actions happen when they are pressed. Another listener is added to the <video>/<audio> so that you can stop it when the end of the media is reached, and yet another is added to set the timer value when the time of the media updates.

Now on to the functions! The first function, playPauseMedia(), controls what happens when the first button is clicked:

function playPauseMedia() {
    if(media.className==="" || media.className==="paused") {
        media.setAttribute("class","playing");
        play.setAttribute("data-icon","u");
        media.play();
    } else {
        media.setAttribute("class","paused");
        play.setAttribute("data-icon","P");
        media.pause();
    }
}

Here I’ve used a simple if ... else statement to specify that if the class set on the media element is blank or paused, it is paused or stopped; otherwise, it is playing. If it is paused or stopped, you change the class on the media element to playing, change the data-icon attribute value on the Play button to “u” (a pause icon), and play the video using the play() method of the media API. If the media is playing, you change the media’s class attribute value back to paused, change the data-icon attribute value on the Play button to “P” (a play icon), and pause the video using the media API’s pause() method.

Next, you add the stopMedia() function, which controls what happens when the Stop button is pressed:

function stopMedia() {
    media.pause();
    media.currentTime = 0;
    media.setAttribute("class","");
    play.setAttribute("data-icon","P");
}

This is much simpler, because it has only one state rather than two states that are toggled in between. There is no stop() method in the media API, so instead you use the pause() method to pause the media and put it back to the start using currentTime = 0. You also make sure that the Play/Pause button is reset by putting those class and data-icon attributes you were playing with earlier back to their default states.

Next, you add the setTime() function, which updates the time counter:

function setTime() {
    var minutes = Math.floor(media.currentTime / 60);
    var seconds = Math.floor(media.currentTime - minutes * 60);
    var minuteValue;
    var secondValue;
    if (minutes<10) {
        minuteValue = "0" + minutes;
    } else {
        minuteValue = minutes;
    }
    if (seconds<10) {
        secondValue = "0" + seconds;
    } else {
        secondValue = seconds;
    }
    mediaTime = minuteValue + ":" + secondValue;
    timer.innerHTML = mediaTime;
}

This code isn’t as bad as it looks. The first part uses a bit of math to work out what the minute and second values are from the raw seconds returned by the currentTime method of the API. The second part checks whether the minute and second values are less than 10 or not. If so, a 0 is appended to the value, for example, 09. If not, the 0 is not appended, so the values will appear as, for example, 10, not 010.

The final two lines build the minute and second value into a timer readout, for example, 09:43, and then that value is squirted into the timer <div> using innerHTML.

The last set of functions is for the rewind/fast forward functionality:

function mediaBackward() {
    media.pause();
    interval = setInterval('media.currentTime = media.currentTime - 3', 200);
}
function mediaForward() {
    media.pause();
    interval = setInterval('media.currentTime = media.currentTime + 3', 200);
}
function normalPlay() {
    clearInterval(interval);
    media.play();
}

The first two functions use setInterval() to add or subtract three to/from the current time every fifth of a second while the mouse button is held down. I also pause the video while this is happening so that it doesn’t mess up the process. There is a setPlaybackRate() method, but I had to fake it like this as that method doesn’t work in Opera yet.

When the mouse button is not longer pressed, the normalPlay() removes the interval, and just starts the video playing as normal.

Other Media Styling Tips

Native video is really rather nice because you can style it in any way you want using CSS, and even create cool effects with media using SVG and <canvas>. For example, a simple effect I’ve used in this example is to hide the controls using opacity when you’re not hovering over the media:

#controls {
    opacity: 0.5;
    transition: 1s all;
}

and then only reveal them in their full glory when you do hover over the media:

#player:hover #controls, player:focus #controls {
    opacity: 1;
}

You could get a lot crazier with transforms and transitions if you wanted to, but I’d advise against it. Animating video is so processor intensive that it’s best to avoid it.

Another tip concerns styling Flash fallbacks. You pretty much can’t. And even if you want to do something simple like making sure a <video> is centered in its parent column, you need to include a wrapper <div> around the video, and then center that. For example:

#wrapper {
    margin: 0 auto;
}

Another big bugbear is getting consistent styling on the HTML5 media and the Flash fallback. You need to think about the styling of the HTML and the Flash movie separately.


image Note

If you really don’t fancy tackling all the JavaScript and styling manually, you could use one of the many third-party video players available. Many of them are written to take a lot of the browsers’ inconsistencies and HTML5/Flash standoffs out of your hands. I recommend checking out http://videojs.com and http://sublimevideo.net.


Other Resources

As you might have guessed, there is a lot more I could say about HTML5 media; in fact, there’s enough to fill an entire book. And indeed one of this book’s sister books fills this role. For much more about HTML5 media, check out HTML5 Multimedia: Develop and Design (Peachpit, 2011) by Ian Devlin.

There are also numerous other good resources available on the Internet. Here are just a few:

dev.opera articles about HTML5 media. http://dev.opera.com/articles/tags/video and http://dev.opera.com/articles/tags/audio

Using HTML5 audio and video on MDN. https://developer.mozilla.org/en/Using_HTML5_audio_and_video

Form Improvements

CSS3 and associated, modern web design goodies offer specific features for making HTML form styling easier. Simply put, HTML forms are a total pain to get looking good, and looking the same across browsers. The reason is that they are rendered so differently by default across browsers—and that is before you even start using the new HTML5 form controls, which as mentioned in Chapter 2 are not supported that well across browsers yet.

Improving Consistency

A great way to instantly level the playing field and improve consistency across browsers is to apply that rather useful normalize.css to your forms (you’ve seen this used throughout this book). Normalize renders many elements more consistently across browsers, including form controls. If you want to see the effect it has, look at the demo page at http://necolas.github.com/normalize.css/demo.html. Scroll down to the “Forms” section. This may not be exactly what you want straight away, but it is a great base to build upon.

CSS3 Form Selectors

CSS3 provides a number of form-related pseudo-classes to help you style form fields that contain valid and invalid data. They should be used along with the new HTML5 required attribute:

<input type="text" id="name" name="name" required>

Keep in mind that form elements need to have a name attribute to be submitted as part of a form and to be validated. The pseudo-classes available to use with CSS are as follows:

:required and :optional. These pseudo-classes let you style controls based on whether or not they have a required attribute.

:valid and :invalid. These pseudo-classes apply styles to form controls based on whether the data contained inside them is valid or invalid.

:in-range and :out-of-range. These pseudo-classes work with controls that feature a min and/or max attribute, styling data based on whether it is inside or outside the allowed data range.

Let’s look at a quick example to illustrate these pseudo-classes in action. See css3-form-selectors.html in the chapter9 code download folder. The parts of the demo that illustrate usage of the different features are fairly self-explanatory, but let’s have a look. Some styling is applied first to differentiate required and optional inputs:

#name:required {
    border: 1px solid black;
    box-shadow: inset 2px 2px 3px rgba(0,0,0,0.7);
    background: linear-gradient(top,#fff,#ccc);
}

label[id="required"]:before {
    content: "*";
}

#name:optional {
    border: 1px grey dashed;
    box-shadow: inset 2px 2px 3px rgba(0,0,0,0.4);
    opacity: 0.9;
}

Here I’ve made the optional input look a bit fainter and less important than the required one, and also used generated content to add an asterisk to the required label.

Next, I’ve styled the valid and invalid input examples as follows:

@keyframes box-shake {
    from { transform: translateX(2px); }
    to { transform: translateX(-2px); }
}

#email:invalid {
    border: 2px solid rgb(255,100,100);
    box-shadow: inset 2px 2px 3px rgba(0,0,0,0.7);
    background: linear-gradient(top,#fff,#eee);
    animation: box-shake 0.1s infinite;
}

#email:valid {
    border: 1px solid black;
    box-shadow: inset 2px 2px 3px rgba(0,0,0,0.7);
    background: linear-gradient(top,#fff,#eee);
}

I’ve made invalid inputs look as deviant as possible with a big red border and a shaky animation! Try entering an email address into one of the email fields to see the instant change in style when the form data becomes valid. Then I’ve used a number input with min and max attributes set (allowing data in the range 1–100):

@keyframes box-pulse {
    from { transform: scale(1.1); }
    to { transform: scale(0.9); }
}

#number:out-of-range {
    border: 2px solid rgb(255,100,100);
    box-shadow: inset 2px 2px 3px rgba(0,0,0,0.7);
    background: linear-gradient(top,#fff,#eee);
    animation: box-pulse 0.8s infinite linear alternate;
    transform-origin: center;
}

#number:in-range {
    border: 1px solid black;
    box-shadow: inset 2px 2px 3px rgba(0,0,0,0.7);
    background: linear-gradient(top,#fff,#eee);
}

Try focusing the input and entering a value of 101 or more to see what happens!


image Note

The pseudo-selectors in the file css3-form-selectors.html will work across all modern browsers with the exception that in-range and out-of-range don’t work in Firefox.


Wrapping Up

In this chapter, you learned a range of styling tips and tricks to help you get the most out of some of the new HTML5 features—namely <audio> and <video>. You also learned some neat little HTML form goodies.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.48.244