1. Screencast: 3D CSS rollovers and 3D CSS tester

    CSS 3D transforms as supported in the latest Aurora allow us to do some nice effects that in the past were only possible in Flash or with a lot of trickery using skewing and filters. I was asked to show a small demo the other day and thought it would be fun to spice up the classic image rollover:

    You can see this in action using Chrome, Safari or Firefox Aurora/Nightly. Older browsers should just show a normal roll-over (and yes, the first example looks weird due to the logo transparency but it makes the effect much cooler in supporting browsers).

    As people asked how this is done I thought it easiest to create a testing tool where you can play with 3D CSS yourself. Here’s a screencast where I explain how to use it and how the roll-over effects were done.

    I found a few interesting bugs while creating this and will file them now. This is the benefit of playing with new tech. Enjoy!

    More reading on this:

  2. Congrats to our October Dev Derby winners!

    Responsive design is more important than ever as people experience the Web on a variety of devices. Web developers can now take advantage of CSS Media Queries to build sites and applications that can be viewed on different screen sizes. So we decided to focus on that for the October Dev Derby.

    For this challenge, developers submitted 15 demos to show what you can do with CSS Media Queries. Check them out so see how they present unique styles and layouts in response to changes in viewing area.

    It was a fairly close race, so join us in congratulating the winners circle:
    October Dev Derby winners - CSS Media Queries

    1st Place: CSS3 Cherry Blossom – Media queries by elufo
    2nd Place: Santa’s Media Queries by tuxie
    3rd Place: Too many fish is the sea by michal.b

    Runners-up:
    Responsive 3D-Models For Any Device
    Spriting with CSS Media Queries

    Thanks to everyone that participated in the October Dev Derby! Only a couple of days left to participate in the November Dev Derby, so get your Canvas demos in now. Otherwise, start experimenting with IndexedDB for December.

    NOTE: We recently updated our Dev Derby rules to allow developers to participate in multiple contests until they win 1st place. That means if you’ve submitted awesome demos and come up short in the past, you still have a chance to win that top spot in future Dev Derbies… so keep those demos coming!

  3. Firefox – tons of tools for web developers!

    One of the goals of Firefox have always been to make the lives of web developers as easy and productive as possible, by providing tools and a very extensible web browser to enable people to create amazing things. The idea here is to list a lot of the tools and options available to you as web developers using Firefox.

    Continued…

  4. HTML5 context menus in Firefox (Screencast and Code)

    You may not know it, but the HTML5 specifications go beyond what we put in the pages and also define how parts of the browser should become available to developers with HTML, CSS and JavaScript. One of these parts of the specs are context menus, or “right click menus”. Using HTML5 and a menu element you can add new options to these without having to write a browser add-on. In Firefox 8 (the current one) we have support for those. See the following screencast for a context menu demo.

    The image example is pretty simple and was actually written by Paul Rouget as a demo in the original Firefox bug request. The main core is the HTML of it:

    <section id="noninteractive" contextmenu="imagemenu">
     
      <img src="html5.png" alt="HTML5" id="menudemo">
     
        <menu type="context" id="imagemenu">
          <menuitem label="rotate" onclick="rotate()"
                    icon="arrow_rotate_clockwise.png">
          </menuitem>
          <menuitem label="resize" onclick="resize()"
                    icon="image-resize.png">
          </menuitem>
          <menu label="share">
            <menuitem label="twitter" onclick="alert('not yet')"></menuitem>
            <menuitem label="facebook" onclick="alert('not yet')"></menuitem>
          </menu>
        </menu>
     
    </section>

    As you can see you link the menu element to an element via its ID. The contextmenu attribute then points to this one. Each menu can have several menuitems. Each of those gets a textual label and a possible icon. You can also nest menu elements to create multiple layer menus. Here, we add inline onclick handlers to point to different JavaScript functions to call when the menu item gets activated. The resulting context menu looks like this:

    image with a context menu

    The functionality is simple, all the rotate() and resize() functions do is add class names to the image using querySelector and classList:

    function rotate() {
      document.querySelector('#menudemo').classList.toggle('rotate'); 
    }
    function resize() {   
      document.querySelector('#menudemo').classList.toggle('resize'); 
    }

    The real effect is in CSS transforms and transitions. As the image has an ID of menudemo here is what is needed in CSS to rotate and resize:

    #menudemo { 
      -moz-transition: 0.2s; 
      width:200px;
    }
    #menudemo.rotate { 
      -moz-transform: rotate(90deg); 
    }
    #menudemo.resize { 
      -moz-transform: scale(0.7); 
    }
    #menudemo.resize.rotate { 
      -moz-transform: scale(0.7) rotate(90deg); 
    }

    Notice that in a real product we should of course add the other browser prefixes and go prefix-less but as the functionality now only works in Firefox, this is enough for this demo.

    Detecting support and visual hinting

    Now, as this is extending the normal user offerings in the browser we need to make it obvious that there is a right-click menu available. In CSS3, there is a context-menu cursor available to us. When context menus are available, this should be shown:

    .contextmenu #menudemo, .contextmenu .demo {
      cursor: context-menu;
    }

    We test the browser for support by checking for contextmenu on the body element and for HTMLMenuItemElement in the window (this has been added as a pull request to Modernizr, too).

    if ('contextMenu' in document.body && 'HTMLMenuItemElement' in window) {
      document.documentElement.classList.add('contextmenu');
    } else {
      return;
    }

    Wouldn’t HTMLMenuItemElement be enough? Yes, but a real context menu should only offer functionality when it is sensible, and that is where contextMenu comes in.

    Turning menuitems on and off depending on functionality

    As a slightly more complex example, let’s add a “count words” functionality to the document. For this, we generate a counter element that will become a tooltip when the words were counted:

    var counter = document.createElement('span');
    counter.id = 'counter';
    counter.className = 'hide';
    document.body.appendChild(counter);
     
    counter.addEventListener('click', function(ev){
      this.className = 'hide';
    },false);

    This one is hidden by default and becomes visible when the hide class is removed. To make it smooth, we use a transition:

    #counter{
      position: absolute;
      background: rgba(0,0,0,0.7);
      padding:.5em 1em;
      color: #fff;
      font-weight:bold;
      border-radius: 5px;
      -moz-transition: opacity 0.4s;
    }
    #counter.hide{
      opacity: 0;
    }

    We start with two sections with context menus:

    <section id="noninteractive" contextmenu="countmenu">
      <menu type="context" id="countmenu">
          <menuitem class="wordcount" label="count words"></menuitem>
      </menu>
    </section>
     
    <section id="interactive" contextmenu="countmenuinteractive">
      <menu type="context" id="countmenuinteractive">
          <menuitem class="wordcount" label="count words"></menuitem>
      </menu>
    </section>

    We then loop through all the menuitems with the class wordcount and apply the functionality.

    var wordcountmenus = document.querySelectorAll('.wordcount'),
        i = wordcountmenus.length;
     
    while (i--) {
      wordcountmenus[i].addEventListener('click', function(ev){
        // add functionality 
      }, false);
    }

    We need to find out what has been selected in the page. We do this by using getSelection() and splitting its string version at whitespace. We then show the counter by removing the hide class name.

    var wordcountmenus = document.querySelectorAll('.wordcount'),
        i = wordcountmenus.length;
     
    while (i--) {
      wordcountmenus[i].addEventListener('click', function(ev){
        var text = document.getSelection(),
            count = text.toString().split(/\s/).length;
        counter.innerHTML = count + ' words';
        counter.className = '';
      }, false);
    }

    You can see this in action in the second context menu demo. Now, the issue with this (as explained in the screencast) is that it always counts the words, regardless of the user having selected some text. What we want is the menu only to be active when there is text selected.

    context menu item available or not available depending on selection

    So in order to make our menu only become available when it makes sense we check if there is a selection in the document. Every context menu fires an event called contextmenu when it opens. So all we need to do is to subscribe to this event.

    When something is selected in the document document.getSelection().isCollapsed is true. Otherwise it is false, so all we need to do is to enable or disable the menu item accordingly:

    document.querySelector('#interactive').addEventListener(
      'contextmenu', function(ev) {
        this.querySelector('.wordcount').disabled =
        document.getSelection().isCollapsed;  
      },
    false);

    The last thing to solve is the position of the mouse to position the counter element. As the menu selection event doesn’t give us the mouse position we need to add a contextmenu handler to the whole document that positions the counter invisibly behind the menu when it is opened:

    document.body.addEventListener(
      'contextmenu', function(ev) {
        counter.style.left = ev.pageX + 'px';
        counter.style.top = ev.pageY + 'px';
        counter.className = 'hide';
      }, 
    false);

    Further reading and resources

  5. Screencast: CSS 3D rollover with fallback for older browsers

    Here’s a quick screencast how to create a 3D image rollover and still give a useful interface to browsers that do not support 3D transforms. If you want to see the effect in Firefox get the latest Aurora or Nightly. Check the following video to see what it looks like (first with a browser without CSS 3D transport, then with a newer one):

    The screencast is on YouTube:

    The main procedure to achieve the effect is simple. First we need a semantically valuable way to show these images, in our case a HTML list with figures and figcaptions. Notice that images still need an alternative text as the figcaption can apply to several images:

    <ul>
      <li class="image3d">
        <figure>
          <img src="mittens.jpg" alt="Mittens the cat">
          <figcaption>
            <p>
              <strong>Mittens</strong> loves to play with yarn and stuff.
            </p>
          </figcaption>
        </figure>
      </li>
    <!-- repeated -->
    </ul>

    We then position the caption absolutely inside the list item, give the list item dimensions and an overflow of hidden and move the caption outside of the visible space. When the user hovers over the list item (or focuses it with a keyboard) we move the caption to the right place and lower the opacity of the image.

    .positioned {
      list-style: none;
      width: 300px;
      height: 200px;
      position: relative;
    }
    .positioned figcaption {
      position: absolute;
      background: rgba( 0, 0, 0, 0.7 );
      color: #fff;
      border-radius: 5px;
      left: 65px;
      bottom: 10px;
      width: 230px;
    }
    .positioned img {
      opacity:0.4 ;    
    }
    .positioned figcaption strong {
      display: block;
      color: lime;
      font-weight: normal;
      font-size:22px;
      padding: 5px 0;
    }
    .positioned figcaption p {
      display: block;
      color: white;
      padding: 5px;
    }
    .interactive {
      overflow: hidden;
    }
    .interactive img {
      opacity: 1;
    }
    .interactive figcaption {
      left: 300px;
    }  
    .interactive:hover img, .interactive:focus img {
      opacity: 0.4;
    }
    .interactive:hover figcaption, .interactive:focus figcaption {
      left: 75px;
    }

    We make the effect smooth by adding transitions. Notice that it makes sense to list all the browser prefixes and set a prefix-less fallback. That way we don’t need to re-write code when a new browser supports them.

    .smooth img {
      -webkit-transition: all 1s;
      -moz-transition:    all 1s;
      -o-transition:      all 1s;
      -ms-transition:     all 1s;
      transition:         all 1s;
    }
    .smooth figcaption {
      -webkit-transition: all 1s;
      -moz-transition:    all 1s;
      -ms-transition:     all 1s;
      -o-transition:      all 1s;
      transition:         all 1s;
    }

    In order to rotate the kitty in 3D space, we need to give the list item a perspective and rotate the image and shift it in 3D space with translate3D to avoid clipping:

    .threed {
      -webkit-perspective: 800px;
      -moz-perspective:    800px;
      -ms-perspective:     800px;
      -o-perspective:      800px;
      perspective:         800px;
    }
    .threed:hover img, .threed:focus img {
      -webkit-transform: rotateY( 50deg ) rotateX( 10deg )
                         translate3d( 80px, -20px, -100px );
      -moz-transform:    rotateY( 50deg ) rotateX( 10deg )
                         translate3d( 80px, -20px, -100px );
      -o-transform:      rotateY( 50deg ) rotateX( 10deg )
                         translate3d( 80px, -20px, -100px );
      -ms-transform:     rotateY( 50deg ) rotateX( 10deg )
                         translate3d( 80px, -20px, -100px );
      transform:         rotateY( 50deg ) rotateX( 10deg )
                         translate3d( 80px, -20px, -100px );
    }

    That’s it. By adding all the browser prefixes, falling back to a simple rollover and by making sure you do the effect on hover and on focus you support all the browsers and bring the cool to the newest ones.

    More reading and resources:

  6. CSS 3D transformations in Firefox Nightly

    When the first 3D transformations in CSS got support on Webkit browsers people got incredibly excited about them. Now that they have matured we also support 3D CSS in Firefox. To see it for yourself, check out one of the latest nightly builds.

    You can see them in action in this demo of a rotating HTML5 logo and the screencast below:

    This means now that we need your support in trying out CSS 3D examples in Firefox and add other extensions than -webkit- to your CSS 3D products and demos. To show that this is possible, we took the well-known webkit-only “poster circle” demo and made it work with Firefox nightly by adding the -moz- (and of course the other prefixes and one set of instructions without browser prefixes). Here is a slight excerpt:

    -webkit-transform-style: preserve-3d;
    -moz-transform-style: preserve-3d;
    -o-transform-style: preserve-3d;
    -ms-transform-style: preserve-3d;
    transform-style: preserve-3d;

    You can see this in action in the screencast below alongside Chrome and you try the demo out yourself. The slight jerkiness is actually my MacBook Air impersonating a starting jet every time I use ScreenFlow and not the browser.

    To celebrate the release and to show how CSS 3D can be applied as subtle effect, have a game of pairs using your favourite browsers (and a cat) :

    browser pairs

    Oleg Romashin also spent some time to convert a few CSS 3D demos to work with Mozilla and you can check the 3D city for more “wow”.

    If you are new to CSS 3D transformations here’s a good beginner course and a tool to create them.

    The rotating HTML5 logo demo also shows how you can check if the currently used browser supports 3D transforms. Instead of repeating the animation frames for all the prefixes we test in JavaScript and create the CSS on the fly:

    function checksupport() {
      var props = ['perspectiveProperty', 'WebkitPerspective',
                   'MozPerspective', 'OPerspective', 'msPerspective'],
          i = 0,
          support = false;
      while (props[i]) {
        if (props[i] in form.style) {
          support = true;
          pfx = props[i].replace('Perspective','');
          pfx = pfx.toLowerCase();
          break;
        }
        i++;
      } 
      return support;
    }
    if (checksupport()) {
      var s = '';
      styles = document.createElement('style');
      s += '#stage{-'+ pfx +'-perspective: 300px;}'+
           '#logo{-'+ pfx +'-transform-style: preserve-3d;position:relative;}'+  
           '#logo.spin{-'+ pfx +'-animation: spin 3s infinite linear;}'+
           '@-'+ pfx +'-keyframes spin {'+  
           '0% {'+ 
           '-'+ pfx +'-transform: rotateX(0deg) rotateY(0deg) rotateZ(0deg);'+   
           '}'+
           '100% {'+   
           '-'+ pfx +'-transform: rotateX(0deg) rotateY(360deg)'+
           ' rotateZ(360deg);'+ 
           '}}';
      styles.innerHTML = s;
      document.querySelector('head').appendChild(styles);
    }

    For more information on creating your own pages that use 3D transformations, take a look at the draft specification

    As always, If you find any bugs, please report them at bugzilla.mozilla.org!

    So please reward our hard work bringing the third dimension to Firefox’s CSS engine by supporting and testing. Cheers!

  7. HTML5: Time for some slicker apps – a talk at Kings of Code

    The Kings of code conference in Amsterdam attracted a few hundred backend developers. Part hackday, part conference, Kings of Code spans over a few days and brings together developers from various backgrounds. The ambitious goal of the Mozilla keynote was to cover the relevant parts of HTML5 and CSS3 for this audience in 25 minutes.

    The presentation slides are available here and embedded below (use cursor keys to navigate back and forth and hit ‘n’ to show and hide the notes):

    The audio recording of the talk (raw, unedited) is available on archive.org.

    Overall the reaction was good, and we hope we managed to bust some myths and look forward to see what people do with the inspiration.