Tag: kranthi

Why We Shouldn’t Make Separate Mobile Websites


  

There has been a long-running war going on over the mobile Web: it can be summarized with the following question: “Is there a mobile Web?” That is, is the mobile device so fundamentally different that you should make different websites for it, or is there only one Web that we access using a variety of different devices? Acclaimed usability pundit Jakob Nielsen thinks that you should make separate mobile websites. I disagree.

Jakob Nielsen, the usability expert, recently published his latest mobile usability guidelines. He summarizes:

“Good mobile user experience requires a different design than what’s needed to satisfy desktop users. Two designs, two sites, and cross-linking to make it all work.”

I disagree (mostly) with the idea that people need different content because they’re using different types of devices.

Firstly, because we’ve been here before, in the early years of this century. Around 2002, the huge UK supermarket chain Tesco launched Tesco Access—a website that was designed so that disabled people could browse the Tesco website and buy groceries that would be delivered to their homes.

It was a great success—heavily stripped down, all server-generated (as in, those days screen readers couldn’t handle much JavaScript) and it was highly usable. One design goal was “to allow customers to purchase an average of 30 items in just 15 minutes from login to checkout.” In fact, from a contemporary report, (cited by Mike Davis), “many non-disabled customers are switching from the main Tesco site to the Tesco Access site, because they find it easier and faster to use!” It also made Tesco a lot of money: “Work undertaken by Tesco.com to make their home grocery service more accessible to blind customers has resulted in revenue in excess of £13m per annum, revenue that simply wasn’t available to the company when the website was inaccessible to blind customers.”

However, some blind users weren’t happy. There were special offers on the “normal” Tesco website that weren’t available on the access website. There were advertisements that were similarly unavailable—which was a surprise; whereas most people hate advertisements, here was a community complaining that it wasn’t getting them.

The vital point is that you never know better than your users what content they want. When Nielsen writes that mobile websites should “cut features, to eliminate things that are not core to the mobile use case; [and] cut content, to reduce word count and defer secondary information to secondary pages,” he forgets this fact.

Tesco learned this:

“We have completely redesigned Access so that it is no longer separate from our main website but is now right at the center of it, enabling our Access customers to enjoy the same features and functionality available on the standard grocery website. As part of this work we have had to retire the old Access website.”

Nielsen writes:

“Build a separate mobile-optimized site (or mobile site) if you can afford it … Good mobile user experience requires a different design than what’s needed to satisfy desktop users. Two designs, two websites, and cross-linking to make it all work.”

From talking to people in the industry, and from my own experience of leading a dev team, I’ve found that building a separate mobile website is considered to be a cheaper option in some circumstances—there may be time or budgetary constraints. Sometimes teams don’t have another option but creating a separate website due to factors beyond their control.

I believe that this is not ideal, but for many it’s a reality. Re-factoring a whole website with responsive design requires auditing content. And changing a production website with all the attendant risks, then testing the whole website to ensure it works on mobile devices (while introducing no regressions in the desktop website)—all this is a huge task. If the website is powered by a CMS, it’s often cheaper and easier to leave the “desktop website” alone, and implement a parallel URL structure so that www.example.com/foo is mirrored by m.example.com/foo, and www.example.com/bar is mirrored by m.example.com/bar (with the CMS simply outputting the information into a highly simplified template for the mobile website).

The problem with this approach is Nielsen’s suggestion: “If mobile users arrive at your full website’s URL, auto-redirect them to your mobile website.” The question here is how can you reliably detect mobile browsers in order to redirect them? The fact is: you can’t. Most people attempt to do this with browser sniffing—checking the User Agent string that the browser sends to the server with every request. However, these are easily spoofed in browsers, so they can’t be relied upon, and they don’t tell the truth, anyways. “Browser sniffing” has a justifiably bad reputation, so is often renamed “device detection” these days, but it’s the same flawed concept.

Twitter_mobile
On mobile, Twitter.com automatically forwards users to a separate mobile website.

More troublesome is that there are literally hundreds of UA strings that your detection script needs to be aware of in order to send the visitor to the “right” page. The list is ever-growing, so you need to constantly check and update your detection scripts. And of course, you only know about a new User Agent string after it turns up in your analytics—so there will be a period between the first visitor arriving with an unknown UA and your adding it to your detection scripts (in which visitors will be sent to the wrong website).

Despite all this work to set up a second parallel website, you will still find that some visitors are sent to the wrong place, so here I agree with Nielsen:

“Offer a clear link from your full site to your mobile site for users who end up at the full site despite the redirect … Offer a clear link from your mobile site to your full site for those (few) users who need special features that are found only on the full site.”

Missing out features and content on mobile devices perpetuates the digital divide. As Josh Clark points out in his rebuttal:

“First, a growing number of people are using mobile as the only way they access the Web. A pair of studies late last year from Pew and from On Device Research showed that over 25% of people in the US who browse the Web on smartphones almost never use any other platform. That’s north of 11% of adults in the US, or about 25 million people, who only see the Web on small screens. There’s a digital-divide issue here. People who can afford only one screen or internet connection are choosing the phone. If you want to reach them at all, you have to reach them on mobile. We can’t settle for serving such a huge audience a stripped-down experience or force them to swim through a desktop layout in a small screen.”

The number of people only using mobile devices to access the Web is even higher in emerging economies. Why exclude them?

Mobile Usability

I also agree with Nielsen when he writes:

“When people access sites using mobile devices, their measured usability is much higher for mobile sites than for full sites.”

But from this he draws the wrong conclusion, that we should continue making special mobile websites. I believe that special mobile websites is like sticking plaster over the problem; we generally shouldn’t have separate mobile websites, anymore than we should have separate screen reader websites. The reason many “full websites” are unusable on mobile phones is because many full websites are unusable on any device. It’s often said that your expenditure rises as your income does, and that the amount of clutter you own expands to fill your house however many times you move to a bigger one. In the same way, website owners have long proved incontinent in keeping desktop websites focussed, simply because they have so much room. This is perfectly illustrated by the xkcd comic:

A Venn diagram showing
A Venn diagram showing “Things on the front page of a university website” and “Things people go to the site looking for.” Only one item is in the intersection: “Full name of school.” Image source: xkcd.

As I wrote on the website The Pastry Box on April 13th:

“The mobile pundits got it right: sites should be minimal, functional, with everything designed to help the user complete a task, and then go. But that doesn’t mean that you need to make a separate mobile site from your normal site. If your normal site isn’t minimal, functional, with everything designed to help the user complete a task, it’s time to rethink your whole site.

“And once you’ve done that, serve it to everyone, whatever the device.”

In a previous article, Nielsen wrote in September 2011 that he dropped testing usability with featurephones:

“Our first research found that feature phone usability is so miserable when accessing the Web that we recommend that most companies don’t bother supporting feature phones.

“Empirically, websites see very little traffic from feature phones, partly because people rarely go on the Web when their experience is so bad, and partly because the higher classes of phones have seen a dramatic uplift in market share since our earlier research.”

This is a highly westernized view. Many people can’t afford smartphones, so they use feature phones running proxy browsers (such as Opera Mini), which move the heavy lifting to servers. This is often the only way that underpowered featurephones can browse the Web. Statistics from Opera’s monthly State of the Mobile Web report (disclosure: Opera is my employer) shows that lower-end feature phones still dominate the market in Eastern Europe, Africa and other emerging economies—see the top 20 handsets worldwide for 2011 that accessed Opera Mini. Since February 2011, the number of unique users of Opera Mini has increased 78.17% and data traffic is up 142.79%.

A caveat about those statistics: not every user of Opera Mini is a featurephone user in developing countries. They’re widely used on high-end smartphones in the West, too, as we know that they are much faster than built-in browsers, and users really want speed.

Nielsen’s dismissal of feature phones reminds me of some attitudes to Web accessibility in the early 2000′s. His assertion that companies shouldn’t support feature phones because they see little traffic from feature phones is the classic accessibility chicken and egg situation: we don’t need to bother with making our website accessible, as no-one who visits us needs it. This is analogous to the owner of a restaurant that is up a flight of stairs saying he doesn’t need to add a wheelchair ramp as no-one with a wheelchair ever comes to his restaurant. It’s flawed logic.

Developing Usable Websites For All Devices

The W3C Mobile Web best practices say:

“One Web means making, as far as is reasonable, the same information and services available to users irrespective of the device they are using. However, it does not mean that exactly the same information is available in exactly the same representation across all devices. The context of mobile use, device capability variations, bandwidth issues and mobile network capabilities all affect the representation. Furthermore, some services and information are more suitable for and targeted at particular user contexts.”

There will always be edge cases when separate, mobile-specific websites will be a better user experience, but this shouldn’t be your default when approaching the mobile Web. For a maintainable, future-friendly development methodology, I recommend that your default approach to mobile be to design one website that can adapt to different devices with viewport, Media Queries and other technologies that are often buzzworded “Responsive Design.”

Combining these techniques in a smart way with progressive enhancement allows your content to be viewed on any device (and with richer experiences available on more sophisticated devices), with the possibility of accessing device APIs such as geolocation, or the shiny new getUserMedia for camera access.

Although many other resources are available, I’ve written “Mobile-friendly: The mobile web optimization guide” which you’ll hopefully find a useful starting point.

Further Reading

(jvb) (il)



© Bruce Lawson for Smashing Magazine, 2012.


Designing With Audio: What Is Sound Good For?


  

Our world is getting louder. Consider all the beeps and bops from your smartphone that alert you that something is happening, and all the feedback from your appliances when your toast is ready or your oven is heated, and when Siri responds to a question you’ve posed. Today our technology is expressing itself with sound, and, as interaction designers, we need to consider how to deliberately design with audio to create harmony rather than cacophony. The cacophony is beautifully captured in Chris Crutchfield’s video, in which he interprets the experience of receiving email, SMS texts, phone calls, Facebook messages and tweets all at the same time:

In this article, we’ll explore some of the uses of audio, where we might find it and when it is useful. This is meant not as a tutorial but rather as a discussion of some basics on using audio feedback.

Audio is a form of feedback that can be used either in combination with other forms, such as haptics, visual displays and LEDs, or on its own. We have to weigh several factors when designing feedback mechanisms: the scenario, the device and the interaction, where and how the device will be used, whether the user has a screen or display, whether the device has physical buttons or a touchscreen, where the user is relative to the device, and so on

Ear buds
(Image credit: Fey Ilyas)

For every action of the user, a good experience will include feedback that the action has been registered; for example, pressing a number key on a mobile phone would play a sound and show the number being pressed. Audio is particularly useful when there is no screen or when looking at the screen is not possible or not desirable (such as when users want to multitask). It’s interactive, creating a dialog with the user. It is also particularly good at providing feedback as “shared audio,� a form of feedback that reaches multiple people at once, such as a PA system or a citywide emergency warning system.

Audio is not always warranted. Something that makes noise repeatedly when other feedback would suffice is annoying. Audio that is private and intended for you but is heard by others is embarrassing, such as when your phone rings and announces a “Call from Sexy Neighbor.� Audio design has many ins and outs, but let’s start with some common uses of audio feedback.

Where We Find Audio

Many of us who work on interaction, mobile, device or game design have already discovered the importance of designing audio — audio is everywhere.

Mobile

Much of the Web is moving to mobile, which of course entails smaller screens and people on the go. But besides creating mobile-specific websites, there are ways to augment the mobile experience with audio when people aren’t looking at or can’t interact with the screen. A great example is GPS and turn-by-turn navigation systems that speak directions (either as part of a dedicated device or from a smartphone app). While audio isn’t yet native to mobile websites and apps, it is native to smartphones to indicate new email, incoming text messages and calendar events.

Gaming

For those who play video games, audio is integral to setting the mood, environment and situation, and it engages the user tremendously. First-person shooter games such as Halo and Call of Duty rely on audio feedback to show cause and effect — for example, the sound of a gun shooting and the moment of impact on the enemy. Or consider Wii Sports: the smash of the ball in tennis, the crack of the bat in baseball, and the cheer of fans all help to blur the line between the very physical game and the digital world.

Consumer Devices

As more appliances become smarter and connected, they might have more to say. Today a set of beeps tells you that the refrigerator door is open, but in the future you can expect notifications that the milk has gone bad or that you need to pick up eggs if you want to make that cake for your spouse’s birthday on Tuesday.

More and more of our everyday devices use audio feedback: a Bluetooth headset tells you who is calling, Nike+ tells you your current distance travelled and pace, and cars beep to help you park.

Speech Recognition and Robots

Voice interaction such as Siri’s is revolutionizing the way people interact with their iPhone and will help to change future interactions with all devices and information sources. People are beginning to talk to their devices and expect some audio feedback in return. Siri is just the start; we’re starting to see speech recognition in Xbox Kinect, Samsung TVs and more. Audio feedback is a natural way to let the user know that the system or device has heard them, is processing their request and so on.

Think of your favorite robots — HAL, Wall-E or any of the personal robotic devices that are emerging. These robots are developing human characteristics, with sounds being one of the strongest ways to deliver emotion. Leila Takayama of Willow Garage has talked about the “design challenge in communicating internal robot states and requests to effectively reach the robot’s assigned goals.â€� Willow Garage has created a set of sound libraries for communication between people and robots that might help make robots “more appealing.â€� Then there are other robots that speak English and other languages, such as the new Autom weight-loss coach. Studies have shown that people who use Autom stick with their diet and exercise routines for twice as long as people who use traditional weight-loss methods, perhaps partly because of its human-like interactions.

Why Use Audio?

There are numerous principles to determine why and when to use audio in designing interactions for devices. Being conscious about adding sound to a device is the first step in designing it right. The point is to do it deliberately, not as an afterthought, so that the audio means something and is not annoying. Here are some of the many scenarios in which you should consider using audio.

Instructions and Information

Audio is used to give instructions, especially where there is no screen or where looking at a screen would be difficult, unsafe or impossible. Again, think turn-by-turn directions. Or it can be used to augment visuals. The parking machine below obviously has visual instructions for entering a credit card, but they weren’t sufficient to get people to enter it correctly.

Audio can be used to offer information, either when no screen is available or when certain details would be better captured as audio. The Jambox by Jawbone tells the user when they need to recharge the battery. The Leapfrog LeapPad takes this one step further by specifying the type of batteries it needs!

Feedback and Interaction

As mentioned, audio is used as a feedback mechanism when the user takes action. This could be feedback for when the user pushes a button, such as when turning on a Jambox speaker, or to tell a driver that they are getting close to a parked car.

It’s also used to allow for interaction and conversation with our devices. We’re used to interacting with speech-recognition systems when we call an airline or a bank, and now sending a text message with your voice from a Windows phone is just as easy. The audio from these services and devices create a dialog that enables users to get things done.

Personalization and Customization

Audio allows for personalization of a device, helping to engage users and create an emotional attachment. Siri learns its user’s name and uses it in its replies, adding a personal connection to the interaction. Garmin and TomTom let users download all kinds of voices to their GPS devices, from Bert and Ernie to Star Wars characters to Kitt from Knight Rider, with the goal of creating more engaging experiences. Jawbone device owners can download different languages and characters to their Bluetooth headset and speaker, with the device volunteering such responses as, “A bombshell is whispering in my ear… And yes, I’m blushing.�

Audio also helps to establish personality and to humanize a device. Ford and other electric vehicle manufacturers are dealing with a proposed bill that would require electric vehicles to make some sound to ensure pedestrian safety. Ford has asked the public to vote on four different sounds that would essentially shape the personality of its cars. Here’s one of them:

In another example, to show the power of talking devices, Radio Lab reported on an experiment that pitted a hamster against a Barbie doll and a Furby (the popular furry electronic talking robot) to see how long kids could hold each of them upside down. While all of the five kids in the experiment could hold Barbie upside down “almost forever,� they treated Furby much more like the living hamster than the Barbie. Why? Well, when you hold Furby upside down, he says, “Me scared,� giving human-like characteristics to the toy. The kids said afterwards that they “didn’t want him to be scared.�

Conclusion

Audio is everywhere, and there are good reasons to use it: to instruct, enhance and engage and to personalize experiences. But if poorly designed or used inappropriately, it can detract from the experience and be annoying. We’ve covered the why and the where of audio. Next time, we’ll review some guidelines and principles on the ins and out of designing with audio.

(al)


© Karen Kaushansky for Smashing Magazine, 2012.


End tags, semi-colons and maintainable code

In Of parser-fetishists and semi-colons, Chris Heilmann brings up the importance of code maintainability, something that I feel is overlooked a bit too often.

The main issue Chris talks about is omitting semi-colons at the end of JavaScript statements, the subject of a current JavaScript drama. Doing so is valid syntax in many cases, and browsers parse and execute the code fine. However, it does not improve code readability for humans, who are often as important to target as the browsers that run the code.

Read full post

Posted in , , .

Copyright © Roger Johansson



Beercamp: An Experiment With CSS 3D


  

I recently had the pleasure of organizing this year’s Beercamp website. If you’re unfamiliar, Beercamp is a party for designers and developers. It’s also a playground for front-end experimentation. Each year we abandon browser support and throw a “Pshaw� in the face of semantics so that we can play with some emerging features of modern browsers.

This year’s experiment: a 3D pop-up book á la Dr. Seuss. If you’ve not seen it, hop on over and take a look. The website was a test to see how far SVG and CSS 3D transforms could be pushed. I learned a lot in the process and wanted to share some of the techniques that I found helpful when working in 3D space.


“Beercamp 2012: A Tale of International Mischief�

Before we jump in, please note that explaining everything about the website without boring you to death would be damn near impossible. For your sake and mine, I’ll provide just brief takeaways. As you skim through the code snippets, be aware that jQuery is being used and that a lot of code has been removed for simplicity (including browser prefixes).

Finally, please remember that this is an experiment! It will not work in all browsers. It does not degrade gracefully, and the markup is less than poetic. Put your convictions on hold for a moment and let’s have some fun.

Takeaway #1: Exploring 3D Space Is Fun

Before I started building the Beercamp website, I did some “research� into what makes pop-up books so much fun. As I flipped through the paper-crafted version of Dr. Seuss’ Oh, the Places You’ll Go, I found myself inspecting each page from multiple angles. Seeing how things looked from different perspectives was fun, and interacting with the environment was engaging.


The inspiration for Beercamp: Dr. Seuss’ “Oh, the Places You’ll Go.�

I wanted to create that same engagement in my digital version with intuitive and unobtrusive controls. Thus, the scene rotates based on the mouse’s coordinates, allowing the user to move the book around without much effort. Achieving this was pretty easy:

1. Set up a listener.

This is for the mousemove event.

$document.mousemove(rotateScene);

2. Calculate the rotation.

I wanted the book to rotate between -15 and 15 degrees, based on where the mouse is located along the x axis. This can be calculated using the following:

rotationY = -15 + (30 * e.pageX / $body.width());

3. Apply the rotation.

$scene.css('transform': 'rotateY(' + rotationY + 'deg)');

Pretty simple, right? The only problem is that our friends on iPhones and iPads don’t have mouse coordinates. They do, however, have a gyroscope. Rotating a phone is very similar to rotating a book, so adjusting the scene based on the device’s orientation made for an intuitive and delightful interaction. Setting this up was similar but slightly more involved.

1. Set up a listener.

window.addEventListener('deviceorientation', rotateScene, false);

2. Determine the orientation.

Before we can calculate the rotation, we need to know whether the device is in landscape or portrait mode. This can be determined by evaluating window.orientation:

  • Landscape
    Math.abs(window.orientation) == 90
  • Portrait
    window.orientation == 0


Determine the device’s orientation by evaluating window.orientation.

3. Calculate the rotation.

Now that we have the orientation, we can pull in the appropriate values from the gyroscope. If the device is in landscape mode, we’ll tap the beta property. Otherwise, we’ll use gamma.

var theta = (Math.abs(window.orientation) == 90) ? e.beta : e.gamma;
rotationY = 0 + (15 * (theta / -45));


The deviceorientation event enables us to pull alpha, beta and gamma rotation values. Note that these values are relative to the current orientation of the device. The image above shows the axes of a phone held perpendicular to the ground in portrait mode.

4. Apply the rotation.

$scene.css('transform': 'rotateY(' + rotationY + 'deg)');

Takeaway #2: Depth-Sorting Is Notoriously Buggy

A number of browsers support 3D transforms, but few do so elegantly. Apart from general efficiency issues, the biggest hindrance is improper depth-sorting.

Depth-sorting is required when two planes intersect in three-dimensional space. The rendering engine must determine which plane (or, more specifically, which areas of the plane) should be rendered and which should be clipped.


Depth-sorting varies across browsers.

Unfortunately, each browser implements depth-sorting differently and, therefore, has its own issues. The best we can do to combat the glitchy pop-through of underlying elements is to keep planes away from each other.

The Beercamp website involves numerous plane intersections. Initially, I had all of the pages rotating around the same point in 3D space (0, 0, 0). This meant that just about every plane in the book was fighting to be on top. To counter this, the pages needed to be positioned as if they were next to each other along the spine of an actual book. I did this by rotating the pages around an arc, with the open page at the pinnacle.


Rotating pages around an arc helps to prevent clipping.

function updateDrag(e) {
    …
    // operate on each spread
   $('.spreads li').each(function(i) {
        // calculate the angle increment
        var ANGLE_PER_PAGE = 20;

        // determine which slot this page should be turned to
        var offsetIndex = per < 0 ? 5 + curPageIndex - i : 5 + curPageIndex - i - 2;

        // calculate the angle on the arc this page should be turned to
        var offsetAngle = per < 0 ? offsetIndex - per - 1 : offsetIndex - per + 1;

        // calculate the x coordinate based on the offsetAngle
        var tarX = 5 * Math.cos(degToRad(offsetAngle * ANGLE_PER_PAGE + 10));

        // calculate the z coordinate based on the offsetAngle
        var tarZ = 5 * Math.sin(degToRad(offsetAngle * ANGLE_PER_PAGE + 10));

        // position the page
        $(this).css('transform', 'translateX(' + tarX.toFixed(3) + 'px) translateZ(' + tarZ.toFixed(3) + 'px)');
    });
}

This technique helped to clear up most of the depth-sorting issues, but not all of them. Further optimization really relies on the browser vendors. Safari seems to have things worked out on both desktop and mobile. Chrome Stable struggles a bit, but the latest Canary works wonderfully. Firefox does a fine job but suffers from slow frame rates. It’s a tough battle to win right now.

Takeaway #3: Vector Space Is Tricky But Useful

Building the pop-ups was by far the most difficult aspect of the project, but also the most satisfying. Other pop-up books have been built on the Web, but I’m unaware of any that use realistic pop-up mechanics. This is with good reason — achieving it is deceptively complex.

The magic of programming pop-up mechanics lies in the calculation of vector space. A vector is essentially a line. Knowing the lengths and directions of lines enables us to perform operations on them. Of particular use when building pop-ups is the vector cross product, which is the line that runs perpendicular to two other lines in 3D space.

The cross product is important because it determines the upward rotation of each pop-up piece. I’ll spare you the headache of play-by-play calculations (you can view the math below if you’re really interested). Instead, let’s try a visual representation.


The vector cross product in action.

We start by determining two points where each pop-up piece touches the page within 3D space. Those points are used to define a vector for each pop-up piece (the red lines). Using those vectors, we can calculate their cross product (the blue line), which is essentially the line at which a physical pop-up folds in half. Rotating each piece up to the cross product then gives us perfectly aligned pop-ups!

This is not exactly easy math in my opinion, but it is extremely useful. If you’re interested in playing with vectors, I strongly recommend Sylvester. It really simplifies vector math.

function setFold() {
    var points = [];

    // origin
    points[0] = [0, 0, 0];

    var adj = Math.sqrt(Math.pow(POPUP_WIDTH, 2) - Math.pow(POPUP_WIDTH * Math.sin(degToRad(-15)), 2));

    // left piece: bottom outside
    points[1] = [-adj * Math.cos(degToRad(-180 * fold)), adj * Math.sin(degToRad(-180 * fold)), POPUP_WIDTH * Math.sin(degToRad(-15))];

    // right piece: bottom outside
    points[2] = [adj * Math.cos(degToRad(-180 * 0)), POPUP_WIDTH * Math.sin(degToRad(-180 * 0)), POPUP_WIDTH * Math.sin(degToRad(-15))];

    // left piece: top inside
    points[3] = [-POPUP_WIDTH * Math.cos(degToRad((-180 * fold) - 90)), POPUP_WIDTH * Math.sin(degToRad((-180 * fold) - 90)), 0];

    var len = Math.sqrt(Math.pow(points[1][0], 2) + Math.pow(points[1][1], 2) + Math.pow(points[1][2], 2));

    // normalize the vectors
    var normV1 = $V([points[1][0] / len, points[1][1] / len, points[1][2] / len]);
    var normV2 = $V([points[2][0] / len, points[2][1] / len, points[2][2] / len]);
    var normV3 = $V([points[3][0] / len, points[3][1] / len, points[3][2] / len]);

    // calculate the cross vector
    var cross = normV1.cross(normV2);

    // calculate the cross vector's angle from vector 3
    var crossAngle = -radToDeg(cross.angleFrom(normV3)) - 90;

    // transform the shape
    graphic.css('transform', 'translateY(' + depth + 'px) rotateZ(' + zRot + 'deg) rotateX(' + crossAngle + 'deg)');
}

Takeaway #4: SVG Is Totally Tubular

I know, I know: you’ve heard the case for SVG before. Well, you’re going to hear it again. SVG is an incredible technology that works really well in 3D space. All of the illustrations on the Beercamp website were done in Illustrator and exported to SVG. This provided numerous benefits.

Benefit 1: Size

Because the pop-up pieces required large areas of transparency, the file-size savings of SVG were enormous. PNG equivalents would have been 200 to 300% larger than the uncompressed SVGs. However, we can reduce file size even more by exporting illustrations as SVGZ.

SVGZ is a compressed version of SVG that is incredibly small. In fact, the SVGZ files for Beercamp are up to 900% smaller than their PNG equivalents! Implementing them, though, requires some server configuration. This can be done easily with an .htaccess file:

AddType image/svg+xml svg svgz
AddEncoding gzip svgz

Benefit 2: Flexibility

The flexibility of SVG is perhaps its most highlighted benefit. The graphics on the Beercamp website are scaled in 3D space to fill the browser window. There are also hotspots on each page that allow the user to zoom in for more details. Because everything is handled with SVG, the illustrations remain crisp and clean regardless of how they’re manipulated in 3D space.


SVG files are inherently responsive.

Benefit 3: Self-Contained Animation

All of the SVGs on the Beercamp website are implemented as background images. This helps to keep the markup clean and allows images to be reused in multiple locations, such as with the pop-up pieces. However, this means we lose DOM access to each of the nodes. So, what if we need some animation on the background SVGs?

SVG allows us to define animations within the file itself. All of the pop-up images in the final Beercamp website are static, but an earlier version featured animated beer bubbles. To increase performance in some of the less-capable browsers, these were taken out. However, the SVG animations ran very smoothly in WebKit.

SVG animation gets less hype than its CSS cousin, but it’s just as capable. Within an element, we can add an animate node to specify typical animation settings: properties, values, start time, duration, repeat count, etc. Below is an excerpt from one of the Beercamp bubbles.

<circle fill="#fff" opacity=".4" clip-path="url(#right-mug-clip)" cx="896" cy="381" r="5">
    <animate attributeType="XML" attributeName="cx" from="890" to="881" begin="7s" dur="5s" repeatCount="indefinite" />
    <animate attributeType="XML" attributeName="cy" from="381" to="100" begin="7s" dur="5s" repeatCount="indefinite" />
</circle>

Takeaway #5: Experimentation Is Messy But Important

Now that the practical tidbits are out of the way, I’d like to say a word about experimentation.

It’s easy to get boxed in by the reality of developing websites that are responsive, cross-platform, cross-browser, gracefully degrading, semantically perfect, progressively enhanced, _______, _______ and _______ (space to fill in upcoming buzzwords). These techniques are useful on production websites to ensure reach and consistency, but they can also limit our creativity.

I’ll be the first to admit it: the Beercamp website is buggy. Browser support is limited, and usability could be improved. However, the website is an experiment. It’s meant to explore what’s possible, not satisfy what’s practical.

A dogma is emerging in our industry — and the buzzwords above are its doctrine. Experimentation enables us to think beyond that dogma. It’s a wonderful exercise that indulges our curiosity, polishes our talent and ultimately advances our industry. If you’re not experimenting in some capacity, you should be.

The State of CSS 3D

CSS 3D has yet to hit a tipping point. Browsers simply don’t support it well enough, but there is promise on the horizon. Mobile Safari, with its hardware acceleration, renders 3D transforms extremely fast and with very little depth-sorting issues. It’s only a matter of time until other manufacturers release stable implementations. It’ll be interesting to see how CSS 3D techniques hold up against other emerging technologies, such as WebGL.

Remember Flash? Me neither.

You’re Invited

By the way, Beercamp is being thrown by nclud at the Front-Trends Conference in Warsaw. If you’re headed to the conference, you should stop by and say hello!

Related Links

(al)


© Tom Giannattasio for Smashing Magazine, 2012.


A New Front-End Methodology: BEM


  

This article is the sixth in our new series that introduces the latest, useful and freely available tools and techniques, developed and released by active members of the Web design community. The first article covered PrefixFree; the second introduced Foundation, a responsive framework; the third presented Sisyphus.js, a library for Gmail-like client-side drafts, the fourth shared with us a free plugin called GuideGuide and the fifth presented Erskine Design’s responsive grid generator Gridpak. Today, we are happy to feature a toolkit devised by Yandex: BEM.

BEM stands for “Block”, “Element”, “Modifier”. It is a front-end methodology: a new way of thinking when developing Web interfaces. This article will elaborate on the theory as well as the practice of building websites at Yandex—one of the leading internet companies in Russia.

To begin, let’s first put BEM in some historical perspective.

We first began sketching out the internal front-end framework at Yandex around the year 2007, starting with a robust CSS naming convention, and a file system layout that was associated with it. Since the naming convention was well-structured, it seemed suitable to develop certain JavaScript helpers (to work with the DOM and CSS classes in particular, on a higher level of abstraction). We then used those approaches to build an internal library of UI components that could be shared among our various websites and rich applications, built using different technology stacks (XML/XSLT, Python/Django, Perl/TT2).

As our ambitions, complexity and performance requirements grew, we aimed at replacing XSLT and Perl templates with a JS-based declarative templating DSL, built on top of Node.js. Along with those efforts, we looked into simplifying development workflow and developed a bunch of command-line tools that already helped us manage front-end code on the file system, preprocess CSS and JavaScript code, and so on, and so forth.

Some parts of the BEM stack started as open source projects, while others (like the UI component library) are being gradually open sourced. Our goal is to publish most of them during 2012.

BEM is a toolkit that will help address and resolve front-end issues quickly and effectively. It is available in a range of reusable code libraries—all of them are hosted on Github and are completely open source.

BEM Principles

One of the most common examples of a methodology in programming is Object-Oriented Programming. It’s a programming paradigm embodied by many languages. In some ways, BEM is similar to OOP—a way of describing reality in code, with a range of patterns, and a way of thinking about program entities regardless of the programming languages being used.

We’ve used BEM principles to create a set of front-end development techniques and tools that allow us to build websites quickly and maintain them over a long period of time. The principles are the following:

Unified Data Domain

Imagine an ordinary website, like the one pictured below:

ordinary website example

While developing such a website, it’s useful to mark out “blocks” from which the website consists of. For example, in this picture there are Head, Main Layout and Foot blocks. The Head in turn consists of Logo, Search, Auth Block and Menu. Main Layout contains a Page Title and a Text Block:

site marked

Giving each part of the page a name is very useful when it comes to team communication.

A project manager could ask:

  • To make the Head bigger, or
  • To create a page without a Search form in the Head.

An HTML guy could ask a fellow JavaScript developer:

  • To make Auth Block animated, etc.

Let’s now take a closer look at what constitutes BEM:

Block

A block is an independent entity, a “building block” of an application. A block can be either simple or compound (containing other blocks).

Example
Search form block:

search form block

Element

An element is a part of a block that performs a certain function. Elements are context-dependent: they only make sense in the context of the block that they belong to.

Example

An input field and a button are elements of the Search Block:

elements of search block

Means Of Describing Pages And Templates

Blocks and elements constitute page content. Besides simply being present on a page, their arrangement is also important.

Blocks (or elements) may follow each other in a certain order. For example, a list of goods on a commerce website:

list of goods on a commerce website

…or menu items:

menu items

Blocks may also be contained inside other blocks. For example, a Head Block includes other blocks:

blocks inside other blocks

Besides, our building blocks need a way to describe page layout in plain text. To do so, every block and element should have a keyword that identifies it.

A keyword designating a specific block is called Block Name. For example, Menu can be a keyword for the Menu Block and Head can be a keyword for the Head block.

A keyword designating an element is called Element Name. For example, each item in a menu is an element Item of the Menu block.

Block names must be unique within a project to unequivocally designate which block is being described. Only instances of the same block can have the same names. In this case, we can say that one block is present on the page twice (or 3, 4, times… etc.).

Element names must be unique within the scope of a block. An element can be repeated several times. For example, menu items:

repeated elements

Keywords should be put in a certain order. Any data format that supports nesting (XML, JSON) will do:

<b:page>
  <b:head>
    <b:menu>
      ...
    </b:menu>
    <e:column>
      <b:logo/>
    </e:column>
    <e:column>
      <b:search>
        <e:input/>
        <e:button>Search</e:button>
      </b:search>
    </e:column>
    <e:column>
      <b:auth>
        ...
      </b:auth>
    <e:column>
  </b:head>
</b:page>

In this example, b and e namespaces separate block nodes from element nodes.

The same in JSON:

{
  block: 'page',
  content: {
    block: 'head',
    content: [
      { block: 'menu', content: ... },
      {
        elem: 'column',
        content: { block: 'logo' }
      },
      {
        elem: 'column',
        content: [
          {
            block: 'search',
            content: [
              { elem: 'input' },
              {
                elem: 'button',
                content: 'Search'
              }
            ]
          }
        ]
      },
      {
        elem: 'column',
        content: {
          block: 'auth',
          content: ...
        }
      }
    ]
  }
}

Examples above show an object model with blocks and elements nested inside each other. This structure can also contain any number of custom data fields. We call this structure BEM Tree (by analogy with DOM tree).

Final browser markup is generated by applying template transformations (using XSL or JavaScript) to a BEM tree.

If a developer needs to move a block to a different place on a page, he does so by changing the BEM tree. Templates generate the final view themselves.

In our recent products we went with JSON as a page description format. It is then turned into HTML by a JS-based template engine. The tools we use are listed at the end of this article.

Block Independence

As projects grow, blocks tend to be added, removed, or moved around on the page. For example, you may want to swap the Logo with the Auth Block, or place the Menu under the Search Block.

swapping blocks

To make this process easier, blocks must be Independent.

An Independent block is implemented in a way that allows arbitrary placement anywhere on the page—including nesting inside another block.

Independent CSS

From the CSS point of view it means that:

  • A block (or an element) must have a unique “name” (a CSS class) that could be used in a CSS rule.
  • HTML elements must not be used in CSS selectors (.menu td) as such selectors are inherently not context-free.
  • Cascading selectors for several blocks should be avoided.
Naming for Independent CSS Classes

One of the possible naming schemes for CSS classes that satisfies said requirements is the following:

  • CSS class for a block coincides with its Block Name.
<ul class="menu">
  ...
</ul>
  • CSS class for an element is a Block Name and an Element Name separated by some character(s)
<ul class="menu">
  <li class="menu__item">
    ...
  </li>
  <li class="menu__item">
    ...
  </li>
</ul>

It’s necessary to include block name in a CSS class for an element to minimize cascading. It’s also important to use separators consistently to allow the tools and helpers to have unambiguous programmatic access to the elements.

Different naming schemes can be used. Take a look here for the naming convention we used.

Independent Templates

From the template engine’s perspective, block independence means that:

  • Blocks and elements must be described in the input data.
    Blocks (or elements) must have unique “names” to make things like “Menu should be placed here” expressible in our templates.
  • Blocks may appear anywhere in a BEM tree.
Independent templates for blocks

When coming across a block in a template, the template engine should be able to unambiguously transform it into HTML. Thus, every block should have a template for that.

For example, a template can look like this in XSL:

<xsl:template match="b:menu">
  <ul class="menu">
    <xsl:apply-templates/>
  </ul>
</xsl:template>

<xsl:template match="b:menu/e:item">
  <li class="menu__item">
    <xsl:apply-templates/>
  </li>
<xsl:template>

We are gradually discarding XSLT in our products in favor of our own JavaScript-based template engine XJST. This template engine absorbs everything we like about XSLT (we are fans of declarative programming), and implements it with JavaScript’s productivity on either the client or the server side.

We, at Yandex, write our templates using a domain-specific language called BEMHTML, which is based on XJST. The main ideas of BEMHTML are published in the BEM club on Ya.Ru (in Russian).

Blocks Reiteration

The second Menu Block can occur in the Foot Block of a website. Also, a Text Block can divide into two, separated by an advertisement.

Even if a block was developed as a singular unit, the same one can appear on a page at any moment.

In CSS related terms, this means:

  • ID-based CSS selectors must not be used.
    Only class selectors satisfy our non-uniqueness requirement.

On the JavaScript side it means:

  • Blocks with similar behavior are detected unequivocally—they have the same CSS classes.
    Using CSS class selectors allows for picking all blocks with a given name to apply the required dynamic behavior.

Modifiers For Elements And Blocks

We often need to create a block very similar to an existing one, but with a slightly altered appearance or behavior.
Let’s say, we have a task:

  • Add another Menu in the Footer with a different layout.

To avoid developing another block that is only minimally different from an existing one, we can use a Modifier.

A Modifier is a property of a block or an element that alters its look or behavior. A modifier has both a name and a value. Several modifiers can be used at once.

Example:
A block modifier specifies background color

search background

Example:
An element modifier changes the look of the “current” item

current item in menu

From the input data point of view:

  • In a BEM tree, modifiers are properties of an entity that describes a block or an element.

For example, they can be attribute nodes in XML:

<b:menu m:size="big" m:type="buttons">

  ...
</b:menu>

The same expressed in JSON:

{
  block: 'menu',
  mods: [
   { size: 'big' },
   { type: 'buttons' }
  ]
}

From the CSS point of view:

  • A modifier is an additional CSS class for a block or an element.
<ul class="menu menu_size_big menu_type_buttons">
  ...
</ul>
.menu_size_big {
  // CSS code to specify height
}
.menu_type_buttons .menu__item {
  // CSS code to change item's look
}

Element modifiers are implemented in the same fashion. Again, when writing CSS by hand, it’s very important to use separators consistently for programmatic access.

E.g., current menu item can be marked with a modifier:

<b:menu>
  <e:item>Index<e:item>
  <e:item m:state="current">Products</e:item>
  <e:item>Contact<e:item>
</b:menu>
{
  block: 'menu',
  content: [
    { elem: 'item', content: 'Index' },
    {
      elem: 'item',
      mods: { 'state' : 'current' },
      content: 'Products'
    },
    { elem: 'item', content: 'Contact' }
  ]
}
<div class="menu">
  <ul class="menu__layout">
    <li class="menu__layout-unit">
      <div class="menu__item">Index</div>
    </li>
    <li class="menu__layout-unit">
      <div class="menu__item menu__item_state_current">Products</div>
    </li>
    <li class="menu__layout-unit">
      <div class="menu__item">Contact</div>
    </li>
  </ul>
</div>
.menu__item_state_current {
  font-weight: bold;
}

Subject-Matter Abstraction

When many people work on a project, they should agree on a data domain and use it when naming their blocks and elements.

For example, a Tag Cloud block is always named Tags. Each of its elements is a Tag. This convention spreads across all languages: CSS, JavaScript, XSL, etc.

From the development process’ point of view:

  • All participants operate on the same terms.

From the CSS point of view:

  • CSS for blocks and elements can be written in a pseudo language that compiles down to CSS according to the naming convention.
  .menu {
    __layout {
      display: inline;
    }
    __layout-item {
      display: inline-block;
      ...
    }
    __item {
      _state_current {
        font-weight: bold;
      }
    }
  }

On the JavaScript side:

  • Instead of using class selectors directly to find DOM elements, a special helper library may be used.
$('menu__item').click( ... );
$('menu__item').addClass('menu__item_state_current');
$('menu').toggle('menu_size_big').toggle('menu_size_small');

The naming convention for CSS classes of blocks and elements can change over the course of time. Using special JavaScript functions to access blocks and elements (and to work with their modifiers) makes it possible to change only these functions if the naming convention changes.

Block('menu').elem('item').click( ... );
Block('menu').elem('item').setMod('state', 'current');
Block('menu').toggleMod('size', 'big', 'small');

The code above is abstract. In real life we use the JavaScript core of i-bem block from the bem-bl block library: http://bem.github.com/bem-bl/sets/common-desktop/i-bem/i-bem.ru.html (described in Russian)

Blocks Consistency

A website has a Button block with certain dynamic behavior.

When a block is hovered, it changes its appearance.

A manager could ask:

  • To use the same button on another page.

Having a CSS implementation of a block is not enough. Reusing a block also means reusing its behavior, described in JavaScript.

So a block must “know” everything about itself. To implement a block, we describe its appearance and behavior in all technologies being used—we call that Multilingualism.

Multilingual presentation is a description of a block in all the programming languages that are necessary to implement the view and the functionality of that block.

To have a block present on a page as a UI element, we need to implement it in the following techs:

  • Templates (XSL, TT2, JavaScript, etc), which turn block declarations into HTML code.
  • CSS that describes appearance of the block.

If a block has dynamic behavior, we add it to this list:

  • A JavaScript implementation for the block.

Everything that constitutes a block is a technology, including images.

File System Representation For A Block

Unequivocal Placement of Code

File Naming

When a project is:

  • Long-lived and under constant development.

If the development team:

  • Consists of several people.
  • Grows and changes.

Then being able to navigate the code base quickly is crucial.

Block code is easiest to find when it’s placed in files using the same naming scheme as the one we use for naming our entities:

menu.xsl
menu.js
menu.css
Expressing Blocks on a File System

There could be a task:

  • To reuse some blocks from a previous project for a new one.

We want the procedure of block reuse to be as simple as possible—like simply copying the files, or using partial checkout of a repository from a “donor” project. In both cases, it is useful to have all of the files under the same directory:

menu/
  menu.xsl
  menu.js
  menu.css
File Structure of a Block

When working on a project we might need to change a block at some point.

A manager could ask:

  • To change the color of the Current Menu Item, or
  • To make the Menu react on hover.

A developer could ask their colleague:

  • To help with Search Form styling for IE.

To understand where the relevant code is located, follow these (or similar) rules:

  • Block code is placed in a separate directory.
    • Directory name matches block name.
    • Implementation is placed under this directory.
  • Elements are placed in subdirectories under the block directory.
    • Directory name matches element name.
    • Implementation is placed under this directory.
  • Modifiers are placed in subdirectories under the block directory.
    • Directory name matches modifier name.
    • Implementation is placed under this directory.
    • File name includes both key and value of the modifier (again, for programmatic access).

Example
File structure of a Menu block:

menu/
  __item/
    _state/
      menu__item_state_current.css
      menu__item_state_current.xsl
    menu__item.css
    menu__item.xsl
  menu.css
  menu.js
  menu.xsl

Maintaining such file structure manually is, quite obviously, inconvenient. So we’ve developed BEM Tools to handle the burden. These tools help with creating the directory structure, placing files, generating placeholder content, etc.

Grouping Blocks in Directories

Big internet portals often need to reuse the same blocks across different websites.

There could be a task:

  • To create the same Footer on all the portals’ websites, or
  • To create a new project using blocks from the existing websites.

Working for a Web design agency often means that one has to use typical solutions for typical Web pages.

A project manager could ask you:

  • To create an order page with a Web form as on the previous project.

We have to do these tasks while preferably avoiding copying blocks around manually. So it’s nice to have a repository of shared blocks that can be linked to a project. Blocks should then be united under a single directory for that.

Such a directory is usually called Blocks.

E.g.

blocks/
  foot/
  head/
  menu/
  page/
  search/

That directory can be linked to another project straight from the version control system, so that we can make changes to shared blocks in a single location.

Levels Of Definition

If a group of blocks (united under one directory) is linked to a project directly (via a partial checkout, svn:externals, etc.), then every change committed to these blocks influences all projects.

When developing a website based on an existing one, we might want:

  • To enlarge the font in the Head on site A without affecting site B.
  • To add animation when showing a drop-down menu.

To do so, we need to be able to define or redefine blocks in different technologies for a specific website only, or for certain pages only. This can be achieved using Definition Levels.

A Definition Level is a set of blocks grouped in one directory.

An implementation of every block from the library can be changed (or completely redefined) at project level.

block levels

From page-building process’ perspective:

  • When building a page, we can set a list of levels (directories) to use their blocks on that page. E.g., build-page -l blocks-common -l blocks-my my-page.html

From the file structure point of view:

  • A project can have any number of levels. But only the levels that are evaluated during the build will be present on the page. It is possible to specify different sets of definition levels for different parts of the website.

On the JavaScript side:

  • We need to define dynamic behavior of a page in declarative style. Final behavior is gathered from different definition levels. E.g.,
/* blocks-common/dropdown/dropdown.js */
Block('dropdown', {
  init: function() {
    ...
  }
});

/* blocks-my/dropdown/dropdown.js */
Block('dropdown', {
  init: function() {
    this.__base();
    ...
  }
});

From the viewpoint of a template engine:

  • To be able to not only define, but to redefine a template, one needs to apply a preceding template implementation.
    E.g., for XSL:
<xsl:template match="b:head">
  <div> <!-- Node for extra design -->
    <xsl:apply-imports/>
  </div>
</xsl:template>

From the architectural point of view:

  • When developing a portal of several websites, we can extract a block library that serves as one of the definition levels for all the websites which are part of the portal. The blocks for a specific website will form another level.
  • The same repo can hold blocks of both desktop and mobile versions.
    Such a project will have the following levels: common, mobile, desktop. Different combinations of these levels give the resulting implementation, required by specific pages.

Open source block library bem-bl (in development) is an example of having several definition levels in one repository.

Building A Page

Working in terms of blocks means having a Subject-Matter Abstraction. This abstraction is for developers only, and browsers will get a compiled version of the code.

So we have Code For People and Code For Browsers—they are not the same.

  • Programmers code blocks—browsers get the code for the whole page.

To turn Code For People into Code For Browsers we Build a page.

Building A Page means generating HTML, CSS, and JavaScript code from a page declaration (written in XML or JSON) by applying implementations of declared blocks.

On the CSS side:

  • All CSS files are combined into a “single page” CSS file.
    Despite the fact that CSS for every block, element or modifier is stored in separate files, we don’t have to link these files to the page as is. It’s possible to collect all the required CSS implementations into one file.
    This also solves the well-known “number of imports” issue in IE, and decreases the number of HTTP requests. For combining CSS we use borschik.
  • Browser gets minimized code.
    When building CSS, we can minimize and optimize CSS code using the CSSO utility, for example.
  • Each browser can get CSS code written especially for it.
    It is also possible to divide CSS implementations for different browsers and deliver only the code needed for each browser.
    setochka—currently in prototype can be used for that.

From the JavaScript point of view:

  • Similarly to CSS, JavaScript files can be combined into one.

From the template engine’s point of view:

  • Only needed templates are included.
    Final set of templates that are used for displaying a page includes only the templates for required blocks. This boosts template performance and reduces the likelihood of side effects.

From the viewpoint of development process:

  • Robots serve people (not the other way around).
    Developer writes code as they see fit. “Robots” take (some) care of performance by optimizing the code (together with making it unreadable) when building a page.

In terms of work organization:

  • Division of labor.
    We have developers working on the core framework (compilers, tools, performance); library developers, who maintain the block library; application developers, who develop websites using the framework.

We use BEM tools to build pages.

How to Automate the Building Process?

The usage of bem tools requires to run several commands for each page whenever page input data or blocks implementation are changed. As a result of these commands, you get CSS and JavaScript files for the page, page’s template, and if you are developing static pages, the HTML code of your page.

To avoid running these commands manually, there is also the GNUmakefile, which was written for a project that includes the instructions on how to build pages.
You can find an example of such a file in the test project bem-bl-test.

But the usage of GNU Make has a list of problems:

  • You have to run it every time you have changed something.
  • Every time you run gmake, it reads the information from a disk. So the compilation process could not be fast.
  • The pages you build not only depend on the content of block files, but on their file structure as well. But it’s impossible to write a gmake goal dependency in these terms.

So we’d like to create something to replace GNU Make for the process of page building. This will be both a development server and a tool to build production files. Bem Server will be run in a project root directory, and give HTTP response with the page files built (so you won’t need to run gmake manually after each change).
Besides, it will be able to watch the files (the adding and removing of them) via fs.FSWatcher that help to chache results efficiently.

BEM Server is a subcommand of bem-tools. Currently it can run an HTTP server, apply BEMhtml templates to BEMjson data and inline CSS imports using borschik utility.

Real Examples

Yandex is a large (mostly Russian) company that use BEM methodology to develop its services.

BEM methodology does not request that you use a certain framework. You also don’t have to use BEM for all the technologies you have on your pages (but that would be the most efficient).

All the services of Yandex have BEM in their CSS and JavaScript code and XSL templates for their pages. E.g.,

Some services don’t use XSL templates, building their pages with our newest template product, Bemhtml template engine which was mentioned above. These are the following services:

There are also other companies that use BEM methodology.

For example, the guys at Mail.ru partly use BEM for their services. Some blocks on their pages are BEM-based in terms of CSS code. They also have their own C++ template engine, and write block templates according to this methodology.

More examples:

You also may be interested in websites that use bem-bl block library (in development):

Libraries

Tools

Additional Information

(jvb)


© Varvara Stepanova for Smashing Magazine, 2012.


  •   
  • Copyright © 1996-2010 BlogmyQuery - BMQ. All rights reserved.
    iDream theme by Templates Next | Powered by WordPress