Mozilla

CSS Articles

Sort by:

View:

  1. Capturing – Improving Performance of the Adaptive Web

    Responsive design is now widely regarded as the dominant approach to building new websites. With good reason, too: a responsive design workflow is the most efficient way to build tailored visual experiences for different device screen sizes and resolutions.

    Responsive design, however, is only the tip of the iceberg when it comes to creating a rich, engaging mobile experience.

    Image Source: For a Future-Friendly Web by Brad Frost

    The issue of performance with responsive websites

    Performance is one of the most important features of a website, but is also frequently overlooked. Performance is something that many developers struggle with – in order to create high-performing websites you need to spend a lot of time tuning your site’s backend. Even more time is required to understand how browsers work, so that you make rendering pages as fast as possible.

    When it comes to creating responsive websites, the performance challenges are even more difficult because you have a single set of markup that is meant to be consumed by all kinds of devices. One problem you hit is the responsive image problem – how do you ensure that big images intended for your Retina Macbook Pro are not downloaded on an old Android phone? How do you prevent desktop ads from rendering on small screen devices?

    It’s easy to overlook performance as a problem because we often conduct testing under perfect conditions – using a fast computer, fast internet, and close proximity to our servers. Just to give you an idea of how evident this problem is, we conducted an analysis into some top responsive e-commerce sites which revealed that the average responsive site home page consists of 87.2 resources and is made up of 1.9 MB of data.

    It is possible to solve the responsive performance problem by making the necessary adjustments to your website manually, but performance tuning by hand involves both complexity and repetition, and that makes it a great candidate for creating tools. With Capturing, we intend to make creating high-performing adaptive web experiences as easy as possible.

    Introducing Capturing

    Capturing is a client-side API we’ve developed to give developers complete control over the DOM before any resources have started loading. With responsive sites, it is a challenge to control what resources you want to load based on the conditions of the device: all current solutions require you to make significant changes to your existing site by either using server-side user-agent detection, or by forcing you to break semantic web standards (for example, changing the src attribute to data-src).

    Our approach to give you resource control is done by capturing the source markup before it has a chance to be parsed by the browser, and then reconstructing the document with resources disabled.

    The ability to control resources client-side gives you an unprecedented amount of control over the performance of your website.

    Capturing was a key feature of Mobify.js 1.1, our framework for creating mobile and tablet websites using client-side templating. We have since reworked Mobify.js in our 2.0 release to be a much more modular library that can be used in any existing website, with Capturing as the primary focus.

    A solution to the responsive image problem

    One way people have been tackling the responsive image problem is by modifying existing backend markup, changing the src of all their img elements to something like data-src, and accompanying that change with a <noscript> fallback. The reason this is done is discussed in this CSS-Tricks post

    “a src that points to an image of a horse will start downloading as soon as that image gets parsed by the browser. There is no practical way to prevent this.

    With Capturing, this is no longer true.

    Say, for example, you had an img element that you want to modify for devices with Retina screens, but you didn’t want the original image in the src attribute to load. Using Capturing, you could do something like this:

    if (window.devicePixelRatio && window.devicePixelRatio >= 2) {
        var bannerImg = capturedDoc.getElementById("banner");
        bannerImg.src = "retinaBanner.png"
    }

    Because we have access to the DOM before any resources are loaded, we can swap the src of images on the fly before they are downloaded. The latter example is very basic – a better example to highlight the power of capturing it to demonstrate a perfect implementation of the picture polyfill.

    Picture Polyfill

    The Picture element is the official W3C HTML extension for dealing with adaptive images. There are polyfills that exist in order to use the Picture element in your site today, but none of them are able to do a perfect polyfill – the best polyfill implemented thus far requires a <noscript> tag surrounding an img element in order to support browsers without Javascript. Using Capturing, you can avoid this madness completely.

    Open the example and be sure to fire up the network tab in web inspector to see which resources get downloaded:

    Here is the important chunk of code that is in the source of the example:

    <picture>
        <source src="/examples/assets/images/small.jpg">
        <source src="/examples/assets/images/medium.jpg" media="(min-width: 450px)">
        <source src="/examples/assets/images/large.jpg" media="(min-width: 800px)">
        <source src="/examples/assets/images/extralarge.jpg" media="(min-width: 1000px)">
        <img src="/examples/assets/images/small.jpg">
    </picture>

    Take note that there is an img element that uses a src attribute, but the browser only downloads the correct image. You can see the code for this example here (note that the polyfill is only available in the example, not the library itself – yet):

    Not all sites use modified src attributes and <noscript> tags to solve the responsive image problem. An alternative, if you don’t want to rely on modifying src or adding <noscript> tags for every image of your site, is to use server-side detection in order to swap out images, scripts, and other content. Unfortunately, this solution comes with a lot of challenges.

    It was easy to use server-side user-agent detection when the only device you needed to worry about was the iPhone, but with the amount of new devices rolling out, keeping a dictionary of all devices containing information about their screen width, device pixel ratio, and more is a very painful task; not to mention there are certain things you cannot detect with server-side user-agent – such as actual network bandwidth.

    What else can you do with Capturing?

    Solving the responsive image problem is a great use-case for Capturing, but there are also many more. Here’s a few more interesting examples:

    Media queries in markup to control resource loading

    In this example, we use media queries in attributes on images and scripts to determine which ones will load, just to give you an idea of what you can do with Capturing. This example can be found here:

    Complete re-writing of a page using templating

    The primary function of Mobify.js 1.1 was client-side templating to completely rewrite the pages of your existing site when responsive doesn’t offer enough flexibility, or when changing the backend is simply too painful and tedious. It is particularly helpful when you need a mobile presence, fast. This is no longer the primary function of Mobify.js, but it still possible using Capturing.

    Check out this basic example:

    In this example, we’ve taken parts of the existing page and used them in a completely new markup rendered to browser.

    Fill your page with grumpy cats

    And of course, there is nothing more useful then replacing all the images in a page with grumpy cats! In a high-performing way, of course ;-).

    Once again, open up web inspector to see that the original images on the site did not download.

    Performance

    So what’s the catch? Is there a performance penalty to using Capturing? Yes, there is, but we feel the performance gains you can make by controlling your resources outweigh the minor penalty that Capturing brings. On first load, the library (and main executable if not concatenated together), must download and execute, and the load time here will vary depending on the round trip latency of the device (ranges from around ~60ms to ~300ms). However, the penalty of every subsequent request will be reduced by at least half due to the library being cached, and the just-in-time (JIT) compiler making the compilation much more efficient. You can run the test yourself!

    We also do our best to keep the size of the library to a minimum – at the time of publishing this blog post, the library is 4KB minified and gzipped.

    Why should you use Capturing?

    We created Capturing to give more control of performance to developers on the front-end. The reason other solutions fail to solve this problem is because the responsibilities of the front-end and backend have become increasingly intertwined. The backend’s responsibility should be to generate semantic web markup, and it should be the front-end’s responsibility to take the markup from the backend and processes it in such a way that it is best visually represented on the device, and in a high-performing way. Responsive design solves the first issue (visually representing data), and Capturing helps solve the next (increasing performance on websites by using front-end techniques such as determining screen size and bandwidth to control resource loading).

    If you want to continue to obey the laws of the semantic web, and if you want an easy way to control performance at the front-end, we highly recommend that you check out Mobify.js 2.0!

    How can I get started using Capturing?

    Head over to our quick start guide for instructions on how to get setup using Capturing.

    What’s next?

    We’ve begun with an official developer preview of Mobify.js 2.0, which includes just the Capturing portion, but we will be adding more and more useful features.

    The next feature on the list to add is automatic resizing of images, allowing you to dynamically download images based on the size of the browser window without the need to modify your existing markup (aside from inserting a small javascript snippet)!

    We also plan to create other polyfills that can only be solved with Capturing, such as the new HTML5 Template Tag, for example.

    We look forward to your feedback, and we are excited to see what other developers will do with our new Mobify.js 2.0 library!

  2. Firefox Development Highlights – H.264 & MP3 support on Windows, scoped stylesheets + more

    Time for the first look this year into the latest developments with Firefox. This is part of our Bleeding Edge and Firefox Development Highlights series, and most examples only work in Firefox Nightly (and could be subject to change).

    H.264 & MP3 support on Windows

    Firefox for Android and Firefox OS already support H.264 and MP3. We are also working on bringing these formats to Firefox Desktop. On Windows 7 and above, you can already test it by turning on the preference media.windows-media-foundation.enabled in about:config. Decoding is done on the OS side (no decoder included in Firefox source code, not like WebM or Ogg Theora). For Linux and Mac, work is in progress.

    The new Downloads panel has been enabled

    We have now enabled the new Downloads panel:

    Scoped style attribute

    It’s now possible to define scoped style elements. Usually, when we write a stylesheet, we use <style>...</style>, and CSS code is applied to the whole document. If the <style> tag is nested inside a node (let’s say a <div>), and the <style> tag includes the scoped attribute (<style scoped>), then the CSS code will apply only to a subtree of the document, starting with the parent node of the <style> element. The root of the subtree can also be referred via the :scope pseudo-class.

    Demo

    Scoped style demo support on JS Bin.

    Our friends over at HTML5Rocks have also written about it in A New Experimental Feature: scoped stylesheets.

    @supports and CSS.supports

    In Firefox 17, we shipped the @supports CSS at-rule. This lets you define specific CSS code only if some features are supported. For example:

    @supports not (display: flex) {
      /* If flex box model is not supported, we use a different layout */
      #main {
          width: 90%;
      }
    }

    In Firefox 20, it’s now possible to do the same thing, but within JavaScript:

    if (CSS.supports("display", "flex")) {
      // do something relying on flexbox
    }
  3. A tale of a CSS3 Animation Demo

    Once upon a time, there was this good hearted web developer, who was everyday worried about learning new cool things and trying new crazy stuff his browser could barely be able to do. Also, there were some giants, working hard to increase the power of the magic web, allowing all the peoples to live, code, learn and share freely.

    Among those things, there was CSS3 with its new features! I heard about something called Mozilla Dev Derby, and by that month, the focused feature was exactly CSS3 animations! What an opportunity to learn cool and be part of something like that! It’s awesome that companies like Mozilla are working so hard to keep these subjects and contents available to us!

    Two examples will be used here to both explain the technologies and tell the history. Felipe prepared a demo using HTML5 and CSS3 animations to do a Earth planet spinning, and, not aware of that, Deivid Marques had a similar idea.

    Why a planet Earth?

    Inspiration was the key. Since I was a child I have been fascinated with the Universe (both the micro, and macro ones) and the Earth, being what it is for us…such a good host! I decided to use it as inspiration!

    Images

    Obviously, images would be required. I tried to avoid images as much as possible, but I simply wouldn’t represent the Earth in a blurred image! Also, the moon, the stars in the background and the small sun are images.

    What should be animating?

    Before animating things around there, I mapped everything that could make sense to be moving, and how. First of all, the planet itself! The earth has to spin in one direction, while also bents to create the four seasons. Also, there is the day and night of the Earth due to its rotation.

    The Moon runs around the globe, but once it is behind the Earth, it should get darker. Also, the Moon should come to the front of the planet, and then hide behind it. Also, a slow movement, added to the stars in the background, could be of use!

    HTML Structure

    I didn’t want to make it too complex, so I didn’t use pseudo elements. That forced me to have the HTML just a little bit bigger.

    This is what is inside the Body tag:

    <div id="sun">
    </div>
    <div id="atmosphere">
    </div>
    <div id='globe'>
    </div>
    <div id='moon'>
    </div>
    <div id="sunLight1">
    </div>
    <div id="sunLight2">
    </div>
    <div id="sunLight3">
    </div>
    <div id="sunLight4">
    </div>
    <div id="sunLight5">
    </div>
    <div id="sunLight6">
    </div>

    Visual effects

    Well, you know that everything seems pretty from out there! So the visual effects should be cool too!

    The globe

    The globe is basically a rounded div, with a global map as its background. It is centered with an absolute position and sizes, and uses a box-shadow effect to represent the side of the planet where it’s night.

    #globe
    {
        background-image: url(images/globe-hearth.jpg) repeat-x;
        border: solid 1px #000;
        position:absolute;
        top: 50%;
        left: 50%;
        width: 600px;
        height: 600px;
        margin-left: -300px; /* aligning it to the center */
        margin-top: -300px;
        border-radius: 50%; /* making it round */
        z-index:0;
        box-shadow: inset 2px 2px 10px #000, inset -140px -70px 100px #000;
    }

    The atmosphere

    The atmosphere is another round div with a box-shadow effect.

    #atmosphere
    {
        position:absolute;
        top: 50%;
        left: 50%;
        width: 600px;
        height: 600px;
        margin-left: -300px;
        margin-top: -300px;
        border-radius: 50%;
        opacity: 0.7;
        box-shadow: -6px -6px 20px #eef;
    }

    The Sun

    The Sun, in this demo is just another div with an image as background, although, there is a tricky detail here! I wanted the Sun to be positioned right in the horizon of the globe, so, just centering it would not work! Also, I couldn’t know the resolution to fit it exactly there! But, I knew the size of the planet and I also knew it was centered!

    Therefore, I just had to center it, and then adjust its position by changing its margin values.

    #sun
    {
        background-image: url(images/sun.png);
        position: absolute;
        top: 50%;
        left: 50%;
        width: 50px;
        height: 47px;
        margin-left: -320px;
        margin-top: -110px;
    }

    The stars behind

    The stars were simply a div with a repeatable background image.

    The Moon

    The Moon was quite more complex. It had to turn around the globe, so, I’d have to play with its z-index as well. Besides that, it was simply another round div.

    Sun lights

    Also, there are a few reflections of the light of the Sun. Those, are other round divs, absolutely positioned with different colours and opacity. Box-shadow could also be an optional nice touch! So I also used it.

    Animation time

    To animate the Earth, I created two animations using the keyframes CSS3 feature.

    (Note: In these examples, I’m just showing the “-moz” definition of the animations, but you have to create them for each vendor if you want it to work in different browsers).

    @-moz-keyframes dayByDay
    {
        from{
                background-position: -1600px;
        }
        to{
                background-position: 0px;
        }
    }

    This way, the background of the globe would be passing, as pretending the globe was spinning. Also, I created the animation for the seasons:

    @-moz-keyframes seasons
    {
        from{
            -moz-transform: rotate(6deg);
        }
        to{
            -moz-transform: rotate(16deg);
        }
    }

    You know, the planet Earth is not fully straight to the 0 degrees. Now, I had to add those animations to the globe:

    #globe{
        -moz-animation: dayByDay 24s linear 0s infinite, seasons 2688s linear alternate 0s infinite;
    }

    Animating the sky behind everything followed the very same technique as the dayByDay animation.

    Animating the Moon was more of a challenge! To animate it, I had to change its size and position. Also making it darker or lighter and taking care of its z-index.

    Below, is how I did that back then (on june 2011). Nowadays, I would try it with -moz-transform using the scale transform, instead of changing its width and height. Also, back then, I used negative and positive values for the z-index of the moon…instead, I could have added a z-index to the Earth, like 2, and use only positive values in the Moon’s z-index(1, and 3) to move it to the back or front of the planet. I didn’t want to change it here, because this is how it is running on the uploaded demo, in Mozilla Derby.

    @-moz-keyframes moon
    {
       0%{
           width: 30px;
           height: 31px;
           margin-left: -310px;
           margin-top: -40px;
           z-index:-1;
       }
       10%{
           margin-left: -450px;
           margin-top: -50px;
           width: 60px;
           height: 61px;
           z-index:1;
       }
       20%{
           margin-left: -500px;
           margin-top: -50px;
           width: 80px;
           height: 81px;
           z-index:1;
       }
       30%{
           margin-left: -450px;
           margin-top: -50px;
           width: 90px;
           height: 92px;
           z-index:1;
       }
       50%{
           margin-left: 0px;
           margin-top: -50px;
           width: 120px;
           height: 122px;
           z-index:1;
       }
       60%{
           margin-left: 300px;
           margin-top: -50px;
           width: 120px;
           height: 122px;
           z-index:1;
       }
       60%{
           margin-left: 410px;
           margin-top: -50px;
           width: 90px;
           height: 92px;
           z-index:1;
           box-shadow: inset 0px 0px 80px #000;
       }
       70%{
           margin-left: 460px;
           margin-top: -50px;
           width: 80px;
           height: 82px;
           z-index:1;
           box-shadow: inset 0px 0px 80px #000;
       }
       80%{
           margin-left: 420px;
           margin-top: -50px;
           width: 60px;
           height: 61px;
           z-index:-1;
           box-shadow: inset 0px 0px 80px #000;
       }
       90%{
           margin-left: 0px;
           margin-top: -50px;
           width: 30px;
           height: 31px;
           z-index:-1;
       }
       100%{
           width: 30px;
           height: 31px;
           margin-left: -310px;
           margin-top: -40px;
           z-index:-1;
       }
    }

    Mozilla Dev Derby

    The above demo can be found as CSS3 up and running! in Mozilla’s Demo Studio.

    Some time later, Deivid Marques did his Planeta Terra demo, using only one DIV. While studying CSS3, the idea of creating a planet Earth also came to his mind. He noticed the example in a flash tutorial and thought of creating that with CSS3 instead.

    His planet Earth is made of a single div and uses the CSS to animate the background image. So, it is simpler to reproduce and understand.

    The div has the following CSS applied to it:

    .earth{
        background: url(images/terra.jpg) repeat-x 0 0;
        border: 1px solid rgba(26,18,101,0.3);
        border-radius: 225px;
        box-shadow: -8px 0 25px rgba(256,256,256,0.3), -1px -2px 14px rgba(256,256,256,0.5) inset;
        height: 450px;
        left: 50%;
        margin: -225px 0 0 -225px;
        position: absolute;
        top: 50%;
        width: 450px;
        animation: loop 80s linear infinite;
    }

    And here is his animation definition in CSS3:

    @keyframes loop {
        0% { background-position: 0 0; }
        100%{ background-position: -900px 0;}
    }

    His demo was also posted to Mozilla Dev Derby once he was also inspired to tell the world about he had learnt while developing this demo! Planeta Terra is also available on GitHub.

    This is how we both met and were invited to write this article.

    Conclusion

    It was great for me to learn new things, face new challenges, talk to a lot of people about their experiences with it, and …well, lots and lots of gains, no losses!

    I hope it has motivated you somehow, to create your own demo, submit it…the least you get, is a lot of fun! :)

  4. The making of a hack – Media Query Mario

    Like any developer, I love any shiny new tech demo that finds its way into my browser; some of the things people are putting together absolutely blows my mind with the level of creativity and technical skill on show.

    After attending WebDevConf 2012 in mid October, I felt the usual heightened sense of inspiration that a good conference gives us all. On my way back to London, I happened to see a tweet about the current Mozilla Dev Derby in my Twitter stream and, still inspired, thought about creating something to enter myself. That something turned into a tech demo called Media Query Mario; a mash up of Media Queries, CSS3 Animations and HTML5 audio.

    Where to start?

    Thinking of the idea came as a result of which new technologies I wanted to experiment with the most at the time. I had been meaning to delve into CSS animation for some time and combining this with media queries – the focus of that months Dev Derby – seemed pretty logical. Letting the CSS fire off the animations instead of needing JavaScript to do this seemed like a very natural fit.

    Choosing Mario 3 for the animation was simply the first thing that popped into my head. I wanted the animation to be a side scrolling 2D affair and being a retro game nerd, Mario instantly came to mind. Anyone with more than a fleeting interest in 2D Mario games would then see that Mario 3 was the only real choice for my animation (although I’m free to argue against any opposing opinions on the ‘best’ 2D Mario game anytime!)

    One question I’ve been asked since putting the demo out is: why choose CSS animations when other technologies may have been more suitable? The main reason is that I simply wanted to see what they could do. There are plenty of demos showcasing just how awesome canvas and SVG are; my demo is by no means meant to advocate the use of CSS animations over those technologies. I just wanted to give a decent benchmark of where CSS animation is at right now, and at least add them to the conversation when people are choosing which technology is right for their project.

    There was only one rule I set myself when starting to put together the demo – I wanted to stick rigidly to animating using CSS wherever possible. If it was possible to do something in CSS, I wanted to use it, irrespective of performance or how fiddly it was to implement. I’ll come back to how I think it performed in retrospect later.

    Push any button to start

    One of the earliest issues I came up against was knowing what width the user would be viewing the animation at. This was not only important in terms of what size to design the animation to, but especially in terms of how much of the level was on show at any one time. The more of the level on show, the more I would need to animate at any one time.

    After a little thought around how Mario 3 itself was presented, it made sense to make use of the original menu screen to help control this. As well as acting as a holding screen while the animation assets loaded, it would ensure the user resized their browser window down to a dimension I could specify, before then allowing the animation to be started. This was controlled by adding a conditional media query hiding the animation start button:

    @media screen and (max-width: 320px), (min-width: 440px) {
        .startBtn {
            display:none;
        }
    }

    Planning the actual animation itself, I wanted to mirror the way the original game would have been played as much as possible. To help with this I found a video clip that traversed through the level at a pace that I could replicate. This helped me plan the image and sound assets I would need, the speed of the animation and started the thinking around how to animate different enemies and power-ups throughout the level.

    With the structure of the demo planned out, I now just needed the assets. As you might expect, you don’t have to search for too long online to find original game images, sprites and sound files. For my demo, I used NESmaps and Mario Mayhem for the level map and character/object sprites and The Mushroom Kingdom for the sound files. I had to do a small amount of image editing myself, but these gave me a really great start.

    You can view the final spritesheet I used for the animation below.

    Letsa Go!

    So I had an idea planned out and had found my assets; I was ready to start putting it all together in code.

    First, I set about learning the specifics of CSS3 animations. A couple of resources really helped me out; MDN is always a great place to start and is no exception for CSS animations. I would also recommend any of these great articles by Peter, Chris or David – all provide an excellent introduction to getting started with CSS3 animations.

    I won’t look to replicate the depth those articles cover, but will highlight the key properties I made use of in the demo. For brevity, I’ll be covering the CSS3 syntax unprefixed, but if trying any of this out for yourself, prefixes should be included in your code to ensure the animations work across different browsers.

    A quick development tip worth mentioning when using newer CSS3 features such as CSS animations, is that using a preprocessor, such as LESS or SASS, is a massive lifesaver and something I’d highly recommend. Creating mixins that abstract the vendor prefixes out of the code you are directly working with helps keep visual clutter down when writing the code, as well as saving a whole load of time when changing CSS property values down the line.

    Before we get into specific techniques used in the demo, we need to understand that an animation consists of two main parts; the animation’s properties and its related keyframes.

    Animation Properties

    An animation can be built up with a number of related properties. The key properties I made use of were:

    //set the name of the animation, which directly relates to a set of keyframes
    animation-name: mario-jump;
     
    //the amount of time the animation will run for, in milliseconds or seconds
    animation-duration: 500ms;
     
    //how the animation progresses over the specified duration (i.e. ease or linear) 
    animation-timing-function: ease-in-out;
     
    //how long the animation should wait before starting, in milliseconds or seconds
    animation-delay: 0s;
     
    //how many times the animation should execute
    animation-iteration-count: 1;
     
    //if and when the animation should apply the rendered styles to the element being animated
    animation-fill-mode: forwards;

    The use of the animation-fill-mode property was especially important in the demo, as it was used to tell the animation to apply the final rendered styles to the element once the animation had finished executing. Without this, the element would revert to it’s pre-animated state.

    So for example, when animating an element’s left position 30 pixels from an initial position of 0px, if no animation-fill-mode is set, the element will return to 0px after animating. If the fill-mode is set to forwards the element will stay positioned at its final position of left: 30px.

    Keyframes

    The Keyframes at-rule lets you specify the steps in a CSS animation. At its most basic level this could be defined as:

    @keyframes mario-move {
        from { left:0px;   }
        to   { left:200px; }
    }

    Where from and to are keywords for 0% and 100% of the animation duration respectively. To show a more complex example we can also code something like this, which, relating back to the demo, animates Mario jumping between several platforms using multiple keyframes:

    @keyframes mario-jump-sequence {
        0% { bottom:30px; left: 445px; }
        20% { bottom:171px; left: 520px; }
        30% { bottom:138px; left: 544px; }
        32% { bottom:138px; left: 544px; }
        47% { bottom:228px; left: 550px; }
        62% { bottom:138px; left: 550px; }
        64% { bottom:138px; left: 550px; }
        76% { bottom:233px; left: 580px; }
        80% { bottom:253px; left: 590px; }
        84% { bottom:273px; left: 585px; }
        90% { bottom:293px; left: 570px; }
        100% { bottom:293px; left: 570px; }
    }

    So if the above animation was 1 second long, Mario would move from position bottom: 30px; left: 445px; at 0 seconds (0% through the animation) to bottom: 138px; left: 520px; during the first 200ms (or 20%) of your animation. This carries on like this throughout the keyframes defined.

    Animating the action

    Considering the above, the type of animations I created in the demo can be broken down into 3 broad categories:

    • Movement such as Mario jumping or a coin appearing out of a question box.
    • Spriting controls the background-image position of characters and objects in the animation.
    • Looping any animation that is to be repeated for x number of milliseconds or seconds.

    Movement

    Movement covers roughly 75% of all of the animations in the demo. For example, this includes character movement (i.e. Mario running and jumping), power-ups appearing and question boxes being hit. What makes each movement animation differ is the animation-timing-function, the animation-duration and the animation-delay properties.

    The animation-timing-function property helps control the speed of the animation over its duration. Wherever possible I used easing, such as ease-in or ease-in-out to save having to be too precise when defining animation keyframes. Where this didn’t create the effect I needed, I resorted to setting the animation-timing-function to linear and using the keyframes to specify the exact movement I required.

    An example a movement animation can be seen by this jump sequence.

    Spriting

    To control the image background-position of the characters and objects in the animation, I used the step-end timing-function:

    .mario {
        animation-timing-function: step-end;
        ...
    }

    Initially, I thought I may need to use JavaScript to control the image spriting by adding and removing classes to my elements. However, after experimenting with how the step-end timing keyword was implemented, I found it perfectly stepped through the keyframes I had defined, one keyframe at a time.

    To show this in action, take a look at the following examples, which show a simple Mario walking animation and Mario transforming after grabbing a power-up.

    Using step-end in this way wasn’t completely pain free however. To my frustration, when these sprite animations were stacked up over multiple media queries, I found that there was a glitch in WebKit that caused the animation to render differently to the keyframes I had defined. Admittedly, the use of CSS animations in this way is an edge case for browser rendering, but I have filed it as a bug in Chromium, and am hopeful this will be looked at in the future and ironed out.

    LOOPING

    Whenever an animation needed to be repeated over a period of time, looping was defined by adjusting the animation-iteration-count:

    //the animation repeats 5 times
    animation-iteration-count: 5;
     
    //the animation repeats infinitely
    animation-iteration-count: infinite;

    An example of this from the demo would be the rotation of the fireball].

    Through these 3 types of animation, the whole demo was constructed. The final layer was to add in the audio.

    Adding Audio

    Although I had previously downloaded all of the sound files I needed in .wav format, I had to convert them into a format that was usable with HTML5 audio; .ogg and .mp3. I used Switch Audio Convertor (on Mac) to do this, but any good audio conversion software should do the job.

    Once I had the converted files, I needed to detect which file type to serve to the browser. This required a couple of lines of JavaScript to detect support:

    var audio = new Audio(); //define generic audio object for testing
    var canPlayOgg = !!audio.canPlayType && audio.canPlayType('audio/ogg; codecs="vorbis"') !== "";
    var canPlayMP3 = !!audio.canPlayType && audio.canPlayType('audio/mp3') !== "";

    I then created a function to set some default audio parameters for each sound, as well as setting the source file based on the format previously detected to be supported by the browser:

    //generic function to create all new audio elements, with preload
    function createAudio (audioFile, loopSet) {
        var tempAudio = new Audio();
        var audioExt;
     
        //based on the previous detection set our supported format extension
        if (canPlayMP3) {
            audioExt = '.mp3';
        } else if (canPlayOgg) {
            audioExt = '.ogg';
        }
     
        tempAudio.setAttribute('src', audioFile + audioExt); //set the source file
        tempAudio.preload = 'auto'; //preload the sound file so it is ready to play
     
        //set whether the sound file would loop or not
        //looping was used for the animations background music
        tempAudio.loop = (loopSet === true ? true : false);
     
        return tempAudio;
    }
    var audioMarioJump = createAudio("soundboard/smb3_jump"); //an example call to the above function

    It was then just a case of playing the sound at the correct time in sync with the animation. To do this, I needed to use JavaScript to listen for the animation events animationstart and animationend – or in WebKit, webkitAnimationStart and webkitAnimationEnd. This allowed me to listen to when my defined animations were starting or ending and trigger the relevant sound to play.

    When an event listener is fired, the event returns the animationName property, which we can use as an identifier to play the relevant sound:

    mario.addEventListener('animationstart', marioEventListener);
     
    function marioEventListener(e) {
        if (e.animationName === 'mario-jump') {
            audioMarioJump.play();
        }
    }

    If you have multiple animationstart events for one element, such as Mario in my demo, you can use a switch statement to handle the animationName that has triggered the event listener.

    Since writing the demo, I have found that you can also target individual keyframes in an animation by using the Keyframe Event JS shim by Joe Lambert, which gives you even more control over when you can hook into your animation.

    Game Complete

    The response to the demo has been more positive than I’d ever hoped for since it was released. Like any hack, there are things I’d like to go back and improve with more time, but I think it’s more valuable to put what I learned into my next project. I think that the demo has shown that CSS animations can be used to create some amazing effects from fairly simple code, but also brought one bigger issue to my mind while putting it together.

    While complex CSS animations actually perform very well, the creation of such an animation is fairly longwinded. Sure, there are tools out there designed to help with this, such as Adobe Edge Animate and Sencha Animator, but both of these output CSS animations wrapped up in JavaScript. This seems a massive shame to me, as the power of CSS animations is surely in the fact that they shouldn’t have to rely on another technology to execute. I’m not sure if there is a potential way around this, other than coding it by hand yourself, but if anyone knows of any I’d be interested to hear of them in the comments.

    Going back to my earlier comment about comparing CSS animations to using canvas and SVG, I think all have a place at the table when discussing what technology to use for animation. However, the sooner the barrier of time spent to craft complex animations like this one can be lowered, the more relevance, and potential use cases, CSS animations will have in the projects that we do.

  5. Popcorn Maker 1.0 released – how it works

    This week Mozilla is in London at the Mozilla Festival 2012. A year ago at last year’s Festival, we released Popcorn.js 1.0, and with it a way for filmmakers, journalists, artists, and bloggers to integrate audio and video into web experiences. Popcorn has since become one of the most popular ways to build time-based media experiences for the web. It has proven to be uniquely powerful for bespoke web demos, films, visualizations, etc. This year, we’ve come to the Mozilla Festival with an even bigger 1.0 release: Popcorn Maker 1.0.

    Popcorn.js and Popcorn Maker

    With Popcorn.js, and its plugin ecosystem, we created a tool for developers. Popcorn lets developers work dynamically using timing information from web media, using a simple API and plugin system. With Popcorn Maker we wanted to go further and give this same power to bloggers, educators, remixers, and artists — web makers.

    At its core, Popcorn Maker is an HTML5 web app for combining web media with images, text, maps, and other dynamic web content. Its appearance is unique, but not unfamiliar, providing a timeline-based video editing experience for the web. Once created, Popcorn Maker hosts remixes as simple HTML pages in the cloud, which can be shared or embedded in blogs or other sites. Furthermore, every remix provides a “Remix” button, allowing anyone watching to become a creator themselves by using the current remix as a base project for their own creation. This “view source” experience for web media is a key aspect of Popcorn Maker’s goals as part of the larger Mozilla Webmaker project.

    On a technical level, Popcorn Maker is the combination of a number of separate projects, each heavily influenced by the “12 factor” philosophy: a node.js-based web service called Cornfield; a JavaScript framework for creating highly-interactive web apps; and Popcorn.js, with a set of custom Popcorn.js plugins.

    Coming from Butter

    When we first started we thought we’d create a simple library named Butter, and that Popcorn Maker would be injectable — something you would add to existing web pages, like a toolbar. Many of the original ideas for Popcorn Maker were taken from an early prototype created by Rick Waldron, Boaz Sender, and Al MacDonald of Bocoup. Over time these ideas evolved, Seneca College and CDOT got involved — bringing their heavy experience with web media and Pocorn.js — and more prototypes ensued. Soon it became clear that what was really needed was a full web app: an infrastructure including client, server, and a community.

    This realization occurred as the Popcorn Maker team continued to grow. More developers joined our team some of whom brought much-needed design experience with them. Ocupop was consulted to enhance the design of the project, and gave us the same expertise that was used to produce the branding for HTML5.

    Using LESS for CSS

    Thanks to talented designer-hacker hybrids like Kate Hudson, Popcorn Maker’s design became modern and responsive. We worked with her to integrate LESS — a dynamic stylesheet language which compiles to CSS. LESS made challenges like cross-browser compatibility — something key to Popcorn Maker’s goals — less painful. It also allowed much more flexibility for a rapid prototype approach to our UI. Consequently, a significant amount of our CSS is constructed in functions and stored in variables, both of which are included in files throughout our style implementation. We can make changes that let us try new approaches very quickly, touching and creating as little boilerplate CSS as possible.

    Popcorn Media Wrappers

    Of course, in order to complete the features we desired, we needed to extend Popcorn.js with new features. One such feature is Popcorn Media Wrappers, which wrap non-HTML5 media with an interface and set of behaviours that allow them to be used exactly like HTML5 video and audio elements. By building wrappers for YouTube, Vimeo, and SoundCloud, we were able to standardize all our media code on the HTML5 media interface. More wrappers are in production, allowing more types of media to be included in future releases, and the current wrappers will ship as part of Popcorn.js 1.4 later this year.

    Evolving into a modern tool

    Eventually, Butter and its constituents allowed us to present a full-featured, responsive, end-user tool using nothing more than HTML, CSS, and JavaScript. Currently, Butter uses a modular development environment provided by require.js, and provides a UI toolkit with widgets that were used to build the timeline, scrubber, editors, dialogs and more. In cooperation with require.js’ text plugin, Document Fragments are used to allowed us to build all of our UI in static HTML, and load and render it dynamically at runtime. This approach lets us treat our HTML as it was meant to be treated (i.e., as layout), but also include it in our source tree to be referenced and linted like anything else.

    While building Butter was a large part of the execution of our app, it comprises only a portion of Popcorn Maker. Cornfield, Popcorn Maker’s server, allows users to save and publish their content, completing the Popcorn universe. It uses node.js, Express, Jade templates, and Amazon S3 to provide a RESTful API and hosting environment for Butter. To avoid the thorny issue of user authentication and credential management, Cornfield leverages Mozilla Persona. During development, attempting to use Persona exposed the need to build the express-persona node module to help make Persona work more easily in Express.

    Based on community input

    The Popcorn Maker team owes a great deal of gratitude to its community and users. Their feedback heavily influenced the direction of Popcorn Maker. The most successful and compelling Popcorn.js demos we saw used the video as a canvas, on which to place pieces of the web dynamically. Further, we found that our users wanted to embed their projects — not just host them. These insights were instrumental in moving our focus to creating embeddable content, rather than full-page content.

    Gathering feedback from our users also influenced our development. In Popcorn Maker we’ve experimented with user feedback collection and JavaScript crash reporting, both built directly into the web app. The app’s Feedback button lets users submit general feedback, which is then stored as JSON in S3. Through such feedback we’ve been able to get valuable information about issues users have encountered and ideas for new features.

    JavaScript crash reports

    Even more significant has been our experiment with JavaScript crash reports. This technique is used to great effect with Mozilla’s native development, for products like Firefox and it s crash stats. However, this technique is not often applied to JavaScript web apps. We use window.onerror to detect top-level exceptions being thrown in our code, and present the user with a dialog to allow them to submit an anonymous report, optionally with details about what they encountered. We log various types of edge cases (e.g., null node access in the DOM by wrapping DOM methods) and send this data with the report. This has been an incredible source of data for our team. Since our 0.9 release for the TED talk release we’ve fixed more than a dozen crash bugs, almost all of which our developers were never able to hit locally.

    Influenced by other Mozilla projects

    The development of Popcorn Maker was also heavily influenced by processes used on other Mozilla projects. In particular an emphasis on automation, tooling, and open source best practices. We accelerated our development by using linting in all of our code, from JavaScript (jshint), to CSS (csslint), to HTML, where we created a client-server solution based on the HTML5 parser. We use many automation systems, from botio, to TravisCI, to Jenkins to run our tests and help us trust the rapid pace of code changes. Most importantly, we also employed a two-stage code review process, similar to Firefox’s Peer-Review and Super-Review. By having every patch reviewed twice, we not only reduced regressions, but also helped grow our developer team by ensuring that multiple people understood every change.

    Popcorn Maker has already touched a large community and is the result of the hard work and collective influence of a growing team of dedicated developers, thinkers, and increasingly active community members. We’re incredibly proud to be releasing a year’s worth of work today with the 1.0 launch. The only question left is what you’ll make with it – https://popcorn.webmaker.org!

    More information on the code and development process

    For more info about the code and development team/process:

    Repositories

    Bug Tracker

    https://webmademovies.lighthouseapp.com/projects/65733-butter/overview

    IRC

    irc://irc.mozilla.org/popcorn

    Twitter

    @popcornjs

    Instances