What’s New in Chrome 19

518-chrome-11

I doubt you noticed but Chrome 19 was released this week. I rarely mention Chrome’s updates because, well, they’re rarely worth mentioning. However, I’ve discovered a few hidden gems in the latest browser…

Tab Syncing

The big new feature is tab syncing. If you’re using Chrome on two or more PCs/smartphones, you should see an “Other devices” link on the new tab page. Click it and you can open synchronized links. I say “should” because I haven’t been able to get it working.

Tab syncing has been available in Firefox for a while so I’m surprised it’s taken quite so long to appear in Chrome. Hopefully, you’ll have better luck than I did.

CSS3 calc() Support

The webkit team has finally implemented one of my favorite CSS3 features: the little-known calc() function. It allows you to define calculated dimensions, e.g.


#myelement { width: calc(50% - 2em + 4px); }

Chrome supports calc() with the -webkit prefix. Firefox uses -moz and IE9 is happy without prefixes. To use it effectively, you’ll need fallback code such as:


#myelement
{
	width: 46%;
	width: -webkit-calc(50% - 2em + 4px);
	width: -moz-calc(50% - 2em + 4px);
	width: -o-calc(50% - 2em + 4px);
	width: calc(50% - 2em + 4px);
}

Combined Settings Page

Choosing tool > Settings now displays a side menu with History, Extensions, Settings and Help. The Help page provides a couple of links and the update checker which normally appears on the “About” dialog (will that disappear soon?)

New JavaScript/ECMAScript 5.1 (Harmony) Features

A number of experimental JavaScript features have made their way from the Harmony specification into Chrome’s V8 engine. However, they’re not available by default — you’ll need to “Enable Experimental JavaScript” in chrome://flags. Language structures such as collections and proxies look great, but it’ll be some time before they’re available in all browsers.

Security and Bug Fixes

21 issues have been fixed in Chrome 19 and Google has paid almost $15,000 to eagle-eyed security hackers.

Chrome has remained fast and stable. It looks set to knock IE from the top of the browser usage chart during the summer of 2012. I’m not convinced any other vendor can prevent Google’s domination of the web and the software we use to access it.

iOS to IE10 Metro: Building Cross-Browser Plugin-Free Experiences

rb4

If you’ve built a plugin-free browsing experience for the iPad, a few changes will make it ready for the new IE10 plugin-free experience on Windows 8. As more browsers adopt the plugin-free approach, now is a good time to start thinking about it. I’ll show you how to do this in a few steps by writing code that works well in all modern browsers.

Today we’re going to work with a MSNBC plugin-free experience for rich media. It breaks down to two things: styles and scripts.

To modify the files of MSNBC, I will be using a proxy application known as Fiddler. You can download this tool from http://fiddler2.com. This tool allows me to modify remote files as though they were on my local machine. If you have direct access to your own site, you can ignore Fiddler, and work directly with your files. Fiddler provides a great way for testing changes without the risk of breaking your live site.

Step 1: Declare Standards Mode and Valid Markup for Modern Browsers

In order to use the HTML5 elements that we’ll be utilizing below, you’ll first need to ensure that you are operating in standards mode. One way to do this is to include the HTML5 doctype at the top of your document:

<!DOCTYPE html>

Step 2: Update your CSS Vendor Prefixes

The CSS language is undergoing a lot of change as new features are suggested, updated, and standardized. In order to allow developers to learn these new features, browser vendors typically offer experimental implementations via prefixed properties.

A key part of using vendor prefixes responsibly is to ensure that prefixes from each vendor are included in your site to allow for the broadest level of feature support. In many cases, especially when building an iPad-centric site, you may focus solely on -webkit properties, omitting the prefixes that target other browsers such as -o, -ms, and -moz. The end result of this is that you greatly limit the target devices that can render your plugin-free site as well as provide a degraded experience for users of other modern browsers, many of which could serve up equally engaging functionality.

For instance, we find the following on MSNBC:

background: -webkit-gradient(
  linear,
  left top,
  left bottom,
  color-stop(1, rgba(192,192,192,.6)),
  color-stop(0.5, rgba(0,0,0,.6))
);

With the growing trend towards an HTML5 plugin-free experience, it’s important to expand these rules to provide the vendor prefixes of other major browsers as well:

background: -webkit-linear-gradient(
  top, rgba( 0, 0, 0, 0.0 ) 0%, rgba( 0, 0, 0, 0.6 ) 50% );
background: -moz-linear-gradient(
  top, rgba( 0, 0, 0, 0.0 ) 0%, rgba( 0, 0, 0, 0.6 ) 50% );
background: -ms-linear-gradient(
  top, rgba( 0, 0, 0, 0.0 ) 0%, rgba( 0, 0, 0, 0.6 ) 50% );
background: -o-linear-gradient(
  top, rgba( 0, 0, 0, 0.0 ) 0%, rgba( 0, 0, 0, 0.6 ) 50% );
background: linear-gradient(
  top, rgba( 0, 0, 0, 0.0 ) 0%, rgba( 0, 0, 0, 0.6 ) 50% );

While more verbose, the benefits to broad browser feature support certainly outweigh the extra typing involved. In addition, there are a number of great tools that can break down this workload, such as SASS and Compass, -prefix-free, or even CSS Snippets in the upcoming Visual Studio 2011.

Also, if you’re working predominantly in JavaScript and would like to save time determining which features are supported by your client’s browser, review the instructions in A Best Practice for Programming with Vendor Prefixes on the IEBlog.

Step 3: Get Rid of Browser Sniffing Methods

There are two methods used to determine the capabilities of the user’s browser and device. One method, which unfortunately is somewhat popular, is browser sniffing. This method consists of examining the navigator object for certain patterns or values:

if ( navigator.userAgent.indexOf("iPad") > -1 ) {
  // Load HTML5 Experience
} else {
  // Load Flash Experience
}

The above code looks at the user agent string for the value “iPad”, and if found delivers a plugin-free HTML5 experience. Otherwise, it’s assumed you are on a device that has Flash installed. This will result in a broken experience for non-iPad users who are browsing with plugins disabled, even though their browser is capable of handling HTML5 features.

Here is an attempt to find the version of Internet Explorer:

if ( tests.IE ) {
  j = /msie.(\d\.\d+)/i;
  k = navigator.userAgent.match(j)[1];
}

The user agent string is tested for a pattern that attempts to target the version number. This pattern looks for a single digit, followed by a period, followed by any number of additional digits. While this test will find values like “MSIE 8.0” and “MSIE 9.0”, it will not identify the latest version of Internet Explorer, which identifies itself as “MSIE 10.0”, as only one digit is expected before the period.

These are just a couple examples of why browser sniffing is not a best practice. The user agent string is not immutable—it is a read-write value that is easily changed by plugins, or even the user. Most modern browsers include the ability to easily change this value from their development tools, which some users take advantage of to get around poorly-developed websites.

If we disable plugins, or visit MSNBC from a device/browser that doesn’t have Flash, we would expect it to attempt a plugin-free experience. Unfortunately, this is not the case. Rather than seeing an HTML5 experience, we’re instead asked to download Flash. This is because the site puts the user in one of two categories: an iPad user, or a Flash-enabled user.

MSNBC download Flash message

Feature Detection

Rather than trying to guess what a browser is capable of by sniffing its user agent string (which will fail you eventually), it is much wiser to actually test features directly in the browser. If you wanted to test the browser’s ability to deliver video and audio via HTML5, you could actually attempt to create these elements via JavaScript, and see if the browser understands them. This practice is called feature detection:

if ( !!document.createElement(“video”).canPlayType ) {
  // Load HTML5 Video
} else {
  // Load Flash Video
}

In the above example, we start by testing whether the canPlayType method exists on our newly-created video tag. We’re using double-negation to cast the response to a Boolean. If the browser understands what a video element is, the canPlayType method will be present. If the video element is unknown to the browser, the canPlayType method will not exist. If this test passes, we load our HTML5 video. If the test does not pass, we attempt to load Flash. Deeper feature detection could take place here, because Flash may not be on the machine, or may be disabled.

Feature detection is the preferred method of determining what a browser is capable of, as there is no guesswork involved. If the browser passes properly-constructed tests, it absolutely supports the features you would like to use.

Many great tools exist to provide feature tests for you. Once such tool, which provides over 40 tests, is Modernizr. This tool creates a global object called “Modernizr” which contains the results of your tests. With Modernizr, testing for HTML5 video support is extremely easy:

if ( Modernizr.video ) {
  // Load HTML5 Video
}

MSNBC engages in browser sniffing to see if the device accessing the page is an iPad or not. Our first step is to remove the browser sniffing code, and replace it with feature detection code.

Before we can modify browser sniffing code, we first need to locate it. While in Internet Explorer, pressing F12 will pull up our Developer Tools. Within the tools, open the Script tab and do a search for “userAgent”. This search will seek out any instance of this property name in all of the site’s script files. We’re interested in the result from line 41 of http://www.msnbc.msn.com/id/37156949/.

MSNBC download Flash message with Internet Explorer Developer Tools open

Now that we know what we want to edit, we can open up Fiddler and load up our traffic. Once Fiddler is opened, perform a hard-refresh (Ctrl+F5 in IE) on the MSNBC page. This results in all of the page sessions being listed in Fiddler.

Fiddler - HTTP Debugging Proxy on MSNBC page

Looking carefully, you’ll notice our resource is the third from the top. Next we can set up an AutoResponder for this session file so that anytime it is requested, a custom file is substituted in the place of the server response:

  1. Right-click this session and select “Decode Selected Sessions” from the context menu.
  2. Select the AutoResponder tab on the right.
  3. Click the “Enable automatic responses” checkbox in the AutoResponder tab.
  4. Drag the selected session from the left panel into the AutoResponder tab.

At this point, you should have an entry within your AutoResponder tab with the following rules:

  • If URI matches: EXACT:http://www.msnbc.msn.com/id/37156949/
  • Then respond with: *200-SESSION_3

Right-click the entry in the AutoResponder and select Edit Response. In the popup that follows, switch to the SyntaxView tab where we will find the source for this file. As expected, line 41 contains our browser sniffing code:

if ( !(navigator.userAgent.toLowerCase().indexOf("ipad")>-1) ){
  // Flash Experience
}

Rather than test the contents of the userAgent, we’re going to instead look for support for the HTML5 video tag. Switch the above condition to the following:

if ( !document.createElement("video").canPlayType ) {
  // Flash Experience
}

This test checks to see if we cannot use the video element. If canPlayType comes back as undefined, it will be cast to true and the first code block will be entered, setting up the Flash experience.

Step 4: Update Touch and Pointer Events

Safari supports both a touch event model and a mouse event model. Internet Explorer 10 groups touch, mouse, and stylus events into a single abstract item known as a pointer. In fact, Internet Explorer 10 is the first browser to work for all input types, across all devices. This abstraction cuts down drastically on the amount of effort involved to determine which event model you ought to bind to and how to detect user-interaction. This pointer is then handled through MSPointer events. If necessary, you can determine the type of pointer by accessing the pointerType property.

Diagram of funnel containing Pen, Touch, and Mouse, leading to Pointer

As Internet Explorer doesn’t support Apple’s proprietary event model, which includes touch events like touchstart, touchmove, and touchend, MSNBC’s event listeners will need to be amended to listen for MSPointer events like MSPointerDown, MSPointerUP, and MSPointerMove.

Due to the difference in event model implementations, use a feature detection tool like Modernizr or code like this to target all major event models:

if (window.navigator.msPointerEnabled) {
  myCanvas.addEventListener("MSPointerMove", paint, false);
} else {
  myCanvas.addEventListener("mousemove", paint, false);
  myCanvas.addEventListener(“touchmove”, paint, false);
}

MSNBC only supports touch events, which we will need to change so that visitors who happen to be using a mouse can still interact with the page. Our events are tied up in http://www.msnbc.msn.com/id/43662671/15:

document.addEventListener("touchstart", touchHandler, false);
document.addEventListener("touchmove", touchHandler, false);
document.addEventListener("touchend", touchHandler, false);

We’re going to update this to include the MSPointer events as well:

if (window.navigator.msPointerEnabled) {
  document.addEventListener("MSPointerDown", touchHandler, false);
  document.addEventListener("MSPointerMove", touchHandler, false);
  document.addEventListener("MSPointerUp", touchHandler, false);
} else {
  document.addEventListener("touchstart", touchHandler, false);
  document.addEventListener("touchmove", touchHandler, false);
  document.addEventListener("touchend", touchHandler, false);
  document.addEventListener("mousedown", touchHandler, false);
  document.addEventListener("mousemove", touchHandler, false);
  document.addEventListener("mouseup", touchHandler, false);
}

First, we’re checking for the presence of pointers. Since the MSPointer covers the mouse, fingers, and pens, we don’t need anything else besides them. We fall back, if necessary, to provide both touch and mouse events.

Next, we need to create cases for these event types in http://www.msnbc.com/id/44937131/. Currently, MSNBC starts with the following:

if ( event.type == "touchstart" ) {
  /* Start drag logic */
} else
if ( event.type == "touchmove" ) {
  /* Drag logic */
} else
if ( event.type == "touchend" ) {
  /* Complete drag logic */
}

We’ll modify this to listen for all of the registered event types:

if ( event.type.match( /(down|start)$/i ) ) {
  /* Start drag logic */
} else
if ( event.type.match( /move$/i ) ) {
  /* Drag logic */
} else
if ( event.type.match( /(up|end)$/i ) ) {
  /* Complete drag logic */
}

The above uses the match method and a series of regular expressions to determine which event was raised. If the event raised ends with a case-insensitive “down” or “start”, we begin our drag code. If the event ends with a case-insensitive “move”, we perform the actual drag logic itself. And lastly, if the event ends with a case-insensitive “up” or “end”, we end our dragging event. Note: other events may be caught here as well, like onresizeend and keyup. Be sure to consider this in your project.

The above is an implementation of Ted Johnson’s solution in Handling Multi-touch and Mouse Input in All Browsers.

The drag logic itself initially relies upon the event.targetTouches TouchList. This member does not exist in Internet Explorer. The drag logic attempts to gather the pageX and pageY properties from the first item in the TouchList, however, in Internet Explorer these values are found directly on the event object:

var curX = event.targetTouches[0].pageX;

Using the logical OR operator, I instruct curX to hold the value of event.pageX as long as event.pageX is present on the event object. If this property is not found, look within the targetTouches list:

var curX = event.pageX || event.targetTouches[0].pageX;

If event.pageX is not found, we fall back to assigning the value of targetTouches[0].pageX to our variable.

Another important item to keep in mind is that this site initially responds to touchmove. When this event is raised while touching the playlist, the code attempts to reposition the playlist based upon your touch movement. There is no hovering when it comes to touch—you’re either touching, or you’re not.

Now that we have mouse events tied into this logic, we have introduced the possibility for hovering. So while touchmove is free to reposition our playlist when it is over the playlist, we don’t want to do the same for mousemove. In fact, we only want the mousemove event to reposition the playlist when the mouse button is pressed.

For further reading, and examples on how to target all browsers, see Handling Multi-touch and Mouse Input in All Browsers.

Testing Both Experiences

Recall our feature detection from earlier, how we first check to see if HTML5 video support is in the user’s browser. If it is, we give them HTML5. If it is not, we give them Flash. One easy way to test our work is to use a browser, or document mode, that doesn’t support HTML5 features. This is very easy to test with Internet Explorer:

  1. Press F12 to reveal the Developer Tools
  2. Change your Document Mode to Internet Explorer 7 Standards
  3. Refresh the page

If our feature detection condition was written properly, you should now be watching a Flash-based presentation. Switching your Document Mode back into Internet Explorer 9 Standards (or “Standards” if you’re using IE10), will return you to the HTML5 experience.

Get it Done!

Hopefully this post helps to define the types of changes that will allow your iOS site to work properly in IE10 Metro and other plugin-free environments. By including best practices such as feature detection and responsibly using vendor prefixes for great new features, you should be able to provide your users with a great experience, regardless of which browser or device they’re using. To assist with testing in other plugin-free environments, download Internet Explorer 10 (currently available only in the Windows 8 CP) and begin testing today!

Two New Proposals to Solve the CSS3 Vendor Prefix Crisis

641-css-vendor-prefix-crisis

Web developers have been concerned about the vendor prefix crisis since February 2012. To summarize the issue, this is what should happen in an ideal world:

  1. Vendors implement experimental CSS3 properties using their own prefix, e.g. -webkit-transform, -moz-transform, -ms-transform, -o-transform.
  2. Developers can use the technologies today without breaking cross-browser compatibility. Properties can be listed with their prefixed and unprefixed names to ensure they work everywhere.
  3. Once a property becomes a W3C recommendation, all browser vendors can provide a stable unprefixed property, e.g. transform.
  4. Optionally, developers can remove the prefixed properties from their stylesheets. However, it’s not strictly necessary if the unprefixed property is defined last and CSS cascade rules apply.

This is what occurs in the real world:

  1. Vendors implement experimental CSS3 properties using their own prefix. In some cases, vendors promote them as an HTML5 “standard” even if they’re device-specific or never submitted to the W3C.
  2. Some developers use the proprietary property from a single vendor, e.g. only -webkit-transform. This might be owing to ignorance, laziness or because they’re testing a limited number of devices.
  3. Once a property becomes a W3C recommendation, all browser vendors can provide a stable unprefixed property, e.g. transform…
  4. but developers neglect to change their stylesheets. The site looks good in some browsers but worse in others even when they support the standard W3C specification.
  5. The vendors become concerned and add support for other prefixes into their browser, i.e. Opera implements the -webkit prefix for some properties. The prefix process is broken and, while it’s too early to predict the outcome, the majority of developers consider it to be a bad move.

We have discussed the issues at length on SitePoint; there are no easy solutions. However, two interesting proposals have been raised by W3C members during the past week.

Option 1: Unprefixed Properties are Supported From Day One

The first proposal comes from Florian Rivoal, Opera’s W3C representative:

When a browser vendor implements a new CSS feature, it should support it, from day 1, both prefixed and unprefixed, the two being aliased. If a style sheet contains both prefixed and unprefixed, the last one wins, according to the cascade.

Authors should write their style sheets using the unprefixed property, and only add a prefixed version of the property (below the unprefixed one) if they discover a bug or inconsistency that they need to work around in a particular browser.

If a large amount of content accumulates using the a particular vendor prefix to work around an issue with the early implementation in that browser, the vendor could decide to freeze the behavior of the prefixed property while continuing to improve the unprefixed one.

For example, you could use the following transform code in your CSS:


transform: rotate(30deg);

The property would be ignored by all browsers which had not implemented transforms. If there were a difference between two or more implementations, e.g. webkit browsers rotated anti-clockwise by default, you could override the property accordingly, e.g.


transform: rotate(30deg);
-webkit-transform: rotate(-30deg);

It’s a simple solution and easy to implement. Most existing stylesheets would continue to work and prefixed properties would rarely be necessary. In most cases, you would never need to update your CSS again.

However, what would happen if webkit changed rotation to the W3C-approved clockwise direction? Developers would need to fix their stylesheets by removing or rearranging the -webkit-transform: rotate(-30deg); property. Unfortunately, not everyone uses the same version of the webkit engine at the same time. You could encounter a situation where your site works in Chrome but not in Safari for several months.

Option 2: A New Vendor-Draft Modifier

The second proposal comes from François Remy:

Let’s introduce the “!vendor-draft” value modifier. I propose we use unprefixed properties from start, but with a token explaining which version of the property we built our CSS for:
border-radius: 3px !webkit-draft;

Any browser which is not webkit but implemented border-radius in a way that is compatible with the “webkit draft” can support the declaration. This is different from vendor prefixes: other browsers don’t impersonate webkit, they just acknowledge they support one specific property the way the webkit draft defines it. Browsers which are not compatible with that draft will just ignore the declaration. Browsers that change their implementation of a property are encouraged to iterate their “!vendor-draft” flag (using a version number, if appropriate).

This solves the issue by changing the property value rather than its name (in a similar way to the !important modifier). Again, the following transform code could be used:


transform: rotate(30deg);

But a default anti-clockwise rotation could be fixed in any browser adhering to a webkit specification:


transform: rotate(30deg);
transform: rotate(-30deg) !webkit-draft;

If a browser subsequently supported the W3C specification, the second property would be ignored.

It would also be possible to implement draft versioning, e.g.


transform: rotate(30deg);
transform: rotate(-30degrees) !webkit-draft;
transform: rotate(-30deg) !webkit-draft-2;

It’s a flexible solution which finally addresses the issue of properties evolving over time.

Unfortunately, it’s more difficult to implement and could take months to appear in browsers even if all vendors agreed today. It may be technically better, but it’s a fundamentally different approach which could break existing stylesheets. In the short term, vendors would probably support both prefixes and value modifiers — and that would lead to confusion.

I like both solutions. From a coding perspective, vendor-draft modifiers seems the most logical option but I doubt it can be considered until vendors “complete” CSS3 and begin work on CSS4.

Supporting unprefixed properties is more practical but will certainly cause versioning issues which couldn’t be fixed in CSS alone. But perhaps that’s the price you pay for using experimental technology?

Do you have a preference for either of these options? Or is it too late to prevent a vendor prefix catastrophe?

Judgment Day Arrives: Opera Implements the CSS3 Webkit Prefix

641-css-vendor-prefix-crisis

In February 2012, we reported the minutes of W3C meeting where Mozilla, Opera and Microsoft discussed implementing -webkit prefixes in non-webkit browsers. The reason: some developers use only webkit prefixes — their sites look good in some browsers, but broken in others even when they offer the same level of CSS3 support. The issue is especially prevalent on mobile browsers and many developers fail to look beyond their high-end Apple or Android devices.

Opera has now announced support for 14 CSS3 webkit properties in their Mobile Emulator. The implementation will eventually reach all editions of their desktop and mobile browsers. If you’re thinking “Opera has a tiny market share”, think again: it’s the world’s most-used mobile browser.

Perhaps I’m being overly dramatic, but Charlton Heston’s famous line comes to mind: “They finally, really did it. You manics. You blew it up!”

Opera -webkit Aliasing

Opera analyzed stylesheets from 10,000 popular websites to determine which CSS values/properties would receive -webkit aliases:

-o- prefix-webkit- alias
-o-linear-gradient-webkit-linear-gradient
box-shadow-webkit-box-shadow
-o-transform-webkit-transform
-o-transform-origin-webkit-transform-origin
border-radius-webkit-border-radius
border-top-left-radius-webkit-border-top-left-radius
border-top-right-radius-webkit-border-top-right-radius
border-bottom-left-radius-webkit-border-bottom-left-radius
border-bottom-right-radius-webkit-border-bottom-right-radius
-o-transition-webkit-transition
-o-transition-delay-webkit-transition-delay
-o-transition-duration-webkit-transition-duration
-o-transition-property-webkit-transition-property
-o-transition-timing-function-webkit-transition-timing-function

If the browser encounters a property such as -webkit-border-radius, it will apply that effect. If you’ve defined -webkit-border-radius, -o-border-radius and border-radius, normal CSS cascading rules apply and the last defined rule or most appropriate selector will be applied, e.g.


#myelement
{
	-o-border-radius: 3px;
	border-radius: 6px;
	-webkit-border-radius: 9px;
}

All properties are considered to have equal priority so Opera applies a border radius of 9px.

With regard to differences in behavior, Opera state:

As far as we can tell, the behavior the properties that we have aliased is identical in WebKit and Opera, or at least close enough that the differences will not matter in practice. If it turns out that there are differences big enough to cause breakage, we will consider our options, one of which is to align the behavior of our -webkit- prefixed variant to what WebKit actually does.

Opera make a reasonable case to justify their decision. While they understand the complaints, their primary goal is to create a browser which works well for users — who outnumber developers by many thousands to one.

The Backlash

Most developers understand the problem but disagree with the solution. It’s crude and has the potential to break the web. Taking the decision to it’s logical extreme, all vendors would support every prefix but any implementation differences would render the CSS property useless.

The solution rewards bad development practices. While Opera advises you use all vendor prefixes, they will exacerbate the problem:

  • Less conscientious developers will see this as justification for only targeting webkit browsers.
  • If your site uses differing -webkit and -o values, it will now be affected by CSS cascade rules. Is it easier to analyze and retest your code or simply remove the Opera properties?
  • It will become easier to accidentally omit the -o prefix since sites will work as expected.

Several problems have already been reported. For example, Modernizr evaluates prefixes in turn until it finds one the browser supports. Therefore:


Modernizr.prefixed("transition");

now returns WebkitTransition in Opera. Transitions are new to Opera and the browser doesn’t support every webkit CSS and JavaScript property. If you want to adjust or disable effects in Opera, you can’t rely on Modernizr-like detection code. You may even need to implement nasty browser sniffing.

However, my biggest issue is this: where are all these problem sites? Has user experience suffered from the lack of rounded corner, gradient, shadow, transition and transform effects? Are those sites genuinely broken or has Opera taken a (marketing) opportunity to make their browser look better?

Since Opera has analyzed 10,000 websites they can contact the owners directly. At the very least, they could publish a “hall of shame” which provides examples and highlights the technical issues. Many developers would happily contact companies on Opera’s behalf. Some would be prepared to fix sites for free since it could lead to future contracts.

There are no easy solutions to the vendor prefix crisis. I understand Opera’s reasons but, regardless of how this is implemented, it’s inevitable that something will end up broken.

Some good news: Microsoft has announced they will not support webkit prefixes in Internet Explorer (although there’s nothing to prevent them reversing that decision). Mozilla is yet to reveal their intentions — they will be watching Opera’s situation closely.

What’s New in Firefox 12 and Chrome 18

Firefox 12 was released on April 24 and Chrome 18 appeared on April 19. Did you notice? Put it this way — I hope you weren’t expecting a gaggle of ground-breaking new features. Unlike a few of the previous editions, the new updates from Mozilla and Google are largely maintenance releases and bug fixes. But there are a few gems to keep developers happy…

Firefox 12

If you have the irritating User Account Control (UAC) enabled in Windows, you should notice one fewer prompt during the update process. Firefox may not upgrade as quietly as Chrome but it’s definitely a step in the right direction.

CSS3 developers can now adopt the text-align-last property. This defines how the last line in a block such as a paragraph is aligned. It’s ideal if you’re using text-align: justify but want to ensure two words which flow into the last line are aligned to the left.

If you often view the Page Source you’ll also be pleased to discover that line numbers are now available whether you have line-wrapping enabled or not. To be honest, I can’t believe it’s taken this long to add that feature!

Other minor improvements:

  • Line breaks can be added to HTML title attributes.
  • “Find in Page” centers the result on screen.
  • URLs pasted into the download manager window are automatically downloaded.
  • A selection of bug fixes including WebGL performance on some Mac hardware.

Chrome 18

If you thought Firefox 12 was a lightweight release, Chrome 18 is positively skinny. GPU-accelerated Canvas 2D has been enabled on capable Windows and Mac PCs. In addition, TransGaming’s SwiftShader software-based rasterizer has been included so 3D WebGL graphics can be viewed on older hardware.

Google has also addressed nine security vulnerabilities and paid $4,000 to the lucky bug hunters.

That’s it, though. There’s nothing more to see here — please move along. Perhaps IE10 will give me a little more to write about very soon…

Modernize your HTML5 Canvas Game

Modern browsers like Internet Explorer 10 are implementing stable versions of some interesting HTML5 features, including offline application programming interfaces (API), drag and drop, and file API. These features are bringing us to a new era of web applications and fresh, quickly emerging gaming scenarios.

In this two-part article, I’ll show how I’ve used these new features to modernize my last HTML5 game, HTML5 Platformer. Hopefully you’ll get some great new ideas for your own games!

Part 1: Hardware scaling and CSS3
Part 2: Offline , file, and drag-and-drop API (next article)

Note: The URL demo is at the end of this article. Feel free to play using your favorite browser, and check out the IE10 gameplay video. The source code will be available for download in Part 2.

Scaling across devices

If you’re building an HTML5 game, you’re probably interested in the cross-platform nature of this standard programming language. But compatibility with a broad variety of devices means you have to take into account a huge number of resolutions. Compared to SVG, Canvas—at first—seems ill-prepared to handle this.

However, with a casual game based on sprites, there is a simple solution to implement. David Catuhe has done a great job of describing this on his blog, Unleash the power of HTML 5 Canvas for gaming – Part 1 (see the section called “Using the hardware scaling feature” for specifics).

The idea is as simple as it is smart. You’re working inside a canvas at a fixed, predictable resolution, and you’re stretching it to the current displayed resolution using the canvas.style properties.

Step 1: Stretch

In the case of my little HTML5 Platformer game, the assets and level logic have been set to 800×480. So if I want to fill a 1080p screen or a 1366×768 tablet, I need to build higher resolution assets to match those specs.

Before building all those assets, I can try a scaling operation—along with proper anti-aliasing—to increase image quality. Let’s give it a try.
The scaling operation simply requires this code:

window.addEventListener("resize", OnResizeCalled, false);
function OnResizeCalled() {
    canvas.style.width = window.innerWidth + 'px';
    canvas.style.height = window.innerHeight + 'px';
}

And that’s it!

With hardware-accelerated browsers, this operation will be done by your GPU at no cost. Anti-aliasing can even be enabled. That’s why David Catuhe thought it was worth mentioning it in his Canvas performance article.

This trick is not specific to HTML5, by the way. Most modern console games are not internally computed in 720p or 1080p; almost all of them render in lower resolutions (like 1024×600) and let the GPU handle the scaling/anti-aliasing process. In most cases, the method described here can help you boost the number of frames per second (FPS).

But this action, by itself, raises a ratio problem. Indeed, when the canvas had a fixed size of 800×480, the ratio was controlled. Now, I get this strange result when resizing the browser window:

The game is still playable, but also clearly far from optimal.

Step 2: Control your ratio

The idea here is to control how the screen is filled when the browser window is resized. Rather than stretching anything further, I’m going to add some empty space on the right if the window is too large, or at the bottom if the window is too high. Here’s that code:

var gameWidth = window.innerWidth;
var gameHeight = window.innerHeight;
var scaleToFitX = gameWidth / 800;
var scaleToFitY = gameHeight / 480;
var currentScreenRatio = gameWidth / gameHeight;
var optimalRatio = Math.min(scaleToFitX, scaleToFitY);
if (currentScreenRatio >= 1.77 && currentScreenRatio < = 1.79) {
    canvas.style.width = gameWidth + "px";
    canvas.style.height = gameHeight + "px";
}
else {
    canvas.style.width = 800 * optimalRatio + "px";
    canvas.style.height = 480 * optimalRatio + "px";
}

The "if" statement creates an exception: If you hit F11 in your browser to switch to full-screen viewing, and you've got a 16:9 screen (like my 1920x1080 Sony VAIO Z screen or the 1366x768 Samsung BUILD tablet), the game will be completely stretched. This experience was quite awesome.

Without this exception, here is the type of output you'll see:

Notice the black areas below and to the right of the game, controlling the ratio.
It would be even better if the game was centered, giving it a widescreen movie effect, right? Let's do it.

Step 3: Center the game with CSS3 Grid Layout

Centering an HTML element can sometimes be painful. There are several ways to do it—and there are plenty of resources on the web to help.

I like to use a new specification named CSS Grid Layout (currently only supported by IE10), which is the base of our Metro-style layout in Windows 8.

Centering an element with CSS Grid Layout is straightforward:

  • Switch the display of the container to display:grid.
  • Define 1 column and 1 row.
  • Center the inner element with the column-align and row-align properties.

Here's the CSS used in my case:

.canvasHolder {
    width: 100%;
    height: 100%;
    display: -ms-grid;
    -ms-grid-columns: 1fr;
    -ms-grid-rows: 1fr;
}
#platformerCanvas {
    -ms-grid-column: 1;
    -ms-grid-row: 1;
    -ms-grid-column-align: center;
    -ms-grid-row-align: center;
}

You’ll notice the prefix is “-ms” for IE10. Mozilla has recently annonced they will also support the CSS Grid Layout specification for Firefox in 2012, which is excellent news. In the meantime, this centering trick only works with IE10. Here’s what it looks like:


IE10 windows will display vertical or horizontal black bars, similar to what you might see on a television screen. In other browsers, the results will match those of Step 2, because the CSS3 Grid Layout specification will be ignored.

Using smooth animations

Now that we’re handling multiple resolutions with an easy scaling operation, it would be nice to play a smooth transition when the user is resizing the window. It would also be great to play a cool animation while each level loads. For that, we’re going to use the CSS3 Transitions and CSS3 3D Transforms tools. On most platforms, hardware acceleration is provided by the GPU.

Animating every change made to Canvas style properties

CSS3 Transitions is easy to use and produces smooth, efficient animations. To discover how to use them, you can read my colleague’s excellent article, Introduction to CSS3 Transitions, or play around on our Internet Explorer test-drive site, Hands On: transitions.

#platformerCanvas {
    -ms-grid-column: 1;
    -ms-grid-row: 1;
    -ms-grid-column-align: center;
    -ms-grid-row-align: center;
    -ms-transition-property: all;
    -ms-transition-duration: 1s;
    -ms-transition-timing-function: ease;
}

The canvas with the “platformerCanvas” ID will now automatically reflect any change made to its style properties in a one-second animation generated by an easing function. Thanks to this new rule, resizing the browser window reduces/increases the size of the canvas with a smooth animation. I love the effect it produces—all with only 3 lines of CSS.
Note: I also add the different prefixes (-moz, -webkit, and -o for Mozilla, WebKit, and Opera, respectively) for compatibility. You’ll want to remember to do the same.

Building a cool animation between each level

Now I’d like to use CSS3 3D Transforms to temporarily make the canvas disappear. This will be done with an animated 90-degree rotation on the Y axis. I’ll load the next level once the animation rotates 90 degrees and comes back to its initial position (rotated zero degrees). To better understand the effect, you can play with our Hands On: 3D Transforms on the Internet Explorer test-drive site:

We’re also going to play with the scale and rotateY properties to build a fun animation. For that, I’m adding two CSS rules and targeting two classes:

.moveRotation
{
    -ms-transform: perspective(500px) rotateY(-90deg) scale(0.1);
    -webkit-transform: perspective(500px) scale(0);
    -moz-transform: perspective(500px) rotateY(-90deg) scale(0.1);
}
.initialRotation
{
    -ms-transform: perspective(500px) rotateY(0deg) scale(1);
    -webkit-transform: perspective(500px) scale(1);
    -moz-transform: perspective(500px) rotateY(0deg) scale(1);
}

First, my canvas has the initialRotation class set:

<canvas id="platformerCanvas" width="800" height="480" class="initialRotation"></canvas>

Now the idea is to wait until the player beats the current level. Once that’s done, we’re changing the class of the canvas from initialRotation to moveRotation. This will automatically trigger the CSS3 Transitions we set before to generate the animation.

In order to know when the animation is finished, an event is raised. It’s named differently in each browser. Here is the code I use for registering the event and targeting IE10, Firefox, WebKit, and Opera:

// Registering to the various browsers vendors transition end event
PlatformerGame.prototype.registerTransitionEndEvents = function () {
    // IE10, Firefox, Chrome & Safari, Opera
    this.platformerGameStage.canvas.addEventListener("MSTransitionEnd", onTransitionEnd(this));
    this.platformerGameStage.canvas.addEventListener("transitionend", onTransitionEnd(this));
    this.platformerGameStage.canvas.addEventListener("webkitTransitionEnd", onTransitionEnd(this));
    this.platformerGameStage.canvas.addEventListener("OTransitionEnd", onTransitionEnd(this));
};
And here is the code that will be called back:
// Function called when the transition has ended
// We're then loading the next level
function onTransitionEnd(instance) {
    return function () {
        if (instance.loadNextLevel === true) {
            instance.LoadNextLevel();
        }
    }
};

At last, here is the code for my game that set the moveRotation class on the canvas:

// Perform the appropriate action to advance the game and
// to get the player back to playing.
PlatformerGame.prototype.HandleInput = function () {
    if (!this.wasContinuePressed && this.continuePressed) {
        if (!this.level.Hero.IsAlive) {
            this.level.StartNewLife();
        }
        else if (this.level.TimeRemaining == 0) {
            if (this.level.ReachedExit) {
                // If CSS3 Transitions is supported
                // We're using smooth & nice effects between each levels
                if (Modernizr.csstransitions) {
                    this.loadNextLevel = true;
                    // Setting the moveRotation class will trigger the css transition
                    this.platformerGameStage.canvas.className = "moveRotation";
                }
                // If CSS3 Transition is not supported, we're jumping directly
                // to the next level
                else {
                    this.LoadNextLevel();
                }
            }
            else
                this.ReloadCurrentLevel();
        }
        this.platformerGameStage.removeChild(statusBitmap);
        overlayDisplayed = false;
    }
    this.wasContinuePressed = this.continuePressed;
};

Notice I’m using Modernizr to do a feature detection of CSS Transitions. We’re finally setting back the initialRotation class inside the LoadNextLevel function:

// Loading the next level
PlatformerGame.prototype.LoadNextLevel = function () {
    this.loadNextLevel = false;
    // Setting back the initialRotation class will trigger the transition
    this.platformerGameStage.canvas.className = "initialRotation";
    // ... loadNextLevel logic stuff...
};

Note: You may have noticed that I’m not setting the same transformation (and animation) for WebKit as for IE10 and Firefox in my previous CSS block. This is because, in my case, Chrome won’t behave the same way as IE10 and Firefox 11. I’ve set up a simple reproduction case on jsFiddle.

Demo video and URL

Here is a short video demonstrating the IE10 features covered in this article:

You can also play with this demo in IE10 or your favorite browser here: Modern HTML5 Platformer.

In the next part of this article, I’ll show how to implement offline API to make my game work without network connections, and how drag-and-drop API can create another cool feature.

How to Use the HTML5 Full-Screen API

653-html5-fullscreen-api

Flash has offered a full-screen mode for many years but, until now, browser vendors have resisted the feature. The main reason: security. If you can force an app to run full-screen, the user loses their browser, taskbar and standard operating system controls. They may not be able to close the window or, worse, nefarious developers could emulate the OS and trick users into handing over passwords, credit card details, etc.

At the time of writing, the HTML5 full-screen API has been implemented in Firefox, Chrome and Safari. Mozilla provide good cross-browser details but it’s worth noting that the specifications and implementation details are likely to change.

Unlike pressing F11 to make your browser go full-screen, the API sets a single element full-screen. It’s intended for images, videos and games using the canvas element. Once an element goes full-screen, a message appears temporarily to inform the user that they can press ESC at any time to return to windowed mode.

The main properties, methods and styles are:

element.requestFullScreen()
Makes an individual element full-screen, e.g. document.getElementById(“myvideo”).requestFullScreen().

document.cancelFullScreen()
Exits full-screen mode and returns to the document view.

document.fullScreen
Returns true if the browser is in full-screen mode.

:full-screen
A CSS pseudo-class which applies to an element when it’s in full-screen mode.

Vexing Vendor Prefixes

Don’t bother trying to use these API names. You’ll require vendor prefixes for BOTH the CSS and JavaScript properties:

StandardChrome/SafariFirefox
.requestFullScreen().webkitRequestFullScreen().mozRequestFullScreen()
.cancelFullScreen().webkitCancelFullScreen().mozCancelFullScreen()
.fullScreen.webkitIsFullScreen.mozfullScreen
:full-screen:-webkit-full-screen:-moz-full-screen

There’s no support in Internet Explorer or Opera yet, but I would suggest you use the ‘ms’ and ‘o’ prefixes for future proofing.

I’ve developed a function in the demonstration page which handles the prefix shenanigans for you:


var pfx = ["webkit", "moz", "ms", "o", ""];
function RunPrefixMethod(obj, method) {
	var p = 0, m, t;
	while (p < pfx.length && !obj[m]) {
		m = method;
		if (pfx[p] == "") {
			m = m.substr(0,1).toLowerCase() + m.substr(1);
		}
		m = pfx[p] + m;
		t = typeof obj[m];
		if (t != "undefined") {
			pfx = [pfx[p]];
			return (t == "function" ? obj[m]() : obj[m]);
		}
		p++;
	}
}

We can then make any element viewable full screen by attaching a handler function which determines whether it’s in full-screen mode already and acts accordingly:


var e = document.getElementById("fullscreen");
e.onclick = function() {
	if (RunPrefixMethod(document, "FullScreen") || RunPrefixMethod(document, "IsFullScreen")) {
		RunPrefixMethod(document, "CancelFullScreen");
	}
	else {
		RunPrefixMethod(e, "RequestFullScreen");
	}
}

The CSS

Once the browser enters full-screen mode you’ll almost certainly want to modify the styles for the element and it’s children. For example, if your element normally has a width of 500px, you’ll want to change that to 100% so it uses the space available, e.g.


#myelement
{
	width: 500px;
}
#myelement:full-screen
{
	width: 100%;
}
#myelement:full-screen img
{
	width: 100%;
}

However, you cannot use a list of vendor prefixed selectors:


/* THIS DOES NOT WORK */
#myelement:-webkit-full-screen,
#myelement:-moz-full-screen,
#myelement:-ms-full-screen,
#myelement:-o-full-screen,
#myelement:full-screen
{
	width: 100%;
}

For some bizarre reason, you must repeat the styles in their own blocks or they won’t be applied:


/* this works */
#myelement:-webkit-full-screen	{ width: 100% }
#myelement:-moz-full-screen		{ width: 100% }
#myelement:-ms-full-screen		{ width: 100% }
#myelement:-o-full-screen		{ width: 100% }
#myelement:full-screen			{ width: 100% }

Weird.

View the demonstration page in Firefox, Chrome or Safari…

The technique works well. The only issue I’ve discovered concerns Safari on a two-monitor desktop — it insists on using the first monitor for full-screen mode even if the browser is running on the second screen?

While it’s possibly a little early to use full-screen mode, games developers and video producers should keep an eye on progress.

The New Sensory Elements Coming to HTML5

658-html5-aroma

The web is primarily a visual medium with a little audio here and there. HTML5 supports the video and audio tags but our other senses have been shamefully neglected. Until now.

The W3C will shortly announce three new HTML5 elements which support alternative sensory interfaces:

  • <texture> for touch
  • <aroma> for smell, and
  • <flavor> for taste

HTML Usage

The new elements will normally be used as wrappers for other items. For example, you might want to apply a fresh grass odor to an image of a field, e.g.


<aroma fresh="50%" sweet="20%" warm="35%">
	<img src="myfield.jpg" alt="field" />
</aroma>

The categorization attributes will vary depending on the tag, e.g.

  • texture: smoothness, firmness, flaccidity, temperature
  • aroma: sweet, pungent, acrid, fragrant, warm, dry, sour
  • flavor: sweetness, sourness, saltiness

The volume and muted attributes are also supported to indicate the strength of odors and flavors.

However, unless you’re a chemical expert, defining these attributes isn’t easy. For that reason, all tags can use the src and type attributes to point to sensory definition files which contain one or more textures, aromas or flavors, e.g.


<aroma src="cheese.odor" type="stilton">
	<img src="stilton.jpg" alt="stilton cheese" />
</aroma>

Vendors will provide several pre-defined sensory packs within their browsers. However, Chrome’s representation of Roquefort is likely to differ from IE’s; it may be several years before we reach agreed sensory standards. Fortunately, it will be possible to develop your own definition files if compatibility issues arise.

CSS Properties

Textures, odors and flavors can also be applied from CSS. For example, our online cheese shop could link to a Stinking Bishop page:


<a id="stinking" href="stinking-bishop.html">
	<img src="stinking-bishop.jpg" alt="stinking bishop cheese" />
</a>

CSS could apply an appropriate aroma, flavor and texture as the user hovers over or focuses on the link. Sensory definition files or classifications can be used:


a#stinking:hover, a#stinking:focus {
	aroma: url("cheese.odor") stinkingbishop 50%; /* pack, type, volume */
	flavor: url("cheese.taste") stinkingbishop 98%; /* pack, type, volume */
	texture: 25% 30% 20; /* smoothness, hardness, temperature (degrees C) */
}

JavaScript APIs

JavaScript APIs will be available for the new sensory elements. For example, you could mute or change the volume (strength) of a sensory tag, e.g.


var cheese = document.getElementById("stinking");
var c = 0;
Pungent();
function Pungent() {
	cheese.aroma.volume = c + "%";
	c += 5;
	if (c < 100) setTimeout(arguments.callee, 500);
}

This example increases the cheese odor over time. Note that aroma-generating devices are likely to have slower response times than screen output: thorough testing will be required to ensure aromas and flavors don’t clash.

Hardware Support

lick-able mouse wheel

Hardware devices which support these sense elements will be introduced during the next year. One of the first is a multi-sensory mouse by Ollofipra, the Scandinavian PC manufacturer. It uses a patented rubber mesh to change shape, texture and temperature. It also emits a range of smells and the central wheel generates different flavors. The company hopes to add the technology to touch-sensitive monitors so they become lick-able.

Please note that the W3C specifications for the sensory elements are at an early daft stage and implementation changes are inevitable. However, the future looks promising and the tags have potential to revolutionize web interfaces. You should certainly discuss it with your colleagues today.

A Comprehensive Introduction to LESS: Mixins

Screen Shot 2012-03-16 at 5.36.44 PM

Mix… what?

With LESS, we can define so-called "mixins", which have some similarities to functions in programming languages. In LESS, they’re used to group CSS instructions in handy, reusable classes. Mixins allow you to embed all the properties of a class into another class by simply including the class name as one of its properties. It’s just like variables, but for whole classes. Any CSS class or id ruleset can be mixed-in that way:

.RoundBorders {
  border-radius: 5px;
  -moz-border-radius: 5px;
  -webkit-border-radius: 5px;
}
#menu {
  color: gray;
  .RoundBorders;
}
//Output
.RoundBorders {
  border-radius: 5px;
  -moz-border-radius: 5px;
  -webkit-border-radius: 5px;
}
#menu {
  color: gray;
  border-radius: 5px;
  -moz-border-radius: 5px;
  -webkit-border-radius: 5px;
}

As you can see, this output is the mixin itself and the CSS ruleset. If you don’t want mixins to appear in your compiled .css file just add empty parenthesis after the mixin name. you may wonder why I’m using a capitalized letter for the mixin names. This is because CSS class selectors also use the dot symbol and there is no way to differentiate it from a LESS mixin name. That’s why I usually use capitalized letters, as in object oriented programming, which uses capitalized letters for classes.

Enter Your Arguments, Please

Mixins can be made parametric, meaning they can take arguments to enhance their utility. A parametric mixin all by itself is not output when compiled. Its properties will only appear when mixed into another block. The canonical example is to create a rounded corners mixin that works across browsers:

.RoundBorders (@radius) {
  border-radius: @radius;
  -moz-border-radius: @radius;
  -webkit-border-radius: @radius;
}

And here’s how we can mix it into various rulesets:

header {
  .RoundBorders(4px);
}
.button {
  .RoundBorders(6px);
}

Parametric mixins can also have default values for their parameters:

.RoundBorders (@radius: 5px) {
  border-radius: @radius;
  -moz-border-radius: @radius;
  -webkit-border-radius: @radius;
}

Now we can invoke it like this:

header {
  .RoundBorders;
}

And it will include a 5px border-radius.

If you have a mixin that doesn’t have any arguments, but you don’t want it to show up in the final output, give it a blank argument list:

.HiddenMixin() {
  color: black;
}
p { .HiddenMixin() }

Which would output:

p {
  color: black;
}

Within a mixin there is a special variable named @arguments that contain all the arguments passed to the mixin, along with any remaining arguments that have default values. The value of the variable has all the values separated by spaces. This is useful for quickly assigning all the arguments:

.BoxShadow(@x: 0, @y: 0, @blur: 1px, @color: #000) {
  box-shadow: @arguments;
  -moz-box-shadow: @arguments;
  -webkit-box-shadow: @arguments;
}
.BoxShadow(2px, 5px);

Which results in:

box-shadow: 2px 5px 1px #000;
-moz-box-shadow: 2px 5px 1px #000;
-webkit-box-shadow: 2px 5px 1px #000;

A Little Matchmaking :)

When you mix in a mixin, all the available mixins of that name, in the current scope, are checked to see if they match according to what was passed to the mixin and how it was declared.

The simplest case is matching on arity (the number of arguments that the mixin takes). Only the mixins that match the number of arguments passed in are used, with the exception of zero-argument mixins, which are always included. Here’s an example:

.mixin() { // this is always included
  background-color: white;
}
.mixin(@a)  {
  color: @a;
}
.mixin(@a, @b) {
  color: fade(@a, @b);
}

Now if we call .mixin with a single argument, we will get the output of the first definition, but if we call it with two arguments, we will get the second definition, namely @a faded to @b.

Another way of controlling whether a mixin matches, is by specifying a value in place of an argument name when declaring the mixin:

.mixin (dark, @color) {
  color: darken(@color, 10%);
}
.mixin (light, @color) {
  color: lighten(@color, 10%);
}
.mixin (@_, @color) { // this is always included
  display: block;
}
@switch: light;
.class {
  .mixin(@switch, #888);
}

We will get the following CSS:

.class {
  color: #a2a2a2;
  display: block;
}

Where the color passed to .mixin was lightened. If the value of @switch was dark, the result would be a darker color. Only mixin definitions that matched were used. Variables match and bind to any value, and anything other than a variable matches only with a value equal to itself.

Guards

Another way of restricting when a mixin is mixed in, is by using guards. A guard is a special expression that is associated with a mixin declaration that is evaluated during the mixin process. It must evaluate to true before the mixin can be used. Guards are useful when you want to match on expressions, as opposed to simple values or arity.

We use the when keyword to begin describing a list of guard expressions.

.mixin (@a) when (lightness(@a) >= 50%) {
  background-color: black;
}
.mixin (@a) when (lightness(@a) < 50%) {
  background-color: white;
}
.mixin (@a) { // this is always included
  color: @a;
}
.class1 { .mixin(#ddd) } // this matches the first mixin
.class2 { .mixin(#555) } // this matches the second mixin

Here’s what we’ll get:

.class1 {
  background-color: black;
  color: #ddd;
}
.class2 {
  background-color: white;
  color: #555;
}

The full list of comparison operators usable in guards are: >, >=, =, =<, <.

If you want to match mixins based on value type, you can use the is* functions. These are—iscolor, isnumber, isstring, iskeyword, and isurl. If you want to check if a value, in addition to being a number, is in a specific unit, you may use one of these—ispixel, ispercentage, isem. Here is a quick example:

.mixin (@a) when (iscolor(@a)) {
  color: @a;
}
.mixin (@a) when (ispixel(@a)) {
  width: @a;
}
body {
  .mixin(black);
}
div {
  .mixin(960px);
}
//Output
body {
  color: #000000;
}
div {
  width: 960px;
}

Guards can be separated with a comma—if any of the guards evaluates to true, it’s considered a match:

.mixin (@a) when (@a > 10), (@a < -10) { ... }

Instead of a comma, we can use the and keyword so that all of the guards must match in order to trigger the mixin:

.mixin (@a) when (isnumber(@a)) and (@a > 0) { ... }

Finally, you can use the not keyword to negate conditions:

.mixin (@b) when not (@b > 0) { ... }

Think Math is Bad? Think Again.

Are some elements in your stylesheet proportional to other elements? Operations let you add, subtract, divide, and multiply property values and colors, giving you the power to create complex relationships between properties. Rather than add more variables, you can perform operations on existing values with LESS. You can build expressions with any number, color, or variable.

@sidebarWidth: 400px;
@sidebarColor: #FFCC00;
#sidebar {
  color: @sidebarColor + #FFDD00;
  width: @sidebarWidth / 2;
  margin: @sidebarWidth / 2 * 0.05;
}
//Output
#sidebar {
  color: #FFFF00; // color is brighter
  width: 200px;   // width is reduced to 200px
  margin: 10px;   // margin is set to 5% of the width
}

Parentheses can be used to control the order of evaluation. They are required in compound values:

border: (@width * 2) solid black;

LESS also provides you with a couple of handy math functions. These are:

round(1.67); // returns 2
ceil(2.4);   // returns 3
floor(2.6);  // returns 2 

And, if you need to turn a value into a percentage, you can do so with the percentage function:

percentage(0.5); // returns 50%

Here I will show you a little secret trick: how to use the golden ratio in your design. You don’t need any calculator at all. Check this out:

@baseWidth: 960px;
@mainWidth: round(@baseWidth / 1.618);
@sidebarWidth: round(@baseWidth * 0.382);
#main {
  width: @mainWidth;
}
#sidebar {
  width: @sidebarWidth;
}

And the answer is:

#main {
  width: 593px;
}
#sidebar {
  width: 367px;
}

Et voila! You have your layout divided properly with the golden ratio. Do you still think math is bad?! I don’t think so :)

Color Alchemy

LESS provides a variety of functions that transform colors. Colors are first converted to the HSL color-space, and then manipulated at the channel level. All color operations take a color and a percentage as parameters, except spin, which uses integers between 0 and 255 instead of percentages to modify the hue, and mix, which takes two colors as parameters. Here is a quick reference for you:

lighten(@color, 10%);    // lightens color by percent and returns it
darken(@color, 10%);     // darkens color by percent and returns it
saturate(@color, 10%);   // saturates color by percent and returns it
desaturate(@color, 10%); // desaturates color by percent and returns it
fadein(@color, 10%);     // makes color less transparent by percent and returns it
fadeout(@color, 10%);    // makes color more transparent by percent and returns it
fade(@color, 50%);       // returns a color with the alpha set to amount
spin(@color, -10);       // returns a color with amount degrees added to hue
mix(@color1, @color2);   // return a mix of @color1 and @color2

You can also extract color information from hue, saturation, lightness, and alpha channels:

hue(@color);        // returns the 'hue' channel of @color
saturation(@color); // returns the 'saturation' channel of @color
lightness(@color);  // returns the 'lightness' channel of @color
alpha(@color);      // returns the 'alpha' channel of @color

This is useful if you want to create a new color based on another color’s channel, for example:

@new: hsl(hue(@old), 45%, 90%);

Do You Love Hierarchy? Yes, I Do.

In CSS, we write out every ruleset separately, which often leads to long selectors that repeat parts over and over. Rather than constructing long selector names to specify inheritance, in LESS you can simply nest selectors inside other selectors. This makes inheritance clear and stylesheets shorter:

header {}
header nav {}
header nav ul {}
header nav ul li {}
header nav ul li a {}

In LESS you can write:

header {
  nav {
    ul {
      li {
        a {}
      }
    }
  }
}

As you can see, this gives you clean, well-structured code, represented by a strong visual hierarchy. Now you don’t have to repeat selectors over and over ever again. Simply nest the relevant ruleset inside another to indicate the hierarchy. The resulting code will be more concise, and mimics the structure of your DOM tree. If you want to give pseudo-classes this nesting structure, you can do so with the & operator. The & operator represents the parent’s selector. It’s used when you want a nested selector to be concatenated to its parent selector, instead of acting as a descendent.

For example, the following code:

header {
  color: black;
}
header nav {
  font-size: 12px;
}
header .logo {
  width: 300px;
}
header .logo:hover {
  text-decoration: none;
}

Can be written this way:

header {
  color: black;
  nav {
    font-size: 12px;
  }
  .logo {
    width: 300px;
    &:hover { text-decoration: none }
  }
}

Or this way:

header    { color: black;
  nav     { font-size: 12px }
  .logo   { width: 300px;
  &:hover { text-decoration: none }
  }
}

Name It, Use It, and Re-use It. Is It That Simple?

What if you want to group mixins into separate bundles for later re-use, or for distributing? LESS gives you the ability to do that by nesting mixins inside a ruleset with an ID, like #namespace.

For example:

#Fonts {
  .Serif (@weight: normal, @size: 14px, @lineHeight: 20px) {
    font-family: Georgia, "Times New Roman", serif;
    font-weight: @weight;
    font-size: @size;
    line-height: @lineHeight;
  }
  .SansSerif (@weight: normal, @size: 14px, @lineHeight: 20px) {
    font-family: Arial, Helvetica, sans-serif;
    font-weight: @weight;
    font-size: @size;
    line-height: @lineHeight;
  }
  .Monospace (@weight: normal, @size: 14px, @lineHeight: 20px) {
    font-family: "Lucida Console", Monaco, monospace
    font-weight: @weight;
    font-size: @size;
    line-height: @lineHeight;
  }
}

Then, to call a mixin from that particular group, you do this:

body {
  #Fonts > .SansSerif;
}

And the output is:

body {
  font-family: Arial, Helvetica, sans-serif;
  font-weight: normal;
  font-size: 14px;
  line-height: 20px;
}

Remember to add empty parentheses when you define mixins, which don’t take parameters. This way the initial definition isn’t included in the rendered CSS, only in the code where the mixin is being used. This both shortens your output code and allows you to keep a library of definitions that don’t add to the weight of the output until they are actually used.

Some Special Cases

String Interpolation

String interpolation is a convenient way to insert the value of a variable right into a string literal. Variables can be embedded inside strings with the @{name} construct:

@baseURL: "http://example.com";
border-image: url("@{base-url}/images/border.png");

Escaping

Sometimes you might need to output a CSS value that is either invalid CSS syntax, or uses proprietary syntax, which LESS doesn’t recognize. If this is the case, just place the value inside a string prefixed with the ~ operator, for example:

body {
  @size ~"20px/80px";
  font: @size sans-serif;
}

This is called an “escaped value”, which will result in:

body {
  font: 20px/80px sans-serif;
}

I’m Ready. Show Me the Magic, Please.

The idea behind LESS is to speed up and simplify only the development step. This means what goes live on your final website should be plain, old CSS, not LESS. Fortunately, this can be done extremely easy. All you need to do is to get a LESS compiler, and let it do its job. I recommend WinLess (for Windows) and LESS.app (for OS x)

Here I will explain to you how to work with WinLess. First, download and install it. When you launch WinLess all you need to do is to drag a folder with .less files inside, and you are ready to go. To configure WinLess behavior, open File > Settings. I leave "Minify by default" unchecked because I want my file to be readable and minify my files only when I’m outputting for production. I check the other two options below because I don’t want to compile manually every single time I save a file, and because I want to know whether the compile is successful. By the way, for the training purpose you can use the WinLess Online LESS Compiler—ideal if you want to quickly try out something.

For working with LESS.app, you can check the video tutorial on its website’s home page.

There is one more option for those of you who don’t use PC or Mac. You can get Crunch!, which is a cross-platform AIR application. Crunch is not only a LESS compiler, but also a LESS editor. This is cool, because Crunch is the only editor, to my knowledge, which gives you syntax highlighting for .less files. Try it to see what I mean. You know what? I’ll tell you my little secret. Actually, I’m using both of them—WinLess for compiling, and Crunch for editing. Sounds cool, huh?

OK. I’m Really Fascinated. Where do I Find More?

Here is a little bonus for you. This is a short list of LESS resources, which can be used in your projects right away. There are some ready for use LESS mixins and variables, plus a couple of projects which use LESS as their base.

  • Official LESS documentation—OK. This can’t be used in your projects :) However, you should check it regularly for any updates and new features added to the language.
  • LESS Elements—a collection of useful LESS mixins.
  • Preboot.less—another collection of LESS mixins and variables.
  • Semantic Grid System—a simple and easy to use page layout tool. It supports Fixed, Fluid, and Responsive layouts. And, by the way, you can use it with Sass and Stylus too (if you still haven’t fallen in love with LESS).
  • Centage—if you need full fluidity and flexibility, you should definitely check this.
  • perkins CSS3 LESS Framework—a nice and rich LESS framework, which uses HTML5 and CSS3.

If you want to find even more resources about LESS, GitHub is the right place to go. As you will see, there are plenty of LESS goodies there. So, what are you waiting for? Go and check them out.

A Few Final Words

In brief, LESS is a fast, easy, and modern way of writing and crafting CSS code. So don’t be too conservative, and just give it a try. Spend some time with LESS and you’ll be creating and tweaking complex stylesheets faster and easier than ever before. Wish you happy coding, and always remember—LESS is more :)

Can You Achieve CSS Warrior Status?

CSS3 Anthology

Hey there, all you CSSers!

As part of the launch of our latest book “The CSS3 Anthology, 4th Edition – Take Your Sites to New Heights” we’re laying down the challenge for all of you to test your CSS knowledge.

Take the testand see if you can attain CSS warrior status!