Browsing articles in "Coding"
May
23
2013

Building The New Financial Times Web App: A Case Study


  

When the mockups for the new Financial Times application hit our desks in mid-2012, we knew we had a real challenge on our hands. Many of us on the team (including me) swore that parts of interface would not be possible in HTML5. Given the product team’s passion for the new UI, we rolled up our sleeves and gave it our best shot.

We were tasked with implementing a far more challenging product, without compromising the reliable, performant experience that made the first app so successful.

promo-500-compr

We didn’t just want to build a product that fulfilled its current requirements; we wanted to build a foundation that we could innovate on in the future. This meant building with a maintenance-first mentality, writing clean, well-commented code and, at the same time, ensuring that our code could accommodate the demands of an ever-changing feature set.

In this article, I’ll discuss some of the changes we made in the latest release and the decision-making behind them. I hope you will come away with some ideas and learn from our solutions as well as our mistakes.

Supported Devices

The first Financial Times Web app ran on iPad and iPhone in the browser, and it shipped in a native (PhoneGap-esque) application wrapper for Android and Windows 8 Metro devices. The latest Web app is currently being served to iPad devices only; but as support is built in and tested, it will be rolled out to all existing supported platforms. HTML5 gives developers the advantage of occupying almost any mobile platform. With 2013 promising the launch of several new Web application marketplaces (eg. Chrome Web Store and Mozilla Marketplace), we are excited by the possibilities that lie ahead for the mobile Web.

Fixed-Height Layouts

The first shock that came from the new mockups was that they were all fixed height. By “fixed height,” I mean that, unlike a conventional website, the height of the page is restricted to the height of the device’s viewport. If there is more content than there is screen space, overflow must be dealt with at a component level, as opposed to the page level. We wanted to use JavaScript only as a last resort, so the first tool that sprang to mind was flexbox. Flexbox gives developers the ability to declare flexible elements that can fill the available horizontal or vertical space, something that has been very tricky to do with CSS. Chris Coyier has a great introduction to flexbox.

Using Flexbox in Production

Flexbox has been around since 2009 and has great support on all the popular smartphones and tablets. We jumped at the chance to use flexbox when we found out how easily it could solve some of our complex layouts, and we started throwing it at every layout problem we faced. As the app began to grow, we found performance was getting worse and worse.

We spent a good few hours in Chrome Developers Tools’ timeline and found the culprit: Shock, horror! — it was our new best friend, flexbox. The timeline showed that some layouts were taking close to 100 milliseconds; reworking our layouts without flexbox reduced this to 10 milliseconds! This may not seem like a lot, but when swiping between sections, 90 milliseconds of unresponsiveness is very noticeable.

Back to the Old School

We had no other choice but to tear out flexbox wherever we could. We used 100% height, floats, negative margins, border-box sizing and padding to achieve the same layouts with much greater performance (albeit with more complex CSS). Flexbox is still used in some parts of the app. We found that its impact on performance was less expensive when used for small UI components.

layout-time-with-flexbox-500_comp
Page layout time with flexbox

layout-time-without-flexbox-500_comp
Page layout time without flexbox

Truncation

The content of a fixed-height layout will rarely fit its container; eventually it has to overflow. Traditionally in print, designers have used ellipses (three dots) to solve this problem; however, on the Web, this isn’t the simplest technique to implement.

Ellipsis

You might be familiar with the text-overflow: ellipsis declaration in CSS. It works great, has awesome browser support, but has one shortfall: it can’t be used for text that spans multiple lines. We needed a solution that would insert an ellipsis at the point where the paragraph overflows its container. JavaScript had to step in.

ellipsis-500_mini
Ellipsis truncation is used throughout.

After an in-depth research and exploration of several different approaches, we created our FTEllipsis library. In essence, it measures the available height of the container, then measures the height of each child element. When it finds the child element that overflows the container, it caps its height to a sensible number of lines. For WebKit-based browsers, we use the little-known -webkit-line-clamp property to truncate an element’s text by a set number of lines. For non-WebKit browsers, the library allows the developer to style the overflowing container however they wish using regular CSS.

Modularization

Having tackled some of the low-level visual challenges, we needed to step back and decide on the best way to manage our application’s views. We wanted to be able to reuse small parts of our views in different contexts and find a way to architect rock-solid styling that wouldn’t leak between components.

One of the best decisions we made in implementing the new application was to modularize the views. This started when we were first looking over the designs. We scribbled over printouts, breaking the page down into chunks (or modules). Our plan was to identify all of the possible layouts and modules, and define each view (or page) as a combination of modules sitting inside the slots of a single layout.

Each module needed to be named, but we found it very hard to describe a module, especially when some modules could have multiple appearances depending on screen size or context. As a result, we abandoned semantic naming and decided to name each component after a type of fruit — no more time wasted thinking up sensible, unambiguous names!

An example of a module’s markup:


<div class="apple">
  <h2 class="apple_headline">{{headline}}</h2>
  <h3 class="apple_sub-head">{{subhead}}</h3>
  <div class="apple_body">{{body}}</div>
</div>

An example of a module’s styling:


.apple {}

.apple_headline {
  font-size: 40px;
}

.apple_sub-head {
  font-size: 20px;
}

.apple_body {
  font-size: 14px;
  column-count: 2;
  color: #333;
}

Notice how each class is prefixed with the module’s name. This ensures that the styling for one component will never affect another; every module’s styling is encapsulated. Also, notice how we use just one class in our CSS selectors; this makes our component transportable. Ridding selectors of any ancestral context means that modules may be dropped anywhere in our application and will look the same. This is all imperative if we want to be able to reuse components throughout the application (and even across applications).

What If a Module Needs Interactions?

Each module (or fruit) has its own markup and style, which we wrote in such a way that it can be reused. But what if we need a module to respond to interactions or events? We need a way to bring the component to life, but still ensure that it is unbound from context so that it can be reused in different places. This is a little trickier that just writing smart markup and styling. To solve this problem, we wrote FruitMachine.

Reusable Components

FruitMachine is a lightweight library that assembles our layout’s components and enables us to declare interactions on a per-module basis. It was inspired by the simplicity of Backbone views, but with a little more structure to keep “boilerplate” code to a minimum. FruitMachine gives our team a consistent way to work with views, while at the same time remaining relatively unopinionated so that it can be used in almost any view.

The Component Mentality

Thinking about your application as a collection of standalone components changes the way you approach problems. Components need to be dumb; they can’t know anything of their context or of the consequences of any interactions that may occur within them. They can have a public API and should emit events when they are interacted with. An application-specific controller assembles each layout and is the brain behind everything. Its job is to create, control and listen to each component in the view.

For example, to show a popover when a component named “button” is clicked, we would not hardcode this logic into the button component. Instead “button” would emit a buttonclicked event on itself every time its button is clicked; the view controller would listen for this event and then show the popover. By working like this, we can create a large collection of components that can be reused in many different contexts. A view component may not have any application-specific dependencies if it is to be used across projects.

Working like this has simplified our architecture considerably. Breaking down our views into components and decoupling them from our application focuses our decision-making and moves us away from baking complex, heavily dependent modules into our application.

The Future of FruitMachine

FruitMachine was our solution to achieve fully transportable view components. It enables us to quickly define and assemble views with minimal effort. We are currently using FruitMachine only on the client, but server-side (NodeJS) usage has been considered throughout development. In the coming months, we hope to move towards producing server-side-rendered websites that progressively enhance into a rich app experience.

You can find out more about FruitMachine and check out some more examples in the public GitHub repository.

Retina Support

The Financial Times’ first Web app was released before the age of “Retina” screens. We retrofitted some high-resolution solutions, but never went the whole hog. For our designers, 100% Retina support was a must-have in the new application. We developers were sick of maintaining multiple sizes and resolutions of each tiny image within the UI, so a single vector-based solution seemed like the best approach. We ended up choosing icon fonts to replace our old PNGs, and because they are implemented just like any other custom font, they are really well supported. SVG graphics were considered, but after finding a lack of support in Android 2.3 and below, this option was ruled out. Plus, there is something nice about having all of your icons bundled up in a single file, whilst not sacrificing the individuality of each graphic (like sprites).

Our first move was to replace the Financial Times’ logo image with a single glyph in our own custom icon font. A font glyph may be any color and size, and it always looks super-sharp and is usually lighter in weight than the original image. Once we had proved it could work, we began replacing every UI image and icon with an icon font alternative. Now, the only pixel-based image in our CSS is the full-color logo on the splash screen. We used the powerful but rather archaic-looking FontForge to achieve this.

Once past the installation phase, you can open any font file in FontForge and individually change the vector shape of any character. We imported SVG vector shapes (created in Adobe Illustrator) into suitable character slots of our font and exported as WOFF and TTF font types. A combination of WOFF and TTF file formats are required to support iOS, Android and Windows devices, although we hope to rely only on WOFFs once Android gains support (plus, WOFFs are around 25% smaller in file size than TTFs).

icon-font-500-compr
The Financial Times’ icon font in Font Forge

Images

Article images are crucial for user engagement. Our images are delivered as double-resolution JPEGs so that they look sharp on Retina screens. Our image service (running ImageMagick) outputs JPEGs at the lowest possible quality level without causing noticeable degradation (we use 35 for Retina devices and 70 for non-Retina). Scaling down retina size images in the browser enables us to reduce JPEG quality to a lower level than would otherwise be possible without compression artifacts becoming noticeable. This article explains this technique in more detail.

It’s worth noting that this technique does require the browser to work a little harder. In old browsers, the work of scaling down many large images could have a noticeable impact on performance, but we haven’t encountered any serious problems.

Native-Like Scrolling

Like almost any application, we require full-page and subcomponent scrolling in order to manage all of the content we want to show our users. On desktop, we can make use of the well-established overflow CSS property. When dealing with the mobile Web, this isn’t so straightforward. We require a single solution that provides a “momentum” scrolling experience across all of the devices we support.

overflow: scroll

The overflow: scroll declaration is becoming usable on the mobile Web. Android and iOS now support it, but only since Android 3.0 and iOS 5. IOS 5 came with the exciting new -webkit-overflow-scrolling: touch property, which allows for native momentum-like scrolling in the browser. Both of these options have their limitations.

Standard overflow: scroll and overflow: auto don’t display scroll bars as users might expect, and they don’t have the momentum touch-scrolling feel that users have become accustomed to from their native apps. The -webkit-overflow-scrolling: touch declaration does add momentum scrolling and scroll bars, but it doesn’t allow developers to style the scroll bars in any way, and has limited support (iOS 5+ and Chrome on Android).

A Consistent Experience

Fragmented support and an inconsistent feel forced us to turn to JavaScript. Our first implementation used the TouchScroll library. This solution met our needs, but as our list of supported devices grew and as more complex scrolling interactions were required, working with it became trickier. TouchScroll lacks IE 10 support, and its API interface is difficult to work with. We also tried Scrollability and Zynga Scroller, neither of which have the features, performance or cross-browser capability we were looking for. Out of this problem, FTScroller was developed: a high-performance, momentum-scrolling library with support for iOS, Android, Playbook and IE 10.

FTScroller

FTScroller’s scrolling implementation is similar to TouchScroll’s, with a flexible API much like Zynga Scroller. We added some enhancements, such as CSS bezier curves for bouncing, requestAnimationFrame for smoother frame rates, and support for IE 10. The advantage of writing our own solution is that we could develop a product that exactly meets our requirements. When you know the code base inside out, fixing bugs and adding features is a lot simpler.

FTScroller is dead simple to use. Just pass in the element that will wrap the overflowing content, and FTScroller will implement horizontal or vertical scrolling as and when needed. Many other options may be declared in an object as the second argument, for more custom requirements. We use FTScroller throughout the Financial Times’ Web app for a consistent cross-platform scrolling experience.

A simple example:


var container = document.getElementById('scrollcontainer');
var scroller = new FTScroller(container);

The Gallery

The part of our application that holds and animates the page views is known as the “gallery.” It consists of three divisions: left, center and right. The page that is currently in view is located in the center pane. The previous page is positioned off screen in the left-hand pane, and the next page is positioned off screen in the right-hand pane. When the user swipes to the next page, we use CSS transitions to animate the three panes to the left, revealing the hidden right pane. When the transition has finished, the right pane becomes the center pane, and the far-left pane skips over to become the right pane. By using only three page containers, we keep the DOM light, while still creating the illusion of infinite pages.

Web
Infinite scrolling made possible with a three-pane gallery

Making It All Work Offline

Not many Web apps currently offer an offline experience, and there’s a good reason for that: implementing it is a bloody pain! The application cache (AppCache) at first glance appears to be the answer to all offline problems, but dig a little deeper and stuff gets nasty. Talks by Andrew Betts and Jake Archibald explain really well the problems you will encounter. Unfortunately, AppCache is currently the only way to achieve offline support, so we have to work around its many deficiencies.

Our approach to offline is to store as little in the AppCache as possible. We use it for fonts, the favicon and one or two UI images — things that we know will rarely or never need updating. Our JavaScript, CSS and templates live in LocalStorage. This approach gives us complete control over serving and updating the most crucial parts of our application. When the application starts, the bare minimum required to get the app up and running is sent down the wire, embedded in a single HTML page; we call this the preload.

We show a splash screen, and behind the scenes we make a request for the application’s full resources. This request returns a big JSON object containing our JavaScript, CSS and Mustache templates. We eval the JavaScript and inject the CSS into the DOM, and then the application launches. This “bootstrap” JSON is then stored in LocalStorage, ready to be used when the app is next started up.

On subsequent startups, we always use the JSON from LocalStorage and then check for resource updates in the background. If an update is found, we download the latest JSON object and replace the existing one in LocalStorage. Then, the next time the app starts, it launches with the new assets. If the app is launched offline, the startup process is the same, except that we cannot make the request for resource updates.

Images

Managing offline images is currently not as easy as it should be. Our image requests are run through a custom image loader and cached in the local database (IndexedDB or WebSQL) so that the images can be loaded when a network connection is not present. We never load images in the conventional way, otherwise they would break when users are offline.

Our image-loading process:

  1. The loader scans the page for image placeholders declared by a particular class.
  2. It takes the src attribute of each image placeholder found and requests the source from our JavaScript image-loader library.
  3. The local database is checked for each image. Failing that, a single HTTP request is made listing all missing images.
  4. A JSON array of Base64-encoded images is returned from the HTTP response and stored separately in the local database.
  5. A callback is fired for each image request, passing the Base64 string as an argument.
  6. An <img> element is created, and its src attribute is set to the Base64 data-URI string.
  7. The image is faded in.

I should also mention that we compress our Base64-encoded image strings in order to fit as many images in the database as possible. My colleague Andrew Betts goes into detail on how this can be achieved.

In some cases, we use this cool trick to handle images that fail to load:


<img src="image.jpg" onerror="this.style.display='none';" />

Ever-Evolving Applications

In order to stay competitive, a digital product needs to evolve, and as developers, we need to be prepared for this. When the request for a redesign landed at the Financial Times, we already had a fast, popular, feature-rich application, but it wasn’t built for change. At the time, we were able to implement small changes to features, but implementing anything big became a slow process and often introduced a lot of unrelated regressions.

Our application was drastically reworked to make the new requirements possible, and this took a lot of time. Having made this investment, we hope the new application not only meets (and even exceeds) the standard of the first product, but gives us a platform on which we can develop faster and more flexibly in the future.

(al)


© Wilson Page for Smashing Magazine, 2013.

May
22
2013

Designing CSS Layouts With Flexbox Is As Easy As Pie


  

Flexible box layout (or flexbox) is a new box model optimized for UI layout. As one of the first CSS modules designed for actual layout (floats were really meant mostly for things such as wrapping text around images), it makes a lot of tasks much easier, or even possible at all. Flexbox’s repertoire includes the simple centering of elements (both horizontally and vertically), the expansion and contraction of elements to fill available space, and source-code independent layout, among others abilities.

Flexbox has lived a storied existence. It started as a feature of Mozilla’s XUL, where it was used to lay out application UI, such as the toolbars in Firefox, and it has since been rewritten multiple times. The specification has only recently reached stability, and we have fairly complete support across the latest versions of the leading browsers.

There are, however, some caveats. The specification changed between the implementation in Internet Explorer (IE) and the release of IE 10, so you will need to use a slightly different syntax. Chrome currently still requires the -webkit- prefix, and Firefox and Safari are still on the much older syntax. Firefox has updated to the latest specification, but that implementation is currently behind a runtime flag until it is considered stable and bug-free enough to be turned on by default. Until then, Firefox still requires the old syntax.

When you specify that an element will use the flexbox model, its children are laid out along either the horizontal or vertical axis, depending on the direction specified. The widths of these children expand or contract to fill the available space, based on the flexible length they are assigned.

Example: Horizontal And Vertical Centering (Or The Holy Grail Of Web Design)

Being able to center an element on the page is perhaps the number one wish among Web designers — yes, probably even higher than gaining the highly prized parent selector or putting IE 6 out of its misery (OK, maybe a close second then). With flexbox, this is trivially easy. Let’s start with a basic HTML template, with a heading that we want to center. Eventually, once we’ve added all the styling, it will end up looking like this vertically and horizontally centered demo.


<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="utf-8"/>
   <title>Centering an Element on the Page</title>
</head>
<body>
   <h1>OMG, I’m centered</h1>
</body>
</html>

Nothing special here, not even a wrapper div. The magic all happens in the CSS:


html {
   height: 100%;
} 

body {
   display: -webkit-box;   /* OLD: Safari,  iOS, Android browser, older WebKit browsers.  */
   display: -moz-box;   /* OLD: Firefox (buggy) */ 
   display: -ms-flexbox;   /* MID: IE 10 */
   display: -webkit-flex;    /* NEW, Chrome 21+ */
   display: flex;       /* NEW: Opera 12.1, Firefox 22+ */

   -webkit-box-align: center; -moz-box-align: center; /* OLD… */
   -ms-flex-align: center; /* You know the drill now… */
   -webkit-align-items: center;
   align-items: center;

    -webkit-box-pack: center; -moz-box-pack: center; 
   -ms-flex-pack: center; 
   -webkit-justify-content: center;
   justify-content: center;

   margin: 0;
   height: 100%;
   width: 100% /* needed for Firefox */
} 

h1 {
   display: -webkit-box; display: -moz-box;
   display: -ms-flexbox;
   display: -webkit-flex;
   display: flex;
 
   -webkit-box-align: center; -moz-box-align: center;
   -ms-flex-align: center;
   -webkit-align-items: center;
   align-items: center;

   height: 10rem;
}

I’ve included all of the different prefixed versions in the CSS above, from the very oldest, which is still needed, to the modern and hopefully final syntax. This might look confusing, but the different syntaxes map fairly well to each other, and I’ve included tables at the end of this article to show the exact mappings.

This is not exactly all of the CSS needed for our example, because I’ve stripped out the extra styling that you probably already know how to use in order to save space.

Let’s look at the CSS that is needed to center the heading on the page. First, we set the html and body elements to have 100% height and remove any margins. This will make the container of our h1 take up the full height of the browser’s window. Firefox also needs a width specified on the body to force it to behave. Now, we just need to center everything.

Enabling Flexbox

Because the body element contains the heading that we want to center, we will set its display value to flex:


body {
   display: flex;
}

This switches the body element to use the flexbox layout, rather than the regular block layout. All of its children in the flow of the document (i.e. not absolutely positioned elements) will now become flex items.

The syntax used by IE 10 is display: -ms-flexbox, while older Firefox and WebKit browsers use display: -prefix-box (where prefix is either moz or webkit). You can see the tables at the end of this article to see the mappings of the various versions.

What do we gain now that our elements have been to yoga class and become all flexible? They gain untold powers: they can flex their size and position relative to the available space; they can be laid out either horizontally or vertically; and they can even achieve source-order independence. (Two holy grails in one specification? We’re doing well.)

Centering Horizontally

Next, we want to horizontally center our h1 element. No big deal, you might say; but it is somewhat easier than playing around with auto margins. We just need to tell the flexbox to center its flex items. By default, flex items are laid out horizontally, so setting the justify-content property will align the items along the main axis:


body {
   display: flex;
   justify-content: center;
}

For IE 10, the property is called flex-pack, while for older browsers it is box-pack (again, with the appropriate prefixes). The other possible values are flex-start, flex-end, space-between and space-around. These are start, end, justify and distribute, respectively, in IE 10 and the old specification (distribute is, however, not supported in the old specification). The flex-start value aligns to the left (or to the right with right-to-left text), flex-end aligns to the right, space-between evenly distributes the elements along the axis, and space-around evenly distributes along the axis, with half-sized spaces at the start and end of the line.

To explicitly set the axis that the element is aligned along, you can do this with the flex-flow property. The default is row, which will give us the same result that we’ve just achieved. To align along the vertical axis, we can use flex-flow: column. If we add this to our example, you will notice that the element is vertically centered but loses the horizontal centering. Reversing the order by appending -reverse to the row or column values is also possible (flex-flow: row-reverse or flex-flow: column-reverse), but that won’t do much in our example because we have only one item.

There are some differences here in the various versions of the specification, which are highlighted at the end of this article. Another caveat to bear in mind is that flex-flow directions are writing-mode sensitive. That is, when using writing-mode: vertical-rl to switch to vertical text layout (as used traditionally in China, Japan and Korea), flex-flow: row will align the items vertically, and column will align them horizontally.

Centering Vertically

Centering vertically is as easy as centering horizontally. We just need to use the appropriate property to align along the “cross-axis.” The what? The cross-axis is basically the axis perpendicular to the main one. So, if flex items are aligned horizontally, then the cross-axis would be vertical, and vice versa. We set this with the align-items property (flex-align in IE 10, and box-align for older browsers):


body {
   /* Remember to use the other versions for IE 10 and older browsers! */
   display: flex;
   justify-content: center;
   align-items: center;
}

This is all there is to centering elements with flexbox! We can also use the flex-start (start) and flex-end (end) values, as well as baseline and stretch. Let’s have another look at the finished example:

figure1.1_mini
Simple horizontal and vertical centering using flexbox. Larger view.

You might notice that the text is also center-aligned vertically inside the h1 element. This could have been done with margins or a line height, but we used flexbox again to show that it works with anonymous boxes (in this case, the line of text inside the h1 element). No matter how high the h1 element gets, the text will always be in the center:


h1 {
   /* Remember to use the other versions for IE 10 and older browsers! */
   display: flex;
   align-items: center;
   height: 10rem;
}

Flexible Sizes

If centering elements was all flexbox could do, it’d be pretty darn cool. But there is more. Let’s see how flex items can expand and contract to fit the available space within a flexbox element. Point your browser to this next example.

figure1.2_mini
An interactive slideshow built using flexbox. Larger view.

The HTML and CSS for this example are similar to the previous one’s. We’re enabling flexbox and centering the elements on the page in the same way. In addition, we want to make the title (inside the header element) remain consistent in size, while the five boxes (the section elements) adjust in size to fill the width of the window. To do this, we use the new flex property:


section {
   /* removed other styles to save space */
   -prefix-box-flex: 1; /* old spec webkit, moz */
   flex: 1;
   height: 250px;
}

What we’ve just done here is to make each section element take up 1 flex unit. Because we haven’t set any explicit width, each of the five boxes will be the same width. The header element will take up a set width (277 pixels) because it is not flexible. We divide the remaining width inside the body element by 5 to calculate the width of each of the section elements. Now, if we resize the browser window, the section elements will grow or shrink.

In this example, we’ve set a consistent height, but this could be set to be flexible, too, in exactly the same way. We probably wouldn’t always want all elements to be the same size, so let’s make one bigger. On hover, we’ve set the element to take up 2 flex units:


section:hover {
   -prefix-box-flex: 2;
   flex: 2;
   cursor: pointer;
}

Now the available space is divided by 6 rather than 5, and the hovered element gets twice the base amount. Note that an element with 2 flex units does not necessarily become twice as wide as one with 1 unit. It just gets twice the share of the available space added to its “preferred width.” In our examples, the “preferred width” is 0 (the default).

Source-Order Independence

For our last party trick, we’ll study how to achieve source-order independence in our layouts. When clicking on a box, we will tell that element to move to the left of all the other boxes, directly after the title. All we have to do is set the order with the order property. By default, all flex items are in the 0 position. Because they’re in the same position, they follow the source order. Click on your favorite person in the updated example to see their order change.

figure1.3_mini
An interactive slideshow with flex-order. Larger view.

To make our chosen element move to the first position, we just have to set a lower number. I chose -1. We also need to set the header to -1 so that the selected section element doesn’t get moved before it:


header {
   -prefix-box-ordinal-group: 1; /* old spec; must be positive */
   -ms-flex-order: -1; /* IE 10 syntax */
   order: -1; /* new syntax */
} 

section[aria-pressed="true"] {
   /* Set order lower than 0 so it moves before other section elements,
      except old spec, where it must be positive.
 */
   -prefix-box-ordinal-group: 1;
   -ms-flex-order: -1;
   order: -1;

   -prefix-box-flex: 3;
   flex: 3;
   max-width: 370px; /* Stops it from getting too wide. */
}

In the old specification, the property for setting the order (box-ordinal-group) accepts only a positive integer. Therefore, I’ve set the order to 2 for each section element (code not shown) and updated it to 1 for the active element. If you are wondering what aria-pressed="true" means in the example above, it is a WAI-ARIA attribute/value that I add via JavaScript when the user clicks on one of the sections.

This relays accessibility hints to the underlying system and to assistive technology to tell the user that that element is pressed and, thus, active. If you’d like more information on WAI-ARIA, check out “Introduction to WAI-ARIA” by Gez Lemon. Because I’m adding the attribute after the user clicks, this example requires a simple JavaScript file in order to work, but flexbox itself doesn’t require it; it’s just there to handle the user interaction.

Hopefully, this has given you some inspiration and enough introductory knowledge of flexbox to enable you to experiment with your own designs.

Syntax Changes

As you will have noticed throughout this article, the syntax has changed a number of times since it was first implemented. To aid backward- and forward-porting between the different versions, we’ve included tables below, which map the changes between the specifications.

Specification versions
Specification IE Opera Firefox Chrome Safari
Standard 11? 12.10+ * Behind flag 21+ (-webkit-)
Mid 10 (-ms-)
Old 3+ (-moz-) -webkit-) 3+ (-webkit-)

* Opera will soon switch to WebKit. It will then require the -webkit- prefix if it has not been dropped by that time.

Enabling flexbox: setting an element to be a flex container
Specification Property name Block-level flex Inline-level flex
Standard display flex inline-flex
Mid display flexbox inline-flexbox
Old display box inline-box
Axis alignment: specifying alignment of items along the main flexbox axis
Specification Property name start center end justify distribute
Standard justify-content flex-start center flex-end space-between space-around
Mid flex-pack start center end justify distribute
Old box-pack start center end justify N/A
Cross-axis alignment: specifying alignment of items along the cross-axis
Specification Property name start center end baseline stretch
Standard align-items flex-start center flex-end baseline stretch
Mid flex-align start center end baseline stretch
Old box-align start center end baseline stretch
Individual cross-axis alignment: override to align individual items along the cross-axis
Specification Property name auto start center end baseline stretch
Standard align-self auto flex-start center flex-end baseline stretch
Mid flex-item-align auto start center end baseline stretch
Old N/A
Flex line alignment: specifying alignment of flex lines along the cross-axis
Specification Property name start center end justify distribute stretch
Standard align-content flex-start center flex-end space-between space-around stretch
Mid flex-line-pack start center end justify distribute stretch
Old N/A

This takes effect only when there are multiple flex lines, which is the case when flex items are allowed to wrap using the flex-wrap property and there isn’t enough space for all flex items to display on one line. This will align each line, rather than each item.

Display order: specifying the order of flex items
Specification Property name Value
Standard order
Mid flex-order <number>
Old box-ordinal-group <integer>
Flexibility: specifying how the size of items flex
Specification Property name Value
Standard flex none | [ <flex-grow> <flex-shrink>? || <flex-basis>]
Mid flex none | [ [ <pos-flex> <neg-flex>? ] || <preferred-size> ]
Old box-flex <number>

The flex property is more or less unchanged between the new standard and the draft supported by Microsoft. The main difference is that it has been converted to a shorthand in the new version, with separate properties: flex-grow, flex-shrink and flex-basis. The values may be used in the same way in the shorthand. However, the default value for flex-shrink (previously called negative flex) is now 1. This means that items do not shrink by default. Previously, negative free space would be distributed using the flex-shrink ratio, but now it is distributed in proportion to flex-basis multiplied by the flex-shrink ratio.

Direction: specifying the direction of the main flexbox axis
Specification Property name Horizontal Reversed horizontal Vertical Reversed vertical
Standard flex-direction row row-reverse column column-reverse
Mid flex-direction row row-reverse column column-reverse
Old box-orient

box-direction

horizontal

normal

horizontal

reverse

vertical

normal

vertical

reverse

In the old version of the specification, the box-direction property needs to be set to reverse to get the same behavior as row-reverse or column-reverse in the later version of the specification. This can be omitted if you want the same behavior as row or column because normal is the initial value.

When setting the direction to reverse, the main flexbox axis is flipped. This means that when using a left-to-right writing system, the items will display from right to left when row-reverse is specified. Similarly, column-reverse will lay out flex items from bottom to top, instead of top to bottom.

The old version of the specification also has writing mode-independent values for box-orient. When using a left-to-write writing system, horizontal may be substituted for inline-axis, and vertical may be substituted for block-axis. If you are using a top-to-bottom writing system, such as those traditional in East Asia, then these values would be flipped.

Wrapping: specifying whether and how flex items wrap along the cross-axis
Specification Property name No wrapping Wrapping Reversed wrap
Standard flex-wrap nowrap wrap wrap-reverse
Mid flex-wrap nowrap wrap wrap-reverse
Old box-lines single multiple N/A

The wrap-reverse value flips the start and end of the cross-axis, so that if flex items are laid out horizontally, instead of items wrapping onto a new line below, they will wrap onto a new line above.

At the time of writing, Firefox does not support the flex-wrap or older box-lines property. It also doesn’t support the shorthand.

The current specification has a flex-flow shorthand, which controls both wrapping and direction. The behavior is the same as the one in the version of the specification implemented by IE 10. It is also currently not supported by Firefox, so I would recommend to avoid using it when specifying only the flex-direction value.

Conclusion

Well, that’s a (flex-)wrap. In this article, I’ve introduced some of the myriad of possibilities afforded by flexbox. Be it source-order independence, flexible sizing or just the humble centering of elements, I’m sure you can find ways to employ flexbox in your websites and applications. The syntax has settled down (finally!), and implementations are here. All major browsers now support flexbox in at least their latest versions.

While some browsers use an older syntax, Firefox looks like it is close to updating, and IE 11 uses the latest version in leaked Windows Blue builds. There is currently no word on Safari, but it is a no-brainer considering that Chrome had the latest syntax before the Blink-WebKit split. For the time being, use the tables above to map the various syntaxes, and get your flex on.

Layout in CSS is only getting more powerful, and flexbox is one of the first steps out of the quagmire we’ve found ourselves in over the years, first with table-based layouts, then float-based layouts. IE 10 already supports an early draft of the Grid layout specification, which is great for page layout, and Regions and Exclusions will revolutionize how we handle content flow and layout.

Flexbox can be used today if you only need to support relatively modern browsers or can provide a fallback, and in the not too distant future, all sorts of options will be available, so that we can use the best tool for the job. Flexbox is shaping up to be a mighty fine tool.

Further Reading

(al)


© David Storey for Smashing Magazine, 2013.

May
2
2013

Open Source Plugin: Magnific Popup, A Truly Responsive Lightbox (For jQuery And Zepto.js)


  

A lightbox is one of those tools that work great on the desktop but often fail on small mobile devices. These days, finding a plugin that is responsive and that displays content right away is hard. For this reason, I created Magnific Popup, an open-source lightbox plugin focused on performance.

In this article, I’ll share the techniques I employed in creating this plugin, techniques that can make your lightbox much faster and easier to use, whatever the device being used.

1. Speed

We might not be able to speed up the loading time of an image with this lightbox plugin, but we can create the perception of a faster loading time.

Progressive Loading of Images

The majority of lightbox plugins will fully preload an image before displaying it. This is done to figure out the original size of the image and to center it with JavaScript. Because Magnific Popup centers the content with CSS, we can avoid preloading and instead display the image right away to take advantage of progressive image loading. It will render and show the image while the data is being received.

You can speed this up even more by progressively rendering the JPEG. It is rendered not from top to bottom, but from low quality to full quality, so the user can discern the image even faster. The type of rendering to use is strictly a matter of preference.

Progressive image loading

CSS-Based Resizing

The CSS-only approach makes this lightbox extremely flexible. You can specify sizes in relative units such as ems, resize popups in media queries, and update popup content dynamically without having to worry about how it will be resized and centered. Try to avoid, or at least reduce, the number of resizing properties in a window’s resize event, because it will look much slower than resizing with just pure CSS.

Vertically centering an element with unknown dimensions is probably the most horrifying topic in CSS layout. The main goal for me was to prevent the size of the content area from dynamically updating the contents of the lightbox, and to make it work in IE 8 and above.

Following the principle of progressive enhancement, I decided to drop the vertical centering feature in IE 7 completely, because the only way to implement it was to use slow CSS expressions, which kill performance in old browsers. In contrast to modern browsers, the resolution of monitors on which IE 7 is being run is unusually easy to predict. We’d know that the user would be on an old PC, which typically has a resolution of somewhere between 800 × 600 and 1280 × 1024 pixels; so, we can just set a fixed margin from the top: .lightbox-image { margin-top: 10%; }. Alternatively, instead of opening the lightbox, you can just link directly to the content. In Magnific Popup, you can do this like so:


$('.popup-link').magnificPopup(function() {
  disableOn: function() {
    // Detect IE 7 or lower with your preferred method
    // and return false if you want to trigger the default action
    return isIE7 ? false: true;
  }
});

Centering an HTML block

Here are the criteria:

  1. The size of the block is unknown and could be changed at any time.
  2. Block should be centered both horizontally and vertically.
  3. If the height of the popup is bigger than the viewport, then the scrollbar should appear, and the popup should automatically align to the top.

The one reliable technique to vertically center an element of unknown height that I’ve found uses a helper inline-block element with a setting of vertical-align: middle and height: 100%. Chris Coyier has written a superb article covering this technique. It works perfectly and meets all three requirements.

Centering an image with a caption

In addition to the requirements of an HTML block, the image should also meet these requirements:

  • It should fit the area both horizontally and vertically.
  • Its maximum height should equal the height of the original image.
  • The caption should be positioned directly below the image, and the text may flow up to two lines.

Here is the structure of the image’s lightbox:

<div class="container">
  <img src="image.jpg"/>
  <div class="description">Caption</div>
</div>

Implementing this just for an image and with support for IE 8 and above is not hard. The problem comes when you try to position elements near to the image (such as a caption or related icon).

I was not able to find the solution for such a layout without using JavaScript, so I used a technique that applies a max-height to the image. Check the example on CodePen to see how it works.

Centering an iframe

Iframes in Magnific Popup are resized using the popular and effective technique introduced by Thierry Koblentz in his article “Creating Intrinsic Ratios for Video” on A List Apart. All you need to do to force any element’s height to scale according to its width is to put it in a container and apply top padding as a percentage:


.iframe-container {
  width: 100%;
  height: 0; 
  overflow: hidden;

  /* element ratio is 4:3 (3/4 * 100) */
  padding-top: 75%; 
}

.iframe-container iframe {
  position: absolute;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
}

Window height on iPhone

Mobile Safari on iPhone and iPod has a nasty bug: the height of the window is always reduced by the height of the navigation bar, whether the bar is present or not, so the popup won’t center correctly. When researching this issue, I found two ways to fix it:

  1. Just add 60 pixels to the height of the window. This solution doesn’t work with iOS 6’s full-screen mode, and it’s not future-friendly.
  2. Use window.innerHeight instead of document.documentElement.clientHeight, which returns the correct value, but only when the window is not zoomed in.

But I’ve figured out a third way to implement this (for more details on this technique, check my answer on Stack Overflow):


var getIphoneWindowHeight = function() {
  // Get zoom level of mobile Safari
  // Such zoom detection might not work correctly on other platforms
  // 
  var zoomLevel = document.documentElement.clientWidth / window.innerWidth;

  // window.innerHeight returns height of the visible area. 
  // We multiply it by zoom and get our real height.
  return window.innerHeight * zoomLevel;
};

If you know of a better way to position elements than what’s suggested here, we’d be hugely grateful to hear!

Preload Adjacent Images in Gallery

Preloading images in a gallery is essential and vastly increases browsing speed. The average modern browser accepts about six connections per host name, whereas IE 7 accepts only two.

After the lightbox gallery is opened, it should start loading not one, but a group of images (the number of items in a group should depend on the size of the images and on how likely your visitor will navigate to the next one — test it!). Don’t even think about waiting to load the next image until after the current one has completely loaded; otherwise, it will reduce browsing speed significantly.

In Magnific Popup, you can set the number of images to preload before and after the current one, and these two values will automatically switch according to the direction in which the user is navigating.

Parallel loading
Inaccurate comparison between parallel and one-by-one loading.

High-DPI Display Support

Magnific Popup’s default controls are made with pure CSS, without any external resources. Thus, the controls are not only light, but also ready for high-DPI (i.e. Retina) displays. But in this section of the article I’d like to talk about serving images for displays with high pixel density.

It’s not hard to change the path, as the image in lightbox is loaded dynamically. The main problem is that the image should be scaled by half (for 2x device pixel ratio). It rises the question: how to get the image size via JavaScript without waiting until it is completely loaded to keep progressive loading?

While researching, I’ve found that the image naturalWidth is defined exactly after browser gets its size. So we just fire an interval that checks if the image object has defined naturalWidth, after it has it we scale the image by applying max-width that equals image.naturalWidth / window.devicePixelRatio. Here is simplified version of how the image loading is implemented:


var interval,
	hasSize,
	onHasSize = function() {
		if(hasSize) return;

		// we ignore browsers that don't support naturalWidth
		var naturalWidth = img[0].naturalWidth;

		if(window.devicePixelRatio > 1 && naturalWidth > 0) {
			img.css('max-width', naturalWidth / window.devicePixelRatio);
		}

		clearInterval(interval);
		hasSize = true;
	},
	onLoaded = function() {
		onHasSize();
	},
	onError = function() {
		onHasSize();
	},
	checkSize = function() {
		if(img[0].naturalWidth > 0) {
			onHasSize();
		}
	},
	img = $('<img />')
		.on('load', onLoaded)
		.on('error', onError)
		// hd-image.jpg is optimized for the current pixel density
		.attr('src', 'hd-image.jpg') 
		.appendTo(someContainer);

interval = setInterval(checkSize, 100);
checkSize();

There is a very common assumption that the image optimized for Retina display weighs two times or more than the normal one, but it’s not always true. As the image will be scaled down, JPEG quality can be reduced without any notable visual difference. From my experience, saving an image for 2x pixel ratio with 25% JPEG quality produces a good-looking result and the file size is only about 1.4x times larger than the regular one. Daan Jobsis has a great article that covers this technique.

What image to serve on what screen size is a topic for another article. I just want to emphasize that for many users mobile is the only way to access the internet. If you serve smaller images for mobile and there is a chance that user will need full-sized ones — provide an alternative way to get it.

Avoid Extra HTTP Requests for Controls

Preload all controls (i.e. the arrows, the closing icon, the preloader) before the popup has opened in order to load the actual content faster. This can be implemented in three ways:

  • Create all controls with CSS only (as Magnific Popup does by default).
  • Include the control graphics in the main CSS sprite of your website, or preload them with CSS before the popup has opened.
  • Use the Data URI scheme to embed base64-encoded images directly in the CSS (supported by IE 8 and above).

2. Accessibility

Content that has opened in the lightbox should be easily zoomable and scrollable, no matter what the device. The contents and controls of the popup should be accessible with the tab key for keyboard users.

Conditional Lightbox

This relatively new technique, introduced by Brad Frost, disables the lightbox entirely on devices with a small screen, substituting an alternative more appropriate to mobile use. Here are some examples:

  • Open maps and videos as a separate page. Many mobile browsers will recognize such links and open a dedicated app that is much easier to use.
  • Simply open images in a new page for easier zooming and panning.
  • Open long text-based popups in a new page. In Magnific Popup, you can do this by adding the source of the popup inside a data attribute and linking to a mobile-friendly page in the href attribute. For example:
    <a href="separate-mobile-friendly-page.html" data-mfp-src="popup-content.html">Open popup</a>

    Here is the popup initialization (with an option that disables the popup and just opens the link when the window is narrower than 500 pixels):

    
    $('.popup-link').magnificPopup(function() {
      disableOn: function() {
        // Detect here whether you want to show the popup
        // return true if you want
        if($(window).width() < 500) {
          return false;
        }
        return true;
      }
    });
    

Progressive Enhancement

Build the markup as if there were no JavaScript at all, and make the button that opens the content-oriented lightbox link to the content. Not only is this an enhancement for users without JavaScript, but it allows you to open the content in a new window, and it makes it completely SEO-friendly. Images will be perfectly indexed by search engines, and the anchor text will work as an alt attribute in the img tag.

<!-- Correct: -->
<a href="image.jpg">Description of the image</a>

<!-- Incorrect: -->
<a href="#" data-src="image.jpg">Description of the image</a>

<!-- Correct: -->
<a href="large-image.jpg">
  <img src="thumbail.jpg" alt="Description of the image" />
</a>

<!-- Incorrect: -->
<img src="thumbail.jpg" data-src="large-image.jpg" alt="Description of the image" />

Selectable Image

Users should be able to select and copy an image that is opened in a popup. This is one of the few ways to bookmark, save or share it.

Presently, fully overlaying a lightbox image with left and right navigation arrows is very common. The screenshots below show context menus above the image (the one on the right is overlaid with a transparent div, making any kind of interaction with the image virtually impossible).

accessible image

position: fixed and overflow: scroll

Zooming a fixed-positioned element looks unnatural and confusing in the majority of mobile browsers. I suggest avoiding this property entirely on devices on which content is likely to be zoomed.

Exactly the same problem happens when you apply overflow: scroll to a popup’s wrapper. In this case, the problem is an unnatural scroll:

  • Once the user has reached the end of the scroll, the main window starts scrolling behind the popup.
  • Scrolling momentum is missing. On iOS 5+, this issue can be fixed with -webkit-overflow-scrolling: touch, but what about other devices?

Magnific Popup automatically disables these properties on mobile devices. Instead of using a fixed positon, it adds a huge dark overlay to the whole page that equals the height of the document and that positions the content area using position: absolute and with a top that equals the scrollTop of the window.

Keyboard Focus

Upon loading, the focus should be set on the popup itself or on the first input (if it is a form). When tabbing, focus should be confined to the lightbox and its controls. After the popup has closed, focus should return to its original location. This can be implemented very simply:


// Save current focused element
var lastFocusedElement = document.activeElement;

// Set focus on some element in lightbox
$('#input').focus();

// After lightbox is closed, put it back
if(lastFocusedElement)
  $(lastFocusedElement).focus();

Roger Johansson’s great article “Lightboxes and Keyboard Accessibility” discusses this topic and the overall keyboard accessibility of lightboxes.

Touch Swipe Support

The main problem with the swipe gesture on touch devices is that it requires blocking the default behavior of the touchmove event (e.preventDefault()), which blocks the zooming and panning gesture.

There are just two ways to enable swiping and zooming at once:

  1. Emulate zooming behavior with help of JavaScript touch events by changing the transform property of the content’s container. But this requires recalculating the content’s size, which breaks our CSS-based resizing technique and is not reliable when there are interactive elements such as iframes. Without a doubt, the library that implements such zooming and panning the best is iScroll by Matteo Spinelli.
  2. Don’t inhibit the default behavior of browser zooming when two touch pointers are detected. But finding the difference between panning and swiping is very hard because detection of the browser’s zoom level is unreliable.

By design, the main purpose of a lightbox is to show enlarged versions of images. So, we would conclude that natural zooming is much more important than swiping. That is why Magnific Popup does not have swiping support. Navigation between gallery items is implemented simply by tapping on arrows with a large hit area.

But if you really need swiping, there are some ways to implement it:

  • If you don’t need a dragging effect, use something like the TouchSwipe plugin.
  • If you need touch navigation with a dragging effect, open in the popup some slideshow plugin with touch support, such as FlexSlider or (mine) RoyalSlider.
  • Use a conditional lightbox technique and create a separate mobile-friendly page that has just a list of stacked images.

If we disable the swiping gesture, we should at least make tap navigation faster. Mobile browsers wait about 300 milliseconds before firing a click event in case they detect a double-tap event. This can be fixed with the popular “fast click” technique, which fires a click on touchend. Ryan Fioravanti of Google has a complete guide on it.

3. User Interface

Some devices allow multiple types of input at once (such as touching and mousing). We conclude that we cannot require mouseovers (:hover) for important UI elements, and we cannot neglect mouse events if touch support is present.

Apple’s “Human Interface Guidelines” for iOS state that a comfortable size for a tappable UI element is at least 44 × 44 pixels. Assuming that any device with any screen size may have touch support, we’ll apply as large a hit area as possible by default.

Hit area for buttons
Red rectangles show the hit area for the controls. (Image: JJ Harrison)

Now let’s talk about actual implementation. First of all, buttons are rendered as <button> elements. Here is why:

  • A button can have a title attribute, which we can use to describe what the button does and its keyboard shortcut.
  • Buttons, unlike <a> elements, do not require hacks such as href="#" and href="javascript:void()". When the cursor hovers over a link, many browsers will show the contents of the href attribute in the bottom-left corner of the browser window; displaying javascript:void() would look quite illogical.
  • Buttons are the most semantically correct approach for such controls.

I recommend reading Nicholas Zakas’ article “You Can’t Create a Button,” which offers a few more arguments in favor of using <button> elements.

The Close Button

The closing icon is just a math multiplication sign (×) rendered in Arial. I strongly recommend avoiding specifying multiple fonts (like font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif) because the position and size of the multiplication sign is very inconsistent across fonts.

close-icon-fonts-2
The multiplication sign in different fonts: Arial, Georgia, Lucida Grande, Helvetica, Helvetica Neue, Roboto.

Next and Previous Buttons

The main requirement for default arrow icons is that they should be visible on any background. At first glance, the best option is to use Unicode triangles with shadow, but it turns out that there are no equally sized left and right triangles.

The only remaining option is to use two nested triangles with different colors. Here is how that’s done:


.double-triangle {
  width: 90px;
  height: 110px;
}

.double-triangle:before, 
.double-triangle:after {
  display: block;
  width: 0;
  height: 0;
  position: absolute;
  left: 0;
  top: 0;
  margin-top: 35px;
  margin-left: 35px; 
}
.double-triangle:after {
  content: '';
  border-top: 12px solid transparent;
  border-bottom: 12px solid transparent;
  border-right: 12px solid black;
  top: 8px; 
  left: 5px;
}
.double-triangle:before {
  content: '';
  border-top: 20px solid transparent;
  border-bottom: 20px solid transparent; 
  border-right: 20px solid white;
}

Because of pseudo-elements, such an implementation will not work in IE 7. Navigation buttons are an important part of the UI, so I decided to write a small polyfill to make it work in IE 7, too. We just add two elements inside the button and apply the same styles as the :before and :after elements.


var button = $('<button class="double-triangle"></button>');
if(ie7) {
  button.append('<span class="ie-before"></span><span class="ie-after"></span>');
}

Here’s the CSS:


.double-triangle:before,
.dobule-triangle .ie-before { 
  /* styles ... */
}

Cursors

I am a big fan of custom cursors; they are a lovely addition to an interface. The zoom-in and zoom-out cursors make very clear that content may be enlarged or reduced, while the progress cursor is an excellent loading indicator of AJAX-based popups. Sadly, zoom cursors are still not supported by IE 10.


.zoom-in-cur {
   cursor: -webkit-zoom-in;
   cursor: -moz-zoom-in;
   cursor: zoom-in;
}
.zoom-out-cur {
   cursor: -webkit-zoom-out;
   cursor: -moz-zoom-out;
   cursor: zoom-out;
}
.progress-cur {
  cursor: progress;
}

Animation

The main rule of in and out animation for a lightbox is make sure you need it. If you do, at least keep it short (shorter than 300 milliseconds). Avoid animation if you anticipate a large image or a huge block of HTML in a lightbox.

Magnific Popup does not use JavaScript animation at all. Instead, it uses light and fast CSS transitions. Browsers that don’t support transitions are most likely slow, and thus JavaScript animation would look choppy in them.

One more important point: As I said before, Magnific Popup automatically disables position: fixed on mobile devices and creates a tall dark overlay on the page. Animating such a block might cause mobile devices to lag, so I suggest forcing position: fixed for the background and keeping position: absolute for the content itself.

And here’s a pro tip: To make your sliding animation a little smoother, Paul Irish suggests animating the translateY property, instead of top or margin-top.

In Summary

A responsive lightbox is not one that scales down proportionally when the screen’s size changes. It’s the one that provides fully accessible content, whatever the device.

No matter what script you use, it should support these standards:

  • Escape key to close the popup.
  • Left and right arrow keys to navigate the gallery.
  • Tab key to navigate the contents of the popup.
  • If there is a single image, the lightbox should close when any part of the image is clicked.
  • If it is a gallery, clicking on the current image should advance to the next image. Check out the discussion on UX Stack Exchange for more information.
  • A gallery should be clearly indicated: “1 of 10” counters, arrows, bullets, thumbnails, or any combination of these.

Useful Related Resources

I hope this article and script will be useful to some. For more techniques, dig into the code of Magnific Popup in the GitHub repository.

(al) (ea)


© Dmitry Semenov for Smashing Magazine, 2013.

Apr
26
2013

CSS3 Transitions: Thank God We Have A Specification!


  

This article is packed with a number of quirks and issues you should be aware of when working with CSS3 transitions. Please note that I’m not showing any workarounds or giving advice on how to circumvent the issues discussed. Alex MacCaw has already written a very insightful and thorough article on “All You Need to Know About CSS Transitions.”

Whereas Alex wrote about achieving particular effects, I’m going to talk about the technical background, especially the JavaScript-facing side. Pitfalls — this article is all about pitfalls.

Table of Contents

Separation of concerns is nothing new — we’ve been using template engines for years to accomplish exactly that, separating our HTML from whatever scripting language we were using. A website has three major concerns: structure (HTML), layout and style (CSS), and behavior (JavaScript). CSS crossed the line and became behavioral quite a while ago, but that’s a whole different discussion.

A couple of weeks ago, I was tasked with developing a JavaScript module that would allow for the use of CSS transitions in a way that the JavaScript side would know nothing about the transitions taking place. The actual problem is the asynchronousity of transitions. After writing a bunch of tests, I gave up on the task. It cannot be done with a reasonable amount of code and initialization time. My test results are what this article is all about.

Before getting started with transitions, we have to talk about a little, frequently used, helper function. getComputedStyle() is a JavaScript method that returns a CSS property’s value as the browser interprets it. This API goes back to “DOM Level 2: getComputedStyle()” and “CSS Level 2: Computed Values” — which basically specify that a computed style is an absolute value.

This is fine for properties such as font-size, which take only one argument and are reliably converted to pixel values. However, it doesn’t cover how browsers should handle shorthand properties, such as margin — some browsers return nothing, others something semi-useful. Then there are properties with different but equivalent values to consider, such as font-weight’s bold and 700. WebKit also has a bug that extracts the computed value of properties from pseudo-elements.

The quirks described here were identified in January 2013 using Firefox 18 (Gecko), Opera 12.12 (Presto), Internet Explorer 10 (Trident), Safari 6.0.2 (WebKit), Chrome 23 (WebKit), as well as Gecko’s and WebKit’s nightly build channels.

Without further ado, let’s dive into the specifications and implementations, a world riddled with misconceptions. Please note that in order to be concise, I’ve omitted vendor prefixes from the examples.

Not knowing is difficult to handle. It’s easier to assume.

– Dr. Axel Rauschmayer

… But assumptions are often wrong. I discovered the information in this article by creating a CSS3 Transitions Test Suite.

Specifying A Transition

Besides the shorthand transition property, the CSS3 transition specification defines the following four CSS properties for specifying an animated change of state:

  • transition-property,
  • transition-duration,
  • transition-delay,
  • transition-timing-function.

CSS Properties to Transition

The transition-property property defines the property (or properties) to animate. The default is all, meaning that all properties a browser can transition will be animated on change (if there’s a transition-duration greater than 0s). The property accepts one value or a list of comma-separated values (like all other transition-* properties).

The specification states that a browser should accept and preserve any property it doesn’t recognize. So, the following example would still run a transition on padding lasting 2 seconds:


transition-property: foobar, padding; 
transition-duration: 1s, 2s;

Contrary to the specification, WebKit parses the above to transition-property: all. Firefox and Opera parse it to transition-property: all, padding.

Duration of a Transition

The transition-duration property defines the amount of time a transition should take to get from the initial state to the target state. It accepts a <time> value in seconds or milliseconds (for example, 2.3s and 2300ms both specify 2.3 seconds).

While the specification makes it clear that values must be a positive number, Opera also accepts -5s — at least for getComputedStyle(). Opera and Internet Explorer (IE) do not accept values lower than 10ms, although the specification mentions no such limitation. In all fairness, you wouldn’t notice a transition lasting 9 milliseconds anyways. WebKit (except for the current WebKit nightly) has a bug in its getComputedStyle() implementation, returning values such as 0.009999999776482582s instead of 0.01s. At least all browsers agree on returning second-based values.

Delay of a Transition

The transition-delay property defines the time to wait before executing a transition, also using <time> values. The delay may be a negative value, which will start the transition immediately and make it appear as though the transition had started at the given offset in time — essentially starting with a jump.

As with transition-duration, IE and Opera don’t accept values between -10ms and 10ms. WebKit’s floating point issues appear here, too.

Timing Functions

The transition-timing-function property defines the mathematical function used to calculate a property’s value at time t. There are three basic types: cubic-bezier(x1, y1, x2, y2), step(<number>, start|end), and keywords that map to predefined cubic bezier curves. Most likely, you already know the keywords linear, ease, ease-in, ease-out and ease-in-out. The math behind cubic beziers gets ridiculously unimportant when using Lea Verou’s charming little Cubic Bezier Editor. While cubic bezier curves make smooth transitions, the step() functions don’t. They instead jump to the next value (i.e. the next step) at a regular interval. This allows for frame-by-frame animations; see “Pure CSS3 Typing Animation With steps()” for an example.

The computed value of linear is usually represented as cubic-bezier(0, 0, 1, 1) — except for WebKit, which actually returns linear. But not to worry: WebKit will still return cubic-bezier(0.25, 0.1, 0.25, 1) instead of ease. The current WebKit nightly returns the keyword for all defined keywords, though. Looking on the bright side, in a couple of months WebKit won’t be inconsistent with itself — only with the rest of the browser world.

The specification stipulates that the x values must be between 0 and 1, while the y values may exceed that range. Contrary to the specification, WebKit allows x to exceed the bounds, at least computationally. At the time of writing, the Android browser (version 4.0) mixes up ranges for x and y, essentially disallowing “bounce” effects.

When A Transition Is Complete

I already mentioned that CSS transitions run asynchronously. The specification provides the TransitionEnd event to allow JavaScript to synchronize with the end of a transition. Sadly, the specification isn’t very specific about this event. In fact, it simply states that an event is to be fired for every property that has undergone a transition. If you need a single word to describe the situation, “nightmare” isn’t far off.

While the specification says that shorthand properties (such as padding) should run transitions for all properties that it covers (padding-top, padding-right, etc.), it doesn’t say which property should be named in a TransitionEnd event. While Gecko, Trident and Presto agree on triggering events for the longhand sub-properties (such as padding-top), even if a transition was defined for a shorthand property (such as padding), WebKit would take the opportunity to screw things up. WebKit would trigger an event for padding if (and only if) you specified transition-property: padding, but transition-property: all would trigger the event for padding-left et al. For some reason, iPhone 6.0.1’s Safari browser might also triggers events for font-size and line-height when padding is being transitioned. Confused yet?


.example {
  padding: 1px;
  transition-property: padding;
  transition-duration: 1s;
}

.example:hover {
  padding: 10px;
}

The above CSS will trigger different TransitionEnd events across browsers:

Gecko, Trident, Presto
padding-top, padding-right, padding-bottom, padding-left
WebKit
padding

.example {
  padding: 1px;
  transition-property: all, padding;
  transition-duration: 1s;
}

.example:hover {
  padding: 10px;
}

The CSS above will trigger different TransitionEnd events across browsers:

Gecko, Trident, Presto, WebKit
padding-top, padding-right, padding-bottom, padding-left
Safari 6.0.1 on iPhone (not iPad, mind you!)
padding-top, padding-right, padding-bottom, padding-left, font-size, line-height

I said that you could specify a negative transition-delay to “jumpstart” your transition. But what happens for transition-duration: 1s; transition-delay: -1s;? Gecko and WebKit immediately jump to the target value and trigger an event. Trident and Presto won’t trigger any events.

That floating point issue that WebKit experiences in getComputedStyle() is also present in TransitionEnd.elapsedTime — consistently in all browsers. Math.round(event.elapsedTime * 1000) / 1000 will “fix” that for you.

WebKit and IE have implemented an unspecified extension to background-position that causes them to trigger TransitionEnd events for background-position-x and background-position-y, instead of background-position.

So, even if you knew that a transition was taking place, you wouldn’t be able to rely on the TransitionEnd.propertyName that you’re given. While you could write loads of JavaScript to equalize the behavior, you wouldn’t be able to do this in a future-proof way without doing proper feature detection for every single property. And this could include properties you might not even know are animatable.

Transitionable Properties

The specification lists a number of CSS properties that a browser is supposed to support animated transition for. This list contains properties of CSS2.1. Any of the newer properties will be marked as animatable in their respective specifications — as order of the Flexible Box Layout shows.

The property’s value type is an important factor. The property margin-top accepts <length> and <percentage> values, but according to the list of transitionable CSS properties, only <length> is to be animated. But that didn’t keep browser vendors from implementing transitions for <percentage> values anyway. The word-spacing property is a different story, though. The specification includes <percentage> values, but at the time of writing, no browser is able to animate that.

Ignoring the (inherently unreliable) TransitionEnd events, a property is transitioned from value A to value B if its getComputedStyle() value is different from A and B at a given time during the transition. Because there is no such thing as a “CSS property value changed” event, you’re left with polling the DOM. setTimeout()’s resolution is not good enough to do this for fast transitions (a duration of less than a few hundred milliseconds). requestAnimationFrame() is your friend for this. The browser will call you before it repaints to screen, allowing you to grab a couple of intermediate values during transitions. Except for Opera, all engines have this feature already.

Instead of bloating this article with a full compatibility table, I’ve sent my results to Oli Studholme (@boblet), who has updated his list of “CSS Animatable Properties” accordingly.

Priority of Transition Properties

The specification on the transition-property property states that we’re allowed to define a property multiple times:

If a property is specified multiple times in the value of ‘transition-property’ (either on its own, via a shorthand that contains it, or via the ‘all’ value), then the transition that starts uses the duration, delay, and timing function at the index corresponding to the last item in the value of ‘transition-property’ that calls for animating that property.

So, we can make padding transition for 1 second, while making padding-left take 2 seconds; or define a default transition style using transition-property: all and overwrite that for particular properties.

In Firefox and IE, this works fine. Opera mixes up the priority order, though. Instead of simply using the last applicable property in the list, it treats padding-left as more specific than padding and all.

The real problem is WebKit. It’s somehow managed to execute a transition multiple times if a property is specified multiple times. To really freak out WebKit, try running a transition for transition-property: padding, padding-left with the very small transition-duration: 0.1s (warning: this is not a good idea for epileptics). WebKit will render the transition at least twice. But the real beauty is the TransitionEnd events, of which you could receive up to hundreds for a single transition.

Transitioning From And To auto

The CSS property value auto translates to “Dear browser, please calculate some reasonable value for this.” Paragraphs (<p>) and any block-level elements will be as wide as their parent if they have width: auto. There are times when you’ll change from width: auto to a specific width — and want to transition that change. The specification neither enforces nor denies the use of auto values for transitionable properties.

Firefox, IE and Opera cannot transition from or to auto values. IE makes a little exception for z-index, but that’s it. WebKit, on the other hand, is capable of transitioning from and to pretty much any CSS property that accepts the auto value. WebKit doesn’t like clip too much; for that property, it will only trigger a TransitionEnd event, without generating or showing any intermediate values or states during the transition.

For the other properties, such as width and height, WebKit’s behavior is not quite what you’d expect. If width: auto translated to a calculated width of 300px and you transitioned that to 100px, then your transition would not shrink from 300 to 100 pixels. Instead, it would grow from 0 to 100 pixels.

For a full compatibility table, have a look at “CSS Animatable Properties.”

Implicit Transitions

An “implicit transition” happens when a change to one property causes another property to be transitioned — or if you change a property on a parent element and cause a child to transition either the inherited property or a dependent property. Confused? Consider font-size: 18px; padding: 2em; — the padding is calculated as 2 × font-size, because that’s what em does, giving us 36 pixels.

There are various relative value types: <percentage>, <length>, em, rem, vh, vw, etc. Using a relative value, such as padding: 2em, makes the browser recalculate the property’s getComputedValue() every time its depending value (such as font-size) changes. That in turn triggers a transition for padding because the computed style has changed. This transition is considered to be “implicit” because the padding property was not modified explicitly.

Most browsers run these implicit transitions. The exception is IE 10, which runs them only for the line-height property. WebKit runs implicit transitions for all applicable properties except vertical-align. Besides font-relative property values, there are width-relative property values (usually <percentage>), viewport-relative property values (such as vh and vw), default initial values (such as column-gap: 1em in Opera), and then currentColor. All of these might — or might not — trigger implicit transitions.

In Firefox, these implicit transitions get particularly interesting when both the depending and the dependent properties are transitioned but their transition-duration or transition-delay do not match. While WebKit and Opera produce transitions that make sense visually, Firefox garbles things a bit. In IE, this is a non-issue because it doesn’t do implicit transitions.

Don’t forget about inheritance within the cascade. A font-size on a DOM element will be inherited by its children, as long as it’s not overwritten, potentially causing implicit transitions.

Transitions And Pseudo-Elements

Pseudo-elements (:before and :after) were introduced with CSS2 generated content. Read “Learning to Use the :before and :after Pseudo-Elements in CSS” if you’re not yet familiar with generated content. While CSS3 content defines additional pseudo-elements (::alternate, ::outside), they are not (yet) supported. All animatable CSS properties should also be animatable for pseudo-elements.

Firefox and IE 10 will transition properties on pseudo-elements. Opera, Chrome and Safari will not. WebKit added support in January 2013 — which you can already check out in WebKit nightly and Chrome Canary.

Transitions of generated content bring their own set of funky issues. TransitionEnd events aren’t fired at all. At some point in the future, they’re supposed to be triggered on the owner element and provide their pseudo-element through TransitionEnd.pseudoElement. But even the “Transition Events” section of the “CSS Transitions” editor’s draft doesn’t specify that properly yet.

There was a time when we would change the value of the content property so that IE 8 would re-render that element in certain circumstances (like when entering a :hover state). It turns out that this fix for old IE interferes with this ability for all other browsers. So, when trying to transition a property on a pseudo-element, make sure the content is not changed.

IE 10 will not run a transition for a pseudo-element’s :hover state if the owner element doesn’t have a :hover state as well:


.some-selector:before {
  content: "hello";
  color: red;
  transition: all 1s linear 0s;
}

.some-selector:hover:before {
  color: green;
}
/* This next rule is necessary for IE 10 to transition :before on hover */
.some-selector:hover {}

The weird thing about this issue isn’t that you need a (possibly empty) :hover state on the owner element. It’s that if you don’t have one, IE 10 will interpret the :hover as :active (i.e. active when you mousedown on the element). The even weirder part is that the :active state persists even after mouseup and is removed only by another click on the document.

Background Tabs

At the time of writing, IE 10 is the only browser that responds to a tab being in the background or foreground. While it will finish a running transition if the tab is pushed to the background, it won’t start any new transitions there. IE 10 will wait until the tab is pulled into the foreground before starting any new transitions. Fortunately, IE 10 already supports the Page Visibility API, allowing developers to respond to this behavior.

We can expect similar things to happen with other browsers as they continue putting background tabs to sleep.

“Invisible” Elements

So, are transitions executed for DOM elements that are not attached to the DOM? Nope, not a single browser does that — why should they? Well, then, what about hidden elements? Most browsers have figured out that there’s no need to run a transition on an invisible (i.e. not painted) element. Opera thinks differently about this — it’ll run a transition regardless of whether it is painted or not.

Transitioning Before The DOM Is Ready?

The DOMContentLoaded event is triggered when the document leaves parsing mode. If you’re into jQuery, we’re talking about jQuery.ready() right now. Transitions can be run before this event happens.

Rendering Quirks

The issues I’ve described up to this point were found by testing against the specification. The tests were run automatically. But as it turns out, quite a few more problems are visible to the eye. The following quirks have been found by various other developers and could affect your meddling with transitions just as much.

At this time, transitioning a background from gradient to gradient is not possible. Transitioning from gradient to solid color is possible — with a big caveat. If a gradient is in play, then the color transition will happen from white to the target color, appearing to quickly flash white at the beginning of the transition. This can be observed in all current browsers.

Firefox seems to be using a different algorithm for rendering (or smoothing) images as they’re being animated (see an example). Apparently, Gecko sacrifies quality for performance during animation. Note that this occurs if a low enough transform: scale() is in play.

Firefox won’t properly animate from a:visited to a:hover or vice versa. Instead, it will jump from a:visited to a:link and then transition to a:hover, as you can see in this example. This is mentioned somewhat in “Privacy and the :visited Selector” on the Mozilla Developer Network. While IE 10 agrees with Chrome, Safari and Opera on the proper transition, it also runs the transition from a:link to a:visited on page load.

Transitioning multiple properties is not synchronized in Firefox and Webkit. You can see in this example how making the border smaller by the same amount that the padding increases (and vice versa) causes the following content to shake a bit. IE 10 and Opera get this right.

Firefox won’t animate an element’s properties if one of its parent’s position is changed, as you can see. Webkit, Opera and IE 10 behave correctly.

Recommendations For The Specification

Having read the specification from top to bottom and actually tested all of the features, I think a few changes would help:

  • Introduce a TransitionsEnd (notice the plural), triggered once all transitions for an element have completed. It could provide a list of properties that have been animated — but I don’t see the use case for knowing what has transitioned, as long as I’m informed when all animations are done.
  • Introduce a TransitionStart event, triggered for every property about to be transitioned. Because DOM events don’t come cheap and the JavaScript event loop and the rendering thread are not necessarily blocking each other, a single event TransitionsStart (there is that plural again) might be the better solution. I don’t see why I should be able to cancel the event, so this would be a “fire and forget” kind of thing.
  • Make it clear what TransitionEnd is supposed to be triggered for. That padding versus padding-left issue in WebKit is rather annoying.
  • Clearly specify how “implicit transitions,” such as line-height: 1em for transition-property: font-size, are to be handled.
  • Add a ::transitioning pseudo-class that allows you to define pointer-events: none to prevent accidental hover states (among other things). The trick here is to prevent the application of styles that themselves would trigger a new transition or that would alter an already running transition.

In addition to these suggestions, we should be able to accomplish a number of common (simple) things without having to throw a lot of JavaScript at the problem:

  • Every once in a while, you’ll want to completely mute all transitions — for example, because you’re changing the layout and need to calculate dimensions and positions before unleashing your beautiful transitions upon the visitor.
  • Sometimes you’ll want to remove an object from the DOM and want that to be animated. Right now, you’d add a class, wait for the TransitionEnd event and then remove the element.
  • Just as with removing things, you’ll want to add a new element and animate its appearance. Right now, you have to insert the element, set some “invisible style,” force a repaint and then revert to the new element’s actual style.
  • Reordering, hiding and showing elements are common for any Web application. Giving that task a little style currently requires us to run utilities such as Isotope. A vanilla CSS solution could shave off some bytes.

Use The delay, Luke!

Imagine a number of elements packed together tightly. Imagine that the styles of those elements change on hover. Imagine moving your cursor (moderately quickly) over that group. What happens? Exactly: you’ll see the styles of those elements flash.

By adding a relatively short delay to your transitions, you can mitigate that effect; 20 milliseconds is undetectable to the human eye, but it’s enough for the mouse cursor to pass over small elements. The transitions won’t appear to lag because of this, and the visual distraction you might have caused just disappears. Simple trick, I know.

Conclusion

  • Be very careful when using transition-property: all. You will get TransitionEnd events for properties that you didn’t expect to ever transition.
  • Be careful when using shorthand properties, because the number of triggered events varies between browsers.
  • Opera and IE don’t trigger events when a negative delay cancels out the duration.
  • WebKit has real issues with the priority of properties such as transition-property: margin, margin-left. Avoid this for now.
  • IE doesn’t support implicit transitions — for example, triggered for padding: 2em when font-size changes.
  • Firefox and Opera cannot parse transition-property: all, width.
  • Opera mixes up the priority of properties.
  • Transitions on pseudo-elements do not trigger TransitionEnd events.
  • IE 10 has a weird :hover bug when transitioning pseudo-elements.
  • The specification leaves a lot of room for improvement.

Related Content

If you’re interested in transitions and animations — and how to use them wisely — have a look at these fantastic resources:

Thanks go to Oli Studholme for taking the time to review this article, and Peter Linss for walking me through the CSS Working Group’s testing infrastructure.

(al)


© Rodney Rehm for Smashing Magazine, 2013.

Apr
18
2013

Weak, Strong, Static And Dynamic: An Introduction To Programming Type Systems


  

Static typing is great because it keeps you out of trouble. Dynamic typing is great because it gets out of your way and lets you get your work done faster. The debate between strongly and dynamically typed languages rages on, but understanding the issue starts with weak typing and languages such as C.

C treats everything like a number. A character like a or 7 or % is the number of the ASCII symbol representing it; “true” and “false” are just 1 and 0.

C defines variables with types such as int for integer and char for character, but that just defines how much memory to use. To access the variable and print it out, I need to know the type.


int a = 1;
printf("The number is %i\n", a);

char z = 'z';
printf("The character is %c\n", z);

When I run this program, it shows this:

The number is 1
The character is z

The printf function needs a hint from us to know how to format the variable. If I give the wrong hint…


char z = 'z';
printf("The character is %i\n", z);

… then I get this:

The character is 122

C doesn’t know whether z is a character or an integer; it has a weak type.

Weak typing is fast because there’s no overhead of remembering the different types, but it leads to some nasty bugs. There’s no way to format the z if you don’t know its type ahead of time. Imagine accessing a variable and getting the number 1229799107. The number could be the result of a mathematical calculation (1,229,799,107), the cost of a government program ($1.2 billion) or a date (Saturday, 20 December 2008). When all you have is the number, there’s no way to know that it’s really the code for the letters in my name: zack.

So far, we’ve just covered weak typing. “Weak versus strong” and “static versus dynamic” are often spoken of synonymously, but they each describe a different phase of the same problem. They’re also politicized, with the words carrying an implied value judgment. “Weak versus strong” makes one of them sound a lot better than the other, while “static vs. dynamic” makes one sound stodgy and the other exciting.


(Image: Cris)

These two terms are used interchangeably, but they describe the difference between the way a language defines types and how it figures them out when the program runs. For example:

Weak with no typing Assembly languages don’t provide any way of specifying or checking types at all. Everything is just a number.
Weak static typing C lets you define object types as structures, but it doesn’t do much to enforce or remember them. C automatically convert between many types. C++ and Objective-C go further with the definitions but still don’t enforce the resulting types.
Strong static typing Java forces you to define all types and checks them with a virtual machine.
Strong dynamic typing Python, JavaScript and Ruby dynamically infer the types of objects, instead of forcing you to define them, and then enforce those types when the program runs in the interpreter. All dynamically typed languages need a strong typing system at runtime or else they won’t be able to resolve the object types.
Weak dynamic typing Dynamically inferred types don’t work in a weakly typed language because there aren’t any types to infer.

No programming language fits any of these definitions 100%. Java is considered one of the most static languages, but it implemented a comprehensive reflection API that lets you change classes at runtime, thus resembling more dynamic languages. This feature allows the Java Virtual Machine to support very dynamic languages such as Groovy.

Functional programming languages such as Lisp, Erlang and Haskell blur the lines even more.

Usually when people argue about the merits of strong versus weak programming languages, they really mean the varying degrees of weak, strong, static and dynamic philosophies in every language.

Weak Static Languages: C, C++ And Objective-C

These next programming languages use a subset of C’s functionality and strict guidelines to improve the loose nature of the language. C++ and Objective-C compile into the same bytes as C, but they use the compiler to restrict the code you can write.

In C++ and Objective-C, our number (1229799107) has a meaning. I can define it as a string of characters and make sure that no one uses it as a currency or a date. The compiler enforces its proper use.

Static typing supports objects with sets of functionality that always work in a well-defined way. Now I can create a Person object and make sure the getName function always returns the string of someone’s name.


class Person {
    public:
        string getName() {
            return "zack";
        }
};

Now I can call my object like this:


Person p;
printf("The name is %s\n", p.getName().c_str());

Static typing goes a long way to avoid the bugs of weakly typed languages by adding more constraints in the compiler, but it can’t check anything when the program is running because a C++ or Objective-C program is just like C code when it runs. Both languages also leave the option of mixing weakly typed C code with static typed C++ or Objective-C to bypass all of the type checking.

Java goes a step beyond that, adding type checking when the code runs in a virtual machine.

Strong Static Languages: Java

C++ offers some stricter ways of using C; Java makes sure you use them. Java needs everything to be defined so that you know at all times what type of object you have, which functions that object has and whether you’re calling them properly.

Java also stopped supporting C code and other ways of getting out of static typing.

The Person object looks almost the same in Java:


public class Person {
    public String getName() {
        return "zack";
    }
}

I get the name by creating a new object and calling the getName function, like this:


public class Main {
    public static void main (String args[]) {
        Person person = new Person();
        System.out.println("The name is " + person.getName());
    }
}

This code creates a new Person object, assigns it to a variable named person, calls the getName function and prints out the value.

If I try to assign my person variable to a different type, such as a character or integer, then the Java compiler will show an error that these types are incompatible. If I was calling a separate API that had changed since I compiled, then the Java runtime would still find the type error.

Java doesn’t allow code outside of a class. It’s a major reason why people complain that Java forces you to write too much boilerplate.

The popularity of Java and its strong adherence to strong typing made a huge impact on the programming landscape. Strong typing advocates lauded Java for fixing the cracks in C++. But many programmers found Java overly prescriptive and rigid. They wanted a fast way to write code without all of the extra definition of Java.

Strong Dynamic Languages: JavaScript, Python, Ruby And Many More

In JavaScript, I define a variable with the keyword var, instead of a type like int or char. I don’t know the type of this variable and I don’t need to until I actually want to access it.

I can define an object in JavaScript with the getName function.


var person = {
    getName: function() {
        return 'zack';
    }
};

alert('The name is ' + person.getName());

Now I have an object named person, and it has a function named getName. If I call person.getName(), it will result in zack.

I declared person as a var, and I can reassign it to anything.


var person = {
    getName: function() {
        return 'zack';
    }
};

person = 5;

alert('The name is ' + person.getName());

This code creates a variable named person and assigns it to an object with a getPerson function, but then it reassigns that variable to the number 5. When this code runs, the result is TypeError: Object 5 has no method 'getName'. JavaScript says that the object 5 doesn’t have a function named getName. In Java, this error would come up during compilation, but JavaScript makes you wait for runtime.

I can also change the type of the object based on the conditions of the program.


var person = {
    getName: function() {
        return 'zack';
    }
};

if (new Date().getMinutes() > 29) {
    person = 5;
}

alert('The name is ' + person.getName());

Now this code will work at 9:15 but will fail at 9:30. Java would call this a type error, but it’s fine in JavaScript.

The most popular form of dynamic typing is called “duck typing” because the code looks at the object during runtime to determine the type — and if it walks like a duck and quacks like a duck, then it must be a duck.

Duck typing enables you to redefine any object in the middle of the program. It can start as a duck and turn into a swan or goose.


var person = {
    getName: function() {
        return 'zack';
    }
};

person['getBirthday'] = function() {
    return 'July 18th';
};

alert('The name is ' + person.getName() + ' ' + 
      'and the birthday is ' + person.getBirthday());

At any point, I can change the nature of my Person object to add the new getBirthday function or to remove existing functionality. Java won’t allow that because you can’t check object types when they’re always changing. Dynamically redefining objects gives you a lot of power, for good and bad.

C shows errors when the program runs. C++, Objective-C and Java use the compiler to catch errors at compile time. JavaScript pushes those errors back to the runtime of the application. That’s why supporters of strong typing hate JavaScript so much: it seems like a big step backward. They’re always looking for JavaScript alternatives.

Which Is Better?

I’m looking for a program to parse XML, find a particular element, make a change and save the file. On a team of Java programmers, I wrote the code in the dynamic language Python.

import sys
import string
from xml.dom.minidom import parse

dom = parse(sys.argv[1])

for node in dom.getElementsByTagName('property'):
    attr = node.attributes['name'];
    if attr.value == 'my value':
        node.childNodes[0] = dom.createTextNode('my new value');

file = open(sys.argv[1], 'w');
file.write(dom.toxml('UTF-8'));
file.close();

This program finds every property node with the name my value and sets the contents to my new value. I define the variables dom for my XML document, node for each node of XML that I find, and attr for the attribute. Python doesn’t even require the keyword var, and it doesn’t know that node has childNodes or that attr has value until I call it.

To change an XML file in Java, I would write a new class, open an input stream, call the DOM parser, traverse the tree, call the right methods on the right elements, and write the file out to an output stream. I could simplify some of those calls with a library, but I’d still have the overhead of defining my static types. All of the extra definition of objects and variables could easily take a hundred lines. Python takes 14.

Dynamic code is generally shorter than static code because it needs less description of what the code is going to do. This program would be shorter in Python than in C++ and shorter in Ruby than in Objective-C.

So, which is better?

The static programmer says: The dynamic programmer says:
“Static typing catches bugs with the compiler and keeps you out of trouble.” “Static typing only catches some bugs, and you can’t trust the compiler to do your testing.”
“Static languages are easier to read because they’re more explicit about what the code does.” “Dynamic languages are easier to read because you write less code.”
“At least I know that the code compiles.” “Just because the code compiles doesn’t mean it runs.”
“I trust the static typing to make sure my team writes good code.” “The compiler doesn’t stop you from writing bad code.”
“Debugging an unknown object is impossible.” “Debugging overly complex object hierarchies is unbearable.”
“Compiler bugs happen at midmorning in my office; runtime bugs happen at midnight for my customers.” “There’s no replacement for testing, and unit tests find more issues than the compiler ever could.”

Static typing made our Person object easier to understand. We defined a Person with a name and agreed about which fields mattered ahead of time. Establishing everything clearly makes our Person easier to debug but harder to change.

What happens when someone in our application needs a second email address? In a static language, we’d need to redefine the object so that everyone has two email addresses, even though most people don’t. Add in a birthday, favorite color and a few more items and every Person will have twice as many fields as they need.

Dynamic languages make this problem much easier. We can add a second email field to one Person without adding it to everyone. Now, each object has only the fields it needs. A static language could handle this with a generic map of values, but then you’re fighting the static environment to write dynamic code. C programmers spent years tearing their hair out over errors in type conversions, corrupt values, and the terrible bugs that come from small typos. They’ve been burnt by weak typing, and dynamic typing looks weak.

Dynamic programmers spent years banging their heads over the rigidity of static languages, and they crave the freedom to make the languages do what they want.

I’ve seen static code get overly complex and become impossible to follow. Try debugging an enterprise JavaBean or understanding all of the details of generics in Java. I’ve seen dynamic code turn into a giant mound of unmaintainable spaghetti. Look at the myriad of terrible JavaScript programs before jQuery. Node.js does some amazing things, but I can’t look at it without traumatic flashbacks of horrible JavaScript that I’ve debugged.

Conclusion

There’s no clear conclusion. Dynamically typed languages are popular now. The pendulum will swing back and forth many times in the coming years. The only solution is flexibility. Learn to work in each environment and you’ll work well with any team.

Image credits of image on front page: Alexflx54

(al) (ea)


© Zack Grossbart for Smashing Magazine, 2013.

Apr
12
2013

Overview And Examples: How To Benefit From CSS Generated Content And Counters


  

Generated content was first introduced in the CSS2 specification. For several years, the feature was used by relatively few Web authors due to inconsistent browser support. With the release of Internet Explorer 8 in 2009, generated content was rediscovered, and many interesting implementations were adopted for the first time. In this article, we’ll discuss some possible uses of generated content.

What Is Generated Content?

In technical terms, generated content is a simple abstraction created by CSS in the document tree. As such, in practical terms, generated content exists only in the layout of the Web document.

Accessing generated content via JavaScript is possible by reading the textual value of the content property:


var test = document.querySelector('#test');
var result   = getComputedStyle(test, ':before').content;
var output = document.querySelector('#output');
output.innerHTML = result;

Inserting Generated Content

Generated content may be inserted before and after the actual content of an element, using the :before and :after pseudo-elements, respectively. To represent the pseudo-elements, we can use the following pseudo-markup.


<p>
   <before>Start</before>
      Actual content
   <after>End</after>
</p>

And our CSS would be:


p:before {
   content: "Start";
}

p:after {
   content: "End";
}

Bear in mind that if you are validating the CSS file against the CSS3 specifications, the :before and :after pseudo-elements should be written as ::before and ::after. Otherwise, the CSS validator will call an error.

As you can see, the property that inserts the two strings is content. This
property accepts the following values:

  • none, normal
    The pseudo-content would not be generated.
  • <string>
    This would be a textual string enclosed in quotation marks.
  • url()
    This function enables us to insert an external resource (usually an image), as with the background-image property.
  • counter(), counters()
    These functions insert counters (see below for details).
  • attr(attribute)
    This function enables us to insert the value of attribute of a given element.
  • open-quote, close-quote, no-open-quote, no-close-quote
    These values automate the generation of quotation marks.

Keep in mind that generated content takes up space on the page, and its presence affects the browser’s computation of the parent element.

Inserting Strings

In the previous example, we inserted two simple strings before and after the actual content of the element. Generated content also enables us to insert more complex symbols, through escaping:


p:before {
   content: "0A7";
   padding-right: 0.2em;
}

The escaped sequence between the double quotation marks is the hexadecimal Unicode value of the paragraph symbol. We can also combine simple strings with Unicode symbols:


p:before {
   content: "( " "0A7" " )";
   padding-right: 0.2em;
}

In case you need it, a comprehensive list of all Unicode characters is available on Alan Wood’s website.

Note that all textual content inside the content property is treated literally. So, spaces and tabs inserted via the keyboard will be inserted on the page as well.

Inserting Icons Using Web Fonts

Web fonts can be used to insert graphical icons through generated content. Depending on the Web font family, you can insert either simple letters or Unicode sequences:


@import url(http://weloveiconfonts.com/api/?family=brandico);

p:before {
   content: "\f303";
   padding-right: 0.3em;
   font-family: 'brandico', sans-serif;
   font-size: 22px;
}

In this example, we have inserted a Twitter icon. Our code could be rewritten as follows:


.icon-twitter:before {
   content: "\f303";
   padding-right: 0.3em;
   font-family: 'brandico', sans-serif;
   font-size: 22px;
}

Inserting Images

We can insert images through the url() function.


a:before {
   content: url(link.png);
   padding-right: 0.2em;
}

As you can see, this function has the same syntax as the background-image property.

Inserting Attribute Values

An attribute value of an element can be inserted through the attr() function.


a[href]:after {
   content: "( " attr(href) " )";
   padding-left: 0.2em;
   color: #000;
   font: small "Courier New", Courier, monospace;
}

We’ve just inserted the value of the href attribute, which is a simple text string.

Inserting Counters

The automatic numbering of CSS is controlled by two properties,
counter-reset and counter-increment. Counters defined by these properties are then used with the counter() and counters() functions of the content property.

The counter-reset property may contain one or more names of counters (i.e. “identifiers”), optionally followed by an integer. The integer sets the value that will be incremented by the counter-increment property for any occurence of the given element. The default value is 0. Negative values are allowed.

The counter-increment property is similar. The basic difference is that this one increments a counter. Its default increment is 1. Negative values are allowed.

Now we are ready for an example. Take the following markup:


<dl>
   <dt>term</dt>
   <dd>description</dd>
   <dt>term</dt>
   <dd>description</dd>
   <dt>term</dt>
   <dd>description</dd>
</dl>

We want to add progressive numbering (1, 2, 3, etc.) to each definition term (dt) in the list. Here is the CSS:


dl {
   counter-reset: term;
}
dt:before {
   counter-increment: term;
   content: counter(term);
}

The first rule here sets a counter for the definition list. This is called a “scope.” The name (or identifier) of the counter is term. Whatever name we choose for our counter must be identical to the one in the counter-increment property (of course, the name should be meaningful).

In the second rule, we attach the :before pseudo-element to the dt element, because we want to insert the counter precisely before the actual content of the element. Let’s take a closer look at the second declaration of the second rule. The counter() function accepts our identifier (term) as its argument, and the content property generates the counter.

There’s no space between the number and the content of the element. If we want to add a space and, say, a period after the number, we could insert the following string in the content property:


dt:before {
   content: counter(term) ". ";
}

Note that the string between the quotation marks is treated literally; that is, the space after the period is inserted just as we’ve typed it on the keyboard. In fact, the content property can be regarded as the CSS counterpart of the JavaScript document.write() method, except that it doesn’t add real content to the document. Simply put, the content property creates a mere abstraction in the document tree but doesn’t modify it.

In case you’re wondering, we can add more styles to counters by applying other properties to the attached pseudo-element. For example:


dt:before {
   content: counter(term);
   padding: 1px 2px;
   margin-right: 0.2em;
   background: #ffc;
   color: #000;
   border: 1px solid #999;
   font-weight: bold;
}

We’ve just set a background color, added some padding and a right margin, made the font bold, and outlined the counters with a thin solid border. Now our counters are a little more attractive.

Furthermore, counters may be negative. When dealing with negative counters, we should adhere to a little math — namely, the part about adding and subtracting negative and positive numbers. For example, if we need progressive numbering starting from 0, we could write the following:


dl {
   counter-reset: term -1;
}
dt:before {
   counter-increment: term;
   content: counter(term) ". ";
}

By setting the counter-reset property to -1 and incrementing it by 1, the resulting value is 0, and the numbering will start from that value. Negative counters may be combined with positive counters to interesting effect. Consider this example:


dl {
   counter-reset: term -1;
}
dt:before {
   counter-increment: term 3;
   content: counter(term) ". ";
}

As you can see, adding and subtracting negative and positive numbers yield a wide range of combinations between counters. With just a simple set of calculations, we get complete control over automatic numbering.

Another interesting feature of CSS counters lies in their ability to be nested. In fact, numbering may also be ordered by progressive sublevels, such as 1.1, 1.1.1, 2.1 and so on. To add a sublevel to the elements in our list, we would write the following:


dl {
   counter-reset: term definition;
}
dt:before {
   counter-increment: term;
   content: counter(term) ". ";
}
dd:before {
   counter-increment: definition;
   content: counter(term) "." counter(definition) " ";
}

This example is similar to the first one, but in this case we have two counters, term and definition. The scope of both counters is set by the first rule and “lives” in the dl element. The second rule inserts the first counter before each definition term in the list. This rule is not particularly interesting because its effect is already known. Instead, the last rule is the heart of our code because it does the following:

  1. increments the second counter (definition) on dd elements;
  2. inserts the first counter (term), followed by a period;
  3. inserts the second counter (definition), followed by a space.

Note that steps 2 and 3 are both performed by the content property used on the :before pseudo-element that is attached to the definition term.

Another interesting point is that counters are “self-nesting,” in the sense that resetting a counter on a descendant element (or pseudo-element) automatically creates a new instance of the counter. This is useful in the case of (X)HTML lists, where elements may be nested with arbitrary depth. However, specifying a different counter for each list is not always possible because it might produce rather redundant code. For this reason, the counters() function is useful. This function creates a string that contains all of the counters with the same name of the given counter in the scope. Counters are then separated by a string. Take the following markup:


<ol>
   <li>item</li>
   <li>item
      <ol>
         <li>item</li>
         <li>item</li>
         <li>item
            <ol>
               <li>item</li>
               <li>item</li>
            </ol>
         </li>
      </ol>
   </li>
</ol>

The following CSS will number the nested list items as 1, 1.1, 1.1.1, etc.


ol {
   counter-reset: item;
   list-style: none;
}
li {
   display: block;
}
li:before {
   counter-increment: item;
   content: counters(item, ".") " ";
}

In this example, we have only the item counter for each nested level. Instead of writing three different counters (such as item1, item2, item3) and thus creating three different scopes for each nested ol element, we can rely on the counters() function to achieve this goal. The second rule is important and deserves further explanation. Because ordered lists have default markers (i.e. numbers), we’d get rid of these markers by turning the list items into block-level elements. Remember that only elements with display: list-items have markers.

Now we can look carefully at the third rule, which does the actual the work. The first declaration increments the counter previously set on the outermost list. Then, in the second declaration, the counters() function creates all of the counter’s instances for the innermost lists. The structure of this function is as follows:

  1. Its first argument is the name of the given counter, immediately followed by a comma.
  2. Its second argument is a period between double quotation marks.

Note that we’ve inserted a space after the counters() function to keep the numbers separate from the actual contents of the list items.

Counters are formatted with decimal numbers by default. However, the styles of the list-style-type property are also available for counters. The default notation is counter(name) (i.e. no styling) or counter(name, 'list-style-type') to change the default formatting. In practice, the recommended styles are these:

  • decimal
  • decimal-leading-zero
  • lower-roman
  • upper-roman
  • lower-greek
  • lower-latin
  • upper-latin
  • lower-alpha
  • upper-alpha

Don’t forget that we’re working with numeric systems. Also remember that the specification doesn’t define how to render an alphabetical system beyond the end of an alphabet. For example, the rendering of lower-latin after 26 list items is undefined. Thus, numerals are recommended for long lists:


dl {
   counter-reset: term definition;
}
dt:before {
   counter-increment: term;
   content: counter(term, upper-latin) ". ";
}
dd:before {
   counter-increment: definition;
   content: counter(definition, lower-latin) ". ";
}

We can also add styles to the counters() function:


li:before {
   counter-increment: item;
   content: counters(item, ".", lower-roman) " ";
}

Note that the counters() function also accepts a third argument (lower-roman) as the last item in its arguments list, separated from the preceding period by a second comma. However, the counters() function doesn’t allow us to specify different styles for each level of nesting.

Conclusion

With the new generation of browsers, we can use CSS-generated content to embellish our layouts with strings and graphics. Generated content, then, is surely an excellent tool that every developer should learn.

Further Reading

Source of image on front page: Riebart

(al)


© Gabriele Romanato for Smashing Magazine, 2013.

Apr
9
2013

Release: Responsive Nav: A Simple JavaScript Plugin For Responsive Navigation


  

There are several ways to make navigation responsive, and usually the solution we need is quite straightforward. But despite the apparent simplicity, there are many underlying factors which, when thought through and implemented properly, can make a simple solution even better without adding more complexity to the user interface.

One of the problems I’ve encountered while building responsive navigations is that browsers currently don’t support CSS3 transitions to a height which is defined auto. Most of the time, we shouldn’t use fixed height either because the height of menu items might not be the same in all browsers, and the number of items may change. I also always try to reduce the weight of pages I build, so I’ve been wanting a solution that doesn’t require a big library such as jQuery to work.

Today, I’m pleased to introduce Responsive Nav, a free and open-source JavaScript plugin that solves these problems and more in one tiny package. It’s released under the MIT License, so you can use it in all of your projects for free and without any restrictions. The solution is not one size fits all, nor is it meant to be. But for those who are looking for a solution that does one thing well, it’s definitely a good choice.

Official site of Responsive Nav plugin.
The official site, view live at responsive-nav.com.

Features

Responsive Nav is a tiny JavaScript plugin which weighs only 1.6 KB minified and Gzip’ed, and helps you to create a toggled navigation for small screens. It uses touch events and CSS3 transitions for the best possible performance. It also contains a “clever” workaround that makes it possible to transition from height: 0 to height: auto, which isn’t normally possible with CSS3 transitions.

  • Simple, semantic markup.
  • Weighs only 1.6 KB minified and Gzip’ed.
  • Doesn’t require any external library.
  • Uses CSS3 transitions and touch events.
  • Removes the 300 ms delay between a physical tap and the click event.
  • Makes it possible to use CSS3 transitions with height: auto.
  • Built with accessibility in mind, meaning that everything works on screen readers and with JavaScript disabled, too.
  • Works in all major desktop and mobile browsers, including IE 6 and up.
  • Free to use under the MIT license.

The official demo of Responsive Nav plugin.
The official demo, View live at responsive-nav.com/demo.

How It Works?

Responsive Nav is the successor of TinyNav.js which was released in 2011. While TinyNav worked so that it converted a regular navigation to a select menu, Responsive Nav only hides the original navigation and adds a toggle which opens and closes it. Responsive Nav doesn’t basically alter the html structure of the document at all, so it’s in that sense a much simpler solution.

Responsive Nav works by calculating in the background the max-height needed to fit all the menu items. When the user taps the navigation toggle the plugin uses CSS3 transitions to transition from a height that is set to 0 to the max-height it calculated earlier. Responsive Nav also attaches a touchstart event listener to the toggle, which makes it possible to remove the default 300 ms delay that happens when using click events.

Why Choose This Over Another Solution?

Responsive Nav is lightweight and doesn’t depend on any external library. The navigation opens instantly on touchstart — no more 300 ms delay on touch devices. It’s also (as far as I know) the only responsive navigation plugin out there that uses CSS3 transitions with variable height (although correct me if I’m wrong). Responsive Nav is also built with accessibility in mind, meaning that everything works on screen readers and with JavaScript disabled, right out of the box. Finally, Responsive Nav has been tested to work on 60+ mobile and desktop browsers, so that you would’t have to worry about browser support. See the full list of tested platforms.

Demo And Download

(al) (ea)


© Viljami Salminen for Smashing Magazine, 2013.

Apr
2
2013

A Thorough Introduction To Backbone.Marionette (Part 2)


  

In the first part of this series, we discussed Backbone.Marionette’s Application. This time around, we’ll discuss the module system that is included in Backbone.Marionette. Modules are accessible through the Application, but modules are a very large topic and deserve an article dedicated to them.

What Are Modules?

Before we get into the details of how to use Marionette’s module system, we should make sure we all have a decent definition of a module. A module is an independent unit of code that ideally does one thing. It can be used in conjunction with other modules to create an entire system. The more independent a unit of code is, the more easily it can be exchanged or internally modified without affecting other parts of the system.

For this article, that’s about as much as we need to define modules, but if you want to learn more about writing modular code, plenty of resources are on the Internet, of which the “Maintainability Depends on Modularity” chapter of Single Page Apps in Depth is one of the better ones out there.

The JavaScript language doesn’t currently have any built-in methods for defining modules (the next version should change that), but many libraries have arisen to provide support for defining and loading modules. Marionette’s module system, sadly, doesn’t provide support for loading modules from other files, but it does offer some functionality that other module systems do not have, such as the ability to start and stop a module. We’ll cover more of that later. Right now, we will just start with defining a module.

Module Definition

Let’s start with the most basic of module definitions. As mentioned, modules are accessible through the Application, so we need to instantiate one of those. Then we can use its module method to define a module.


var App = new Backbone.Marionette.Application();

var myModule = App.module(‘myModule’);

That’s pretty simple, right? Well, it is, but that’s the simplest module we can create. What exactly did we create, though? Essentially, we told the application that we want a barebones module, with no functionality added by us, and that it will be named myModule (according to the argument we passed into module). But what is a barebones module? It’s an instantiation of a Marionette.Module object.

Module comes with a bit of functionality baked in, such as events (through EventAggregator, which we’ll discuss thoroughly in a later article), starting with initializers (just like Application has), and stopping with finalizers (we’ll go over that in the “Starting and Stopping Modules” section).

Standard Module Definition

Now let’s look at how to define a module with some of our own functionality.


App.module("myModule", function(myModule, App, Backbone, Marionette, $, _){
    // Private Data And Functions
    var privateData = "this is private data";

    var privateFunction = function(){
        console.log(privateData);
    }

    // Public Data And Functions
    myModule.someData = "public data";

    myModule.someFunction = function(){
        privateFunction();
        console.log(myModule.someData);
    }
});

As you can see, there’s a lot of stuff in there. Let’s look at the top line and work our way down. Just like before, we call App.module and provide a name for the module. But now we’re also passing a function in, too. The function is passed several arguments. I bet you can figure out what they are, based on the names I’ve given them, but I’ll still explain them all:

  • myModule is the very module you’re trying to create. Remember, it’s already created for you, and it’s a new instance of Module. You’re probably going to want to extend this with some new properties or methods; otherwise, you might as well stick with the short syntax that doesn’t require you to pass in a function.
  • App is the Application object that you called module on.
  • Backbone is, of course, the reference to the Backbone library.
  • Marionette is the reference to the Backbone.Marionette library. It is actually available through Backbone, but this allows you to alias it and make it a shorter name.
  • $ is your DOM library, which will be either jQuery or Zepto (or possibly something else in the future).
  • _ is a reference to Underscore or Lodash, whichever you’re using.

After that, you can actually pass in and use custom arguments. We’ll go over this in a bit.

Normally, I would say that most of these arguments are unnecessary; after all, why wouldn’t you already have access to these references? However, I could see these being useful in a couple of situations:

  • A minifier can shorten the names of the arguments, saving some bytes.
  • If you’re using RequireJS or some other module loader, you only need to pull in the Application object as a dependency. The rest will be available through the arguments given to you by Module.

Anyway, let’s get back to explaining the rest of what’s going on in the code above. Inside the function, you can utilize the closure to create private variables and functions, which is what we’ve done. You can also expose data and functions publicly by adding them as properties of myModule. This is how we create and extend our module. There is no need to return anything because the module will be accessible directly through App, as I’ll explain in the “Accessing a Module” section below.

Note: Make sure that you only try to add properties to your module variable and do not set it equal to something (for example, myModule = {…}), because when you set your module variable to something, that changes what the variable’s name is referencing, and none of the changes you specify will show up in your module later.

Earlier, I noted that you can send in custom arguments. In fact, you can send in as many custom arguments as you want. Take a look at the code below to see how it’s done.


App.module("myModule", function(myModule, App, Backbone, Marionette, $, _, customArg1, customArg2){
    // Create Your Module
}, customArg1, customArg2);

As you can see, if you pass additional arguments to module, it will pass those in to the function that you are defining your module in. Once again, the biggest benefit I see from this is saving some bytes after minification; other than that, I don’t see much value.

Another thing to note is that the this keyword is available within the function and actually refers to the module. This means you don’t even need the first argument, but you would lose the advantage of minification if you didn’t use the argument. Let’s rewrite that first code using this so that you can see that it’s exactly the same as myModule.


App.module("myModule", function(){
    // Private Data And Functions
    var privateData = "this is private data";

    var privateFunction = function(){
        console.log(privateData);
    }

    // Public Data And Functions
    this.someData = "public data";

    this.someFunction = function(){
        privateFunction();
        console.log(this.someData);
    }
});

As you can see, because I’m not using any of the arguments, I decided not to list any of them this time. It should also be obvious that you can skip the first argument and just use this.

Split Definitions

The final thing I’ll mention about defining modules is that we can split up the definitions. I don’t know exactly why you would want to do this, but someone might want to extend your modules later, so splitting up the definitions might help them avoid touching your original code. Here’s an example of split definitions:


// File 1
App.module("myModule", function(){
    this.someData = "public data";
});

// File 2 
App.module("myModule", function(){
    // Private Data And Functions
    var privateData = "this is private data";

    var privateFunction = function(){
        console.log(privateData);
    }

    this.someFunction = function(){
        privateFunction();
        console.log(this.someData);
    }
});

This gives us the same result as the previous definition, but it’s split up. This works because in File 2, the module that we defined in File 1 is being given to us (assuming that File 1 was run before File 2). Of course, if you’re trying to access a private variable or function, it has to be defined in the module definition where it is used because it’s only available within the closure where it is defined.

Accessing A Module

What good is creating modules if we can’t access them? We need to be able to access them in order to use them. Well, in the very first code snippet of this article, you saw that when I called module, I assigned its return value to a variable. That’s because we use the very same method to both define and retrieve modules.


var myModule = App.module("myModule");

Normally, if you’re just trying to retrieve the module, you’ll pass in the first argument, and module will go out and grab that module for you. But if you pass in a function as the second argument, the module will be augmented with your new functionality, and it will still return your newly created or modified module. This means you can define your module and retrieve it all with a single method call.

This isn’t the only way to retrieve modules, though. When a module is created, it is attached directly to the Application object that it was constructed with. This means you can also use the normal dot notation to access your module; but this time, it must be defined beforehand, otherwise you’ll get undefined back.


// Works but I don't recommend it
var myModule = App.myModule;

While this syntax is shorter, it doesn’t convey the same meaning to other developers. I would recommend using module to access your modules so that it is obvious you are accessing a module and not some other property of App. The convenience and danger here is that it will create the module if it doesn’t already exist. The danger comes if you misspell the name of the module; you won’t have any way of knowing that you didn’t get the correct module until you try to access a property on it that doesn’t exist.

Submodules

Modules can also have submodules. Sadly, Module doesn’t have its own module method, so you can’t add submodules to it directly, but that won’t stop us. Instead, to create submodules, you call module on App, just like you used to do; but for the name of the module, you need to put a dot (.) after the parent module’s name and then put the name of the submodule.


App.module('myModule.newModule', function(){
    ...
});

By using the dot separator in the module’s name, Marionette knows that it should be creating a module as a submodule of the module before the dot. The cool (and potentially dangerous) part is that if the parent module isn’t created at the time that you call this, it will create it along with its submodule. This can be dangerous because of the same potential for misspelling that I mentioned earlier. You could end up creating a module that you didn’t intend to create, and the submodule would be attached to it, instead of to the module you intended.

Accessing Submodules

As before, submodules can be accessed the very same way they are defined, or you can access them as properties of the module.


// These all work. The first example is recommended
var newModule = App.module('myModule.newModule');
var newModule = App.module('myModule').newModule;
var newModule = App.myModule.newModule;

// These don't work. Modules don't have a 'module' function
var newModule = App.myModule.module('newModule');
var newModule = App.module('myModule').module('newModule');

Any of these methods of accessing the submodule will work equally well if both the module and submodule have already been created.

Starting And Stopping Modules

If you read the previous article in the series, about Application, you will know that you can start an Application with start. Well, starting modules is the same, and they can also be stopped with stop.

If you recall (assuming you’ve read the previous article), you can add initializers with addInitializer to an Application, and they will be run when it is started (or will run immediately if the Application has already started). A few other things happen when you start an Application. Here are all of the events, in order:

  • fires the initialize:before event,
  • starts all of the defined modules,
  • runs all of the initializers in the order they were added,
  • fires the initialize:after event,
  • fires the start event.

A Module behaves in a very similar way. The number of events and some of the names of the events are different, but overall it is the same process. When a module is started, it:

  • fires the before:start event,
  • starts all of its defined submodules,
  • runs all of its initializers in the order they were added,
  • fires the start event.

The stop method is also very similar. Instead of adding initializers, though, you need to add finalizers. You do this with addFinalizer and by passing in a function to run when stop is called. Unlike with initializers, no data or options are passed along to each of the functions. When stop is called, it:

  • fires the before:stop event,
  • stops its submodules,
  • runs its finalizers in the order they were added,
  • fires the stop event.

Initializers and finalizers aren’t only meant for use by others. In fact, they are quite helpful when used inside the module definition. This way, you can define a module inside the definition without actually creating any objects to be used, but then write your initializers to start creating the objects and setting them up, such as in the example below.


App.module("myModule", function(myModule){
    myModule.startWithParent = false;

    var UsefulClass = function() {...}; // Constructor definition
    UsefulClass.prototype ... // Finish defining UsefulClass
    ...

    myModule.addInitializer(function() {
        myModule.useful = new UsefulClass();
        // More setup
    });

    myModule.addFinalizer(function() {
        myModule.useful = null;
        // More tear down
    });
});

Automatic And Manual Starting

When a module is defined, by default it will automatically start at the same time that its parent starts (either the root Application object or a parent module). If a module is defined on a parent that has already started, it will start immediately.

You can set up a module to not start automatically by changing its definition in one of two ways. Inside the definition, you can set a module’s startWithParent property to false, or you can pass an object (instead of a function) to module that has a startWithParent property set to false and a define property to replace the normal function.


// Set 'startWithParent' inside function
App.module("myModule", function(){
    // Assign 'startWithParent' to false
    this.startWithParent = false;
});

// -- or --

// Pass in object 
App.module("myModule", {
    startWithParent: false,

    define: function(){
        // Define module here
    }
});

App.start();

// myModule wasn't started, so we need to do it manually
App.module('myModule').start("Data that will be passed along");

Now the module won’t autostart. You must call start manually to start it, as I did in the example above. The data that is passed to start could be anything of any type, and it will be passed along to the submodules when they’re started, to the initializers, and to the before:start and start events.

As I said, data isn’t passed along like this when you call stop. Also, stop must be called manually, and it will always call stop on submodules; there is no way around this. This makes sense because a submodule shouldn’t be running when its parent isn’t running, although there are cases when a submodule should be off when its parent is running.

Other Events And Built-In Functionality

I mentioned that Module comes with some baked-in functionality, such as the EventAggregator. As discussed, we can use the on method on a module to watch for events related to starting and stopping. That’s not all. There are no other built-in events, but a module can define and trigger their own events. Take a look:


App.module('myModule', function(myModule) {
    myModule.doSomething = function() {
        // Do some stuff
        myModule.trigger('something happened', randomData);
    }
});

Now, whenever we call doSomething on the module, it will trigger the something happened event, which you can subscribe to:


App.module('myModule').on('something happened', function(data) {
    // Whatever arguments were passed to `trigger` after the name of the event will show up as arguments to this function
    // Do something with `data`
});

This is very similar to the way we do things with events on collections, models and views in normal Backbone code.

How We Might Actually Use A Module

The modules in Marionette can definitely be used to define modules very similarly to any other module definition library, but that’s actually not how it was designed to be used. The built-in start and stop methods are an indication of this. The modules that Marionette includes are meant to represent somewhat large subsystems of an application. For example, let’s look at Gmail.

Gmail is a single application that actually contains several smaller applications: email client, chat client, phone client and contact manager. Each of these is independent — it can exist on its own — but they are all within the same application and are able to interact with one another. When we first start up Gmail, the contact manager isn’t up, and neither is the chat window. If we were to represent this with a Marionette application, each of those sub-applications would be a module. When a user clicks the button to open the contact manager, we would stop the email application (because it becomes hidden — although, for speed, we could keep it running and just make sure it doesn’t show in the DOM) and start the contacts manager.

Another example would be an application built largely out of widgets. Each widget would be a module that you can start and stop in order to show or hide it. This would be like a customizable dashboard such as iGoogle or the dashboard in the back end of WordPress.

Of course, we’re not limited to using Marionette’s modules in this way, although it’s difficult to use it in the traditional sense. This is because Marionette’s modules are fully instantiated objects, while traditional modules are “classes” that are meant for instantiation later.

Conclusion

Phew! That’s a lot of information. If you’ve made it this far, I commend you (although it was much easier for you to read this than for me to write it). Anyway, I hope you’ve learned a lot about the way that Marionette handles defining, accessing, starting and stopping modules and submodules. You may find it to be a very handy tool, or you might choose to completely ignore its existence. That’s one of the great things about Backbone and Marionette: most of their features are largely independent, so you can pick and choose what you want to use.

Credits of image on front page: ruiwen

(al) (ea)


© Joseph Zimmerman for Smashing Magazine, 2013.

Mar
26
2013

High-Speed Coding: Goodbye, Zen Coding. Hello, Emmet!


  

Back in 2009, Sergey Chikuyonok wrote an article to present a new way of writing HTML and CSS code. This revolutionary plugin, called Zen Coding, has helped many developers through the years and has now reached a new level.

Emmet, previously known as Zen Coding, is the most productive and time-saving text-editor plugin you will ever see. By instantly expanding simple abbreviations into complex code snippets, Emmet can turn you into a more productive developer.

For those who prefer to watch instead of read, here is a summary of my favorite tricks.

How Does It Work?

Let’s face it: writing HTML code takes time, with all of those tags, attributes, quotes, braces, etc. Of course, most text editors have code completion, which helps a lot, but you still have to do a lot of typing. Emmet instantly expands simple abbreviations into complex code snippets.

HTML Abbreviations

Initializers

Getting started with a new HTML document takes less than a second now. Just type ! or html:5, hit “Tab,” and you’ll see an HTML5 doctype with a few tags to jumpstart your application.

Emmet Demonstration - Initializers

  • html:5 or !
    for an HTML5 doctype
  • html:xt
    for an XHTML transitional doctype
  • html:4s
    for an HTML4 strict doctype

Easily Add Classes, IDs, Text and Attributes

Because Emmet’s syntax for describing elements is similar to CSS selectors, getting used to it is very easy. Try mixing an element’s name (e.g. p) with an identifier (e.g. p#description).

Emmet Demonstration - Classes and IDs

Also, you can combine classes and IDs. For example, p.bar#foo will output this:

<p class="bar" id="foo"></p>

Now let’s see how to define content and attributes for your HTML elements. Curly brackets are used for content. So, h1{foo} will produce this:

<h1>foo</h1>

And square brackets are used for attributes. So, a[href=#] will generate this:

<a href="#"></a>

Emmet Demonstration - Texts and Attributes

Nesting

By nesting abbreviations, you can build a whole page using just one line of code. First, the child operator, represented by >, allows you to nest elements. The sibling operator, represented by +, lets you place elements near each other, on the same level. Finally, the new climb-up operator, represented by ^, allows you to climb up one level in the tree.

Emmet Demonstration - Nesting operators

Grouping

To effectively take advantage of nesting without turning them into a confusing mess of operators, you’ll need to group some pieces of code. It’s like math — you just need to use parentheses around certain pieces. For example, (.foo>h1)+(.bar>h2) will output this:

<div class="foo">
  <h1></h1>
</div>
<div class="bar">
  <h2></h2>
</div>

Emmet Demonstration - Grouping

Implicit Tag Names

To declare a tag with a class, just type div.item, and then it will generate <div class="item"></div>.

In the past, you could omit the tag name for a div; so, you just had to type .item and it would generate <div class="item"></div>. Now Emmet is more intelligent. It looks at the parent tag name every time you expand the abbreviation with an implicit name. So, if you declare .item inside of a <ul>, it will generate <li class="item"></li> instead of <div class="item"></div>.

Emmet Demonstration - Implicit tag names

Here’s a list of all implicit tag names:

  • li
    for ul and ol
  • tr
    for table, tbody, thead and tfoot
  • td
    for tr
  • option
    for select and optgroup

Multiplication

You can define how many times an element should be outputted by using the * operator. So, ul>li*3 will produce:

<ul>
  <li></li>
  <li></li>
  <li></li>
</ul>

Emmet Demonstration - Multiplication

Numbering

What about mixing the multiplication feature with some item numbering? Just place the $ operator in the element’s name, the attribute’s name or the attribute’s value to output the number of currently repeated elements. If you write ul>li.item$*3, it will output:

<ul>
  <li class="item1"></li>
  <li class="item2"></li>
  <li class="item3"></li>
</ul>

Emmet Demonstration - Numbering

Try It Now!

Why not try it right now? Go ahead: type in an Emmet HTML abbreviation, and hit the Tab key.

CSS Abbreviations

Values

Emmet is about more than just HTML elements. You can inject values directly into CSS abbreviations, too. Let’s say you want to define a width. Type w100, and it will generate:

width: 100px;

Emmet Demonstration - Values

Pixel is not the only unit available. Try running h10p+m5e, and it will output:

height: 10%;
margin: 5em;

Here’s a list with a few aliases:

  • p → %
  • e → em
  • x → ex

Extra Operator

You already know many intuitive abbreviations, such as @f, which produces:

@font-face {
  font-family:;
  src:url();
}

Some properties — such as background-image, border-radius, font, @font-face, text-outline, text-shadow — have some extra options that you can activate by using the + sign. For example, @f+ will output:

@font-face {
  font-family: 'FontName';
  src: url('FileName.eot');
  src: url('FileName.eot?#iefix') format('embedded-opentype'),
     url('FileName.woff') format('woff'),
     url('FileName.ttf') format('truetype'),
     url('FileName.svg#FontName') format('svg');
  font-style: normal;
  font-weight: normal;
}

Emmet Demonstration - Extra operator

Fuzzy Search

The CSS module uses fuzzy search to find unknown abbreviations. So, every time you enter an unknown abbreviation, Emmet will try to find the closest snippet definition. For example, ov:h and ov-h and ovh and oh will generate the same:

overflow: hidden;

Emmet Demonstration - Fuzzy Search

Vendor Prefixes

CSS3 is awesome, but those vendor prefixes are a real pain for all of us. Well, not anymore — Emmet has abbreviations for them, too. For example, the trs abbreviation will expand to:

-webkit-transform: ;
-moz-transform: ;
-ms-transform: ;
-o-transform: ;
transform: ;

Emmet Demonstration - Vendor Prefixes

You can also add prefixes to any kind of element. You just need to use the - prefix. So, -super-foo will expand to:

-webkit-super-foo: ;
-moz-super-foo: ;
-ms-super-foo: ;
-o-super-foo: ;
super-foo: ;

What if you don’t want all of those prefixes? No problem. You can define exactly which browsers to support. For example, -wm-trf will output:

-webkit-transform: ;
-moz-transform: ;
transform: ;
  • w-webkit-
  • m-moz-
  • s-ms-
  • o-o-

Gradients

Speaking of annoying CSS3 features, we cannot forget gradients. Those long definitions with different notations can now be easily replaced with a concise, bulletproof abbreviation. Type lg(left, #fff 50%, #000), and the output will be:

background-image: -webkit-gradient(linear, 0 0, 100% 0, color-stop(0.5, #fff), to(#000));
background-image: -webkit-linear-gradient(left, #fff 50%, #000);
background-image: -moz-linear-gradient(left, #fff 50%, #000);
background-image: -o-linear-gradient(left, #fff 50%, #000);
background-image: linear-gradient(left, #fff 50%, #000);

Emmet Demonstration - Gradients

Try It Now!

Had enough of the animated GIFs? Go ahead — type an Emmet CSS abbreviation, and hit the Tab key.

Extras

Lorem Ipsum

Forget about those third-party services that generate “Lorem ipsum” text. Now you can do that right in your editor. Just use the lorem or lipsum abbreviations. You can specify how many words to generate. For instance, lorem10 will output:

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Libero delectus.

Emmet Demonstration - Lorem Ipsum

Also, lorem can be chained to other elements. So, p*3>lorem5 will generate:

<p>Lorem ipsum dolor sit amet.</p>
<p>Voluptates esse aliquam asperiores sunt.</p>
<p>Fugiat eaque laudantium explicabo omnis!</p>

Customization

Emmet offers a wide range of tweaks that you can use to fine-tune your plugin experience. There are three files you can edit to do this:

And A Lot More!

This is just the beginning. Emmet has a lot of other cool features, such as encoding and decoding images to data:URL, updating image sizes and incrementing and decrementing numbers.

Go check out the new website, the awesome documentation and the handy cheat sheet!

Supported Editors

If you are wondering, “Will it work in my text editor?,” The answer is, “Oh yes, my friend!” A lot of editors are supported, and I hope you find yours in the list below.

And You?

What are your favorite tricks? Leave a comment below. Now it’s your turn to share your favorite tricks.

(al) (ea)


© Zeno Rocha for Smashing Magazine, 2013.

Mar
21
2013

Device Size Matters: Responsive Web Design With Physical Units


  

This post should be titled “Getting Ahead of Yourself.” “…By a Few Years,” actually. Here’s the deal: at the time I’m writing this, early 2013, there’s no way to accurately design for the Web using physical units, nor will there be for a very long time. But there is a way to design while knowing the physical characteristics of the device — or, at least, there will be in the very near future.

Mobile devices
Different devices can have a similar screen resolution, yet entirely different physical factors. iPad (1st generation) has the diagonal size of 9.7″, the resolution 1024 × 768 and 132 ppi. Kindle Keyboard 3G has the diagonal size of 6″, also the resolution 768 × 1024, yet 212 ppi. Image source: kodomut.

It’s called the “resolution media query”, and it’s been in the specification for media queries for some time. However, while it has been in the spec, that doesn’t mean anyone has actually implemented it yet. Fortunately, WebKit is leading the way and pushing for this feature to be implemented. So, how will we use this nifty little feature, exactly? Here’s how.

The Thin Line Between Queries

First off, I posit that there will be only one use case for a resolution-only media query. Something along the lines of


@media (min-resolution: 250dpi) {

}

has, at this time, only one good use: swapping out low- for high-resolution images. I’ve tried imagining other uses and, as far as I can tell, there just aren’t any. But resolution is not what we, as Web designers, are truly interested in. Since we are designing for humans, shouldn’t we be thinking about the physical side of human data consumption and designing using this kind of a metric? And in a perfect world we could simply say width: 1in and have a one-inch wide element, regardless of the device. Unfortunately, we live in a digital world in which the physical and digital pixels are not the same. We need something to bridge the gap. That something is the resolution media query.

Good. Now that that’s out of the way, let me show you how this one little piece of code can make so much difference that your head will promptly explode. (I take no responsibility for actual blown heads as a result of this post.)

Let’s compare two media-query declarations:


@media (min-resolution: 341dpi) and (min-width: 767px) > {

}

and


@media (max-resolution: 131dpi) and (min-width: 767px) > {

}

At first glance, this doesn’t seem like much of a separation, right? Wrong. The numbers I’ve used are specific to the HTC Windows Phone 8X (the first snippet) and the iPad 2 (the second snippet). By using the resolution query, one can basically separate physically small devices from large devices.

As it currently stands, a query that looks like @media (min-width: 767px){ } will affect both the HTC and the iPad, with no other possibility of separation, because both have a resolution that is 768 pixels wide. In fact, the iPad has a lower resolution, at 1024 × 768, whereas the HTC is 1280 × 768. In case you haven’t realized yet, the problem with all of this is that the iPad is a 10-inch device, while the HTC is a 4.3-inch one. That’s less than half the physical size!

By using the resolution media query together with a width query, we can distinguish between physically small and large devices to adjust design elements and layouts accordingly. While, as mentioned above, screen resolution isn’t really what we are interested in since we use logical breakpoints in responsive design, it is useful to know whether a site is being displayed on a small or a large physical display — e.g. to increase font size or rearrange design elements in the layout. But where do we draw the line between small and large? Quite simply, we can’t. Each of us has to draw the line, possibly on a project-by-project basis, between “This is a small device” and “This is a large device.” As far as ballpark numbers go, I’ve done a few calculations and have developed a theorem that should give you a clearer idea of how this works more or less.

The Physical Size Inquiry Non-Exhaustive Theorem (PSINET)

Here’s the theory: In a combined query, if the ratio between the smaller of the width and height and the resolution, called a PSINET score, is higher than 5, then the result falls in the category of a physically large device. If the resulting number is lower than 5, then it is a physically small device. Devices that score very close to 5 are considered to be medium-sized, close to the physical size of an A4 sheet of paper (21 × 29.7 cm).

Here’s a non-exhaustive list of devices to test the formula above. I’ve listed each device’s score according to the formula, along with its diagonal size, resolution and density, and PSINET score.

Physically Large Devices

Device name Diagonal size (inches) Resolution PPI PSINET score
Apple iMac 27 2560 × 1440 109 13.00
Sony Vaio F 16.4 1920 × 1080 134 8.05
Apple MacBook Pro RD 13 2560 × 1600 227 7.04

Physically Small Devices

Device name Diagonal size (inches) Resolution PPI PSINET score
Sony PSP 4.3 480 × 272 128 3.75
Kindle Keyboard 3G 6 768 × 1024 212 3.62
Kindle Fire 7 1024 × 600 169 3.55
Samsung Galaxy S 4 480 × 800 160 3.00
Samsung Galaxy NoteII 5.5 720 × 1280 267 2.69
Samsung Galaxy S IV 5 1080 × 1920 441 2.62
HTC Butterfly 5 1080 × 1920 441 2.62
Samsung Galaxy Grand I9082 5 480 × 800 187 2.56
Palm Pre 3.1 480 × 320 186 2.5
Sony Xperia Z 5 1920 × 1080 443 2.43
Samsung Galaxy SIII 4.8 720 × 1280 306 2.35
LG Nexus 4 E960 4.7 768 × 1280 318 2.41
Nokia Lumia 920 4.5 1280 × 768 332 2.31
HTC One 4.7 1080 × 1920 469 2.30
HTC One X 4.7 720 × 1280 312 2.30
HTC Desire HD 4.3 480 × 800 217 2.21
BlackBerry Q10 3.1 720 × 720 328 2.19
BlackBerry Z10 4.2 768 × 1280 355 2.16
Motorola Droid X 4.3 854 × 480 228 2.10
Sony Ericsson S 4.3 720 × 1280 342 2.10
Motorola RAZR i XT890 4.3 540 × 960 256 2.10
iPhone 5 4 640 × 1136 326 1.96
Apple iPod Touch 3.5 960 × 640 326 1.96
Nokia Lumia 620 3.8 480 × 800 246 1.95
HTC Wildfire 3.2 240 × 320 125 1.92
Nokia Lumia 710 3.7 800 × 480 252 1.90
Motorola Defy 3.7 854 × 480 265 1.81
LG Optimus One 3.2 320 × 480 180 1.77
Nokia N96 2.8 240 × 320 143 1.67
Sony Ericsson W810i 1.9 176 × 220 148 1.18

Medium-Sized Devices

Device name Diagonal size (inches) Resolution PPI PSINET score
Apple iPad (1 & 2) 9.7 1024 × 768 132 5.81
Apple iPad (3rd Gen) 9.7 2048 × 1536 264 5.81
Amazon Kindle DX 9.7 824 × 1200 150 5.49
Acer Iconia Tab A500 10.1 800 × 1280 149 5.36
Samsung Galaxy Tab 10.1 1280 × 800 149 5.36
Motorola Xoom 10.1 1280 × 800 149 5.36
Asus Transformer Pad Infinity 10.1 1920 × 1200 224 5.35
Microsoft Surface 10.1 1366 × 768 148 5.18
Asus VivoTab RT TF600T 10.1 1366 × 768 155 4.95
iPad Mini 7.9 768 × 1024 162 4.74
Amazon Kindle Fire HD 8.9 1920 × 1200 254 4.72

Is this method of determining device size foolproof? Hardly — that’s why it’s a theorem. It’s based on solid reasoning and empirical evidence and has come about by using the scientific method, but it is not a rule, law or axiom. Take it with a pinch of salt (or, better yet, a truckload of NaCl) and refine it. It is a theorem, a proposition, to be remembered in the future when the resolution media query and our work with it become a mainstay of the Web.

Breaking the Theorem

Like any self-respecting follower of the scientific method, I’ve tried to break my own theorem. Thus, I imagined a freak of a device, 2 inches long and 20 inches wide, putting its diagonal size at 20.09 inches, with a 240 × 40 pixel display, yielding a resolution of just 11.94 PPI. It gets a PSINET score of 2.01, which puts it well into the small device category, even though it’s almost half a meter long. The reason is simple: it’s that 2-inch-wide dimension. Because the PSINET score ignores the longer of the device’s physical width and height, the greater the difference between those two dimensions, the less accurate the PSINET score will be. Sure, this beast of a device is unlikely to ever become reality, but it’s worth understanding the reasons why it would break the theorem.

Device name Diagonal size (inches) Resolution PPI PSINET score
ThinLong 20.09 24 × 240 11.94 2.01

Real-World Applications

Apart from the obvious visual changes and tweaks mentioned above, there are other ways to use the resolution media query.

Enter Enquire.js. For those of you who haven’t heard of it, it’s a very nice JavaScript library that helps you execute particular scripts on matching media queries.

We could use Enquire.js or even just window.matchMedia, which is a native JavaScript method, to differentiate between mobile, tablet and computer users much more reliably than by using width queries alone. Here’s a not-very-polite example using Enquire.js:


enquire.register("screen and max-resolution: 150dpi and max-width: 300px", function() {
    alert('My, what a small screen you have there, Grandma!')
});

Combining media query types with CSS and using a resolution-aware JavaScript library is just the right formula to give us real future-proof control over what I call the “physical Web.” Imagine being able to view a priceless sculpture located in a museum halfway across the Earth on a 1:1 ratio on any device, or shopping for an engagement ring online and seeing exactly how big that 24-carat diamond is. The real-world applications, pun intended, are nearly endless.

In our world of responsive Web design, we’d very much like to provide the best experience to users, whatever their device. In light of the sans-resolution media query above, that task becomes less of a challenge and more a windmill fight. Assigning blame is pointless, because none of us can do anything to change the current ecosystem of devices. Manufacturers will continue to put out devices with resolutions and pixel densities that they’ve pulled out of their butts, and that’s fine — that’s their business. Staying on top of the situation by providing us designers with the tools we need (but can’t easily build ourselves) to create the best user experience possible is the job of browser makers, and I salute the good people at WebKit for spearheading the implementation of the resolution media query.

(al)


© Radu Chelariu for Smashing Magazine, 2013.

Pages:1234567...20»

Categories