Mozilla

Articles by Chris Heilmann

Sort by:

View:

  1. 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

  2. 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:

  3. Accelerating the overall web experience – Mozilla at Velocity Europe

    This year’s Velocity EU conference had a special presentation round where browser makers talked about the performance of their specific products. I was invited last minute to represent Firefox and originally was asked to show benchmarks, impressive demos and how we compare to others. As browsers get released in very short intervals these days, this doesn’t quite make sense any longer – at least to me.

    Funnily enough the other browser representatives took the same approach so I was happy to see that we agreed that we are beyond number-comparisons and head to head browser war on performance.

    My talk “Accelerating the overall web experience” covered other things, like that the choice of which browser to use lies with the users and there is not much we can do to change that. I also pointed out that users will find a way to make our browsers slow, no matter how hard we try and that in a lot of cases third party add-ons and debugging tools are to blame for an impression of slowness.

    I ended by showing how the new developer tools in Firefox empower developers to perform much better in finding bugs and fixing them – a part of performance that is not easily measurable but very important.

    You can see the slides here (left+right to go back and forward, down for next bullet point and N to toggle notes) or read them as an HTML page:

    There is also an audio recording of the talk on archive.org:

    All in all it was good to see that all browsers are getting faster and faster and we all see this as a given rather than a goal.

  4. Esteban, Saqib and Craig – three lucky people to join Mozilla at Full frontal

    A day ago or so we asked who wants to come to Full Frontal with us, and a few people have given good reasons. We used state of the art algorithms also used in social media impact products (Math.random) to pick the lucky winners. And they are:

    • Esteban Saiz who will also join us the speaker dinner
    • Saqib Shaikh
    • Craig Moore

    See you all at Full Frontal!

  5. Want to go to Full Frontal in Brighton, England this Friday? We got tickets!

    photo by Lily

    Full Frontal is a JavaScript centric conference in Brighton, England on the 11/11/11. The simplest way to describe it is “a splendid kick into your lower back side” event when it comes to what’s hot and amazing int he world of scripting.

    The Mozilla Developer Network has 3 tickets to give out, one of which also entitles you to attend the speakers dinner the day before the conference. Tickets for the conference are gone, so here is your last chance.

    If you want to take part in this, you need to be able to get to Brighton, England on the 11th and be open to also come on the 10th for the speaker’s dinner (one of you). Please say if you can’t come on the 10th – you can still win a ticket. We will need your name for the organisers to put on the list.

    First and foremost though, in order to win a ticket add a comment here why you deserve to get a Mozilla ticket and what you can do as a thank you to help the open web.

    The best reasons and offers will get the tickets. We will announce the pick on the 9th here and contact you so please leave a valid email in the comment (this will not be shown to the public).

    For extra brownie points, why not tell us what new initiatives of Mozilla get you most excited and what we could be doing to make them a reality faster.

    See you in Brighton, it rocks!

    We picked the winners, now! Let’s get full frontal!

  6. Beam me up, Scotty – bringing HTML5 to the enterprise

    The last few days I was busy talking to in-house developers at two large enterprise companies, Sabre in Poland and SAP in Germany. Both these companies approached us asking for a talk about HTML5 as the topic gets a lot of interest in the upper echelons and there is a lot of confusion about it.

    As we were in Poland anyways to attend Frontrow it was easy to visit Sabre and give a one hour presentation on the ins and outs of HTML5 and where the web might go. The day after the same talk was repeated over Skype for the German office of SAP.

    In the one hour presentation we covered:

    • the basics of HTML5
    • what it meant as an evolution of markup
    • what HTML5 is not
    • common HTML5 myths
    • “Friends of HTML5″ – related technologies and
    • what the future of web technologies could look like

    The slides are available online or embedded below (cursor keys to navigate, press N to show and hide notes and cursor down to proceed on slides with bullet points):

    The audio recording of the talk is available on archive.org.

    The slides and the audio is licensed with Creative Commons, so feel free to re-use and distribute them.

  7. 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!

  8. HTML5 live: Rocking the boat – and causing a ripple

    Today was the HTML5 live conference in London, England. In this one day conference around 150 attendees learned the why of HTML5, and how to implement it in the current work environment.

    As Mozilla’s representative I was asked to give a talk on how we are faring as a movement when it comes to HTML5. In the talk Rocking the boat – and causing a ripple I discussed the necessity to take HTML5 away from something to build cool demos in to be used in day to day products so we can find and report bugs. I also covered a few of the issues that are cropping up like “best viewed with browser X” products and trying to impress users by listing the technologies used rather than just using them to improve the overall experience. In the end we also list some of the new technologies and products Mozilla is working on to make the web a real application platform that has the same access that native applications have.

    The slides are embedded below and use a modified DZSlides as the system. Focus on them and use the cursor keys to navigate. Display bullet points by pressing space and show and hide the notes by pressing N. Alternatively you can also see the slides a simple web page.

    The audio recording of the talk is available at archive.org

  9. 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.

  10. Geolocation explained – a quick screencast

    If you’ve been here last week, you might have seen the webinar and geolocation Q&A with Remy Sharp. Sadly enough, we had a problem recording the screen so we recorded this replacement screencast yesterday night to give you a quick introduction to the Geolocation API.

    Once you are up to speed (or refreshed your memory) why not go and build something for this month’s Developer Derby?

    You can see the video on any HTML5 enabled device here (courtesy of vid.ly).