Tomorrow we will release the MDN advent calendar at http://thewebrocks.com/calendar with a daily link on a web technology product, a MDN wiki page or a great demo collected by us over the last few days. You can get a preview of how the calendar will look and work here:
As an extra bonus, we thought it would be fun to document the step-by-step development of the calendar and release it for you to re-use or get inspired by.
It is an example of how to build something server-side (so you can’t cheat by setting your operating system calendar ahead), enhance it with JavaScript and make it smooth by using CSS transitions. This should work for everybody and by playing each technology to its strengths, the code is very small indeed.
Enjoy, and see you tomorrow and the day after, and the day after that and…
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:
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:
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:
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:
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).
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:
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.
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:
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:
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><liclass="image3d"><figure><imgsrc="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.
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:
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.
BrowserID is an initiative to provide the web with a better way to sign in. The web is a connected collection of resources and you should not have to have a user name and password for each of them when you could use the web instead.
Today we show you a screencast of how easy BrowserID makes it to login to a web site. For this, we’ll look at how the login flow for an existing BrowserID user works the first time they log in on a new website. Our example website is OpenPhoto, a hot new photo sharing app that keeps users in control of their data.
Screencast of logging into OpenPhoto with BrowserID
Get involved:
BrowserID needs your help to grow and become a weapon of choice in the fight against insecure and annoying login systems. The great thing is that now is the time where you can be part of this.
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.
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:
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.
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
Tilt is a Firefox addon that lets you visualize any web page in 3D. A new update is available, coming with more developer-oriented features. Try the addon.
Since the first alpha version of Tilt was announced (a Firefox extension focused on creating a 3D visualization of a webpage), a lot of work has been done to add a great number of developer-oriented features. These focus on debugging the structure of a webpage, inspecting styling and attributes for each node and seamlessly refreshing the visualization when the DOM structure changes or after contents of document are repainted.
Solve nesting problems
Tilt is useful when searching problems in the HTML structure (like finding unclosed DIV elements for example) by providing the extra third dimension, layering each node based on nesting in the DOM tree. Stacks of elements visually represent branches in the DOM, and each node can be inspected for the inner HTML contents, its computed CSS style and the attributes.
Clicking anywhere on the visualization highlights a color-coded rectangle surrounding the corresponding node. Double click shows up the source preview for that node. Tilt also tries to show the most relevant information when needed (one is most likely to inspect the attributes of an input, button or image element, for example, but can easily switch between HTML, CSS and attributes view at any time).
Minidom map
The “minidom” is a tree view representation showing a minimalistic snapshot of the document object model. Each node is assigned a color associated by tag name (blue for div, green for span etc.) and represented as a strip, along with visual markers for the id and/or class if available. Each one of these strips also has a width relative to the type, id and class name length for the respective element, and the corresponding 3D stack in the visualization has color-coded margins. The coloring for individual elements is easily changeable using the color picker near to the minidom legend.
Clicking a strip in the tree view (or directly a stack on the 3D document visualization mesh) also highlights the node with a colored quad. This behavior is a good way to relate with the Style Inspector, and a more unified interaction between Tilt and other Developer Tools is planned in the future. All of these additions make it easier to analyze the bounds of each node, along with the HTML, computed CSS and attributes.
Realtime editing
Because Tilt is able to detect when a webpage’s DOM structure changes or when a repaint is necessary, integration is seamless with existing Developer Tools. Using Tilt and Firebug or Style Editor at the same time is easy. One can enable or disable CSS properties, changing the style of a node, and the visualization changes accordingly.
To enable realtime updates for the 3D webpage, go to the Options menu and check “Refresh visualization”.
Useful for learning
Developer tools such as “view source” have always been used to help people learn about web development. The 3D view highlights the structure of a page better than a flat view, thus anyone can immediately understand the parent-child relationship between nodes in a webpage, their positioning and how the layout is influenced.
One use case for this is the Hackasaurus mashup. The X-Ray Goggles is a nice and fun tool designed to make it easier to learn about the different document node types, the “building blocks” which create a webpage.
Export
A requested feature was the ability to export the visualization as a 3D mesh, to be used in games or other 3D editors. Tilt adds the ability to export to .obj, along with a material .mtl file and a .png texture (a screenshot of the entire webpage). The open .obj format ensures the fact that the mesh can be opened with almost any editor. Here’s a ray-traced rendering of hacks.mozilla.org in Blender:
Fun with experiments
As soon as it was released, many people found clever and interesting alternative ways to interact with Tilt. One experiment was creating a 3D visualization of an image, by exporting chunks of pixels to a HTML representation. The result was a voxel-like representation, with node blocks and stacks instead of pixels. A simple Image2Tilt converter was written in JavaScript, and you can try it directly in the browser.
Accelerometer support was another addition based on community request. This shows how easy it is to add functionality that wasn’t originally planned.
You can view the source code, fork it and also contribute to the addon with ideas or feature requests on Github, at github.com/victorporof/Tilt.
For compatibility, Tilt requires WebGL capabilities. Go to get.webgl.org to check availability and troubleshoot any issues. The current version works with Firefox 6.0 to latest 10.0 Nightly releases (latest Nightly builds now also support WebGL anti-aliasing, working great with Tilt).
To start Tilt, hit Control+Shift+M (or Command+Shift+M if you’re on Mac OS), or go to Web Developer -> Tilt, available in the Firefox application menu (or the Tools menu on Mac OS). You can modify this hotkey (and other properties) from the Options menu after starting Tilt.
More information about Tilt, the development process and milestone updates can be found on blog.mozilla.com/tilt.
Future
Tilt has become an active Developer Tools project, and an ongoing effort is made to integrate it with other existing tools like Style Inspector and Style Editor (source code and latest builds). As the 3D view of a webpage has proven to be useful for debugging, this main functionality will gradually become part of Firefox in future releases.
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.
The Demoparty Online Competition 2011 is part of the Mozilla Labs Demoparty Project, an initiative to foster artful exploration of open web technologies.
We asked people from the demo scene to have a go at web technologies and (with WebGL being the absolute winner of course) managed to collect over 100 submissions. Now the judges have spoken and we picked the winners in the categories of Main Demo, Single Effect, Audio Demo, Animated GIF and pure CSS demo.
Amongst other great examples of using technology in a purely creative way unhindered by real life application needs here are the winners of Demo and Single Effect:
We congratulate all the winners and thank all those who contributed. Playing with technology is a big part of making it interesting for everyone to use.
One of the best new features of HTML5 when it comes to visual effects is the canvas element and its API. On the surface, it doesn’t look like much – just a rectangle in the page you can paint on and wipe. Much like an etch-a-sketch. However, the ability to transform, rotate and scale its coordinate system is very powerful indeed once you master it.
Today I want to quickly show how you can do (well simulate) something rather complex with it, like a calculated drop shadow on an element. To see what I mean with this, check out the following demo which is also available on the Demo Studio:
(This is using JSFiddle to show you the demos, so you can click the different tabs to see the JavaScript and CSS needed for the effects. All of the demos are also available on GitHub.)
As you can see, the shadow becomes more blurred and less pronounced the further away the “sun” is from it. You can use the mouse to see the effect in the following demo:
Let’s take a look how that is done. The first step is to have a canvas we can paint on – you do this simply by having a mouse detection script (which we used for years and years) and a canvas with access to its API:
Click the play button of the above example and you see that you can paint on the canvas. However, the issue is that you keep painting on the canvas instead of only having the orb follow the cursor. To do this, we need to wipe the canvas every time the mouse moves. You do this with clearRect()
Running the above example now shows that the orb moves with the mouse. Cool, so this is going to be our “sun”. Now we need to place an object on the canvas to cast a shadow. We could just plot it somewhere, but what we really want is it to be in the middle of the canvas and the shadow to go left and right from that. You can move the origin of the canvas’ coordinate system using translate(). Which means though that our orb is now offset from the mouse:
If you check the “fix mouse position” checkbox you see that this is fixed. As we move the coordinate system to the half of the width of the canvas and half of its height, we also need to substract these values from the mouse x and y position.
Now we can draw a line from the centre of the canvas to the mouse position to see the distance using c.moveTo( 0, 0 );c.lineTo( distx, disty ); where distx and disty are the mouse position values after the shifting:
This gives us a shadow distance from the centre opposite of the mouse position, but we don’t want the full length. Therefore we can apply a factor to the length, in our case 0.6 or 60%:
Now we are ready for some drop shadow action. You can apply shadows to canvas objects using shadowColor and its distance is shadowOffsetX and shadowOffsetY. In our case, this is the end of the red line, the inversed and factored distance from the mouse position to the centre of the canvas:
Now, let’s blur the shadow. Blurring is done using the shadowBlur property and it is a number starting from 0 to the strength of the blur. We now need to find a way to calculate the blur strength from the distance of the mouse to the centre of the canvas. Luckily enough, Pythagoras found out for us years ago how to do it. As the x and y coordinate of the mouse are the catheti of a right-angled triangle, we can calculate the length of the hypothenuse (the distance of the point from the centre of the canvas) using the Square root of the squares of the coordinates or Math.sqrt( ( distx * distx ) + ( disty * disty ) ).
This gives us the distance in pixels, but what the really want is a number much lower. Therefore we can again calculate a factor for the blur strength – here we use an array for the weakest and strongest blur blur = [ 2, 9 ]. As the canvas itself also has a right-angled triangle from the centre to the top edge points we can calculate the longest possible distance from the center using longest = Math.sqrt( ( hw * hw ) + ( hh * hh ) ) where hw is half the width of the canvas and hh half the height. Now all we need to do is to calculate the factor to multiply the distance with as blurfactor = blur[1] / longest. The blur during the drawing of the canvas is the distance of the mouse position multiplied with the factor or currentblur = parseInt( blurfactor * realdistance, 10 );. We disregard blur values below the range we defined earlier and we have our blurred shadow:
In order to make the shadow weaker the further away the mouse is we can use the alpha value of its rgba() colour. The same principle applies as with the blur, we set our edge values as shadowalpha = [ 3, 8 ] and after calculating them from the distance we apply their inverse as the alpha value with c.shadowColor = 'rgba(0,0,0,' + (1 - currentalpha / 10) + ')';. This blurs and weakens the shadow:
Text-to-Speech (TTS) can make content more accessible, but there is so far no simple and universal way to do that on the web. One possible approach is shown in this demo, which is powered by speak.js, a new 100% pure JavaScript/HTML5 TTS implementation. speak.js is a port of eSpeak, an open source speech synthesizer, from C++ to JavaScript using Emscripten.
Compiling an existing speech synthesis engine to JavaScript is a good way to avoid writing a complicated project like eSpeak from scratch. Once compiled, the eSpeak code in speak.js doesn’t know it’s running on the web: speak.js uses the Emscripten emulated filesystem to ‘fake’ the normal file reading and writing calls that the eSpeak C++ code has (fopen, fread, etc.). This allows the normal eSpeak datafiles to be used (either through an xhr, or by converting them to JSON and bundling them with the script file). The result of running the compiled eSpeak code is that it ‘writes’ a .wav file with the generated audio to the emulated filesystem. speak.js then takes that data, encodes it using base64, and creates a data URL. That URL is then loaded in an HTML5 audio element, letting the browser handle playback. (Note that while that is a very simple way to do things, it isn’t the most efficient. speak.js has not yet focused on speed, but with some additional work it could be much faster, if that turns out to be an issue.)
Why would you want TTS in JavaScript? Well, with speak.js you can bundle a single .js file in your website, and then generating speech is about as simple as writing
speak("hello world")
(see the speak.js website for instructions). The generated speech will be exactly the same on all platforms, unlike if your users each did TTS in their own way (using an OS capability, or a separate program). speak.js can also be used to build browser addons in a straightforward way, since it’s pure JavaScript – no need for platform dependent binaries, and the addon will work the same on all OSes.
A few more comments:
JavaScript is getting more and more capable all the time. The development versions of the top JavaScript engines today can run code compiled from C++ only 3-5X slower than a fast C++ compiler, and getting even better. As a consequence, expanding the capabilities of the web platform can in many cases be done in JavaScript or by compiling to JavaScript, instead of adding new code to the browsers themselves, which inevitably takes longer – especially if you wait for all browsers to implement a particular feature.
While speak.js uses only standards-based APIs, due to browser limitations it can’t work everywhere yet. It won’t work in IE, Safari or Opera since they don’t support typed arrays, nor in Chrome since it doesn’t support WAV data URLs. So currently speak.js only works properly in Firefox. However, the missing features just mentioned are not huge and hopefully those browser makers will implement them soon. It is also possible to implement workarounds in speak.js for these issues (see next comment).
Help with improving speak.js is very welcome! One important thing we need is to implement workarounds for the issues that prevent speak.js from running on the browsers it currently can’t run on. Another goal is to build browser addons using speak.js. Please get in touch on github if you want to help out.
eSpeak supports multiple languages so speak.js can too. You do need to include the additional language files though. Here is an experimental build where you can switch between English and French support (note that it is an unoptimized build, so it will run slower).