![]() |
Web Dev
In my first article, âEven Better In-Browser Mockups with Node.js,â I explained why Node.js makes designing applications easier and more efficient, and how to get started. Now itâs time to see your new design process in action.
Rather than figuring out all your requirements and API schemas just to design your comps with mockup content hard-coded and server interactions fakedâonly to throw it all away when you go back and implement things âfor realââyou can use Node.js to skip the hard-coding and produce client-side code thatâs ready for beta at the end of the design stage.
The process looks a lot like good olâ designing in the browser, but with more JavaScript and an additional layer:
Sound daunting? Donât worry. The first step takes approximately a zillion times longer than any of the others. So if youâve already mastered the design, youâll find the rest of these steps more than manageable.
In this walkthrough, weâll build a feature for a mock art store. If you want to follow along at home, you can clone my GitHub repository. (If you need help installing, see the README, or just take a peek at the live demoâIâll cover all the steps and code below.)
Once you have a solid design and the markup to accompany it, converting it to a template you can use for all examples is more efficient than creating duplicate markup for each one. The hard partâs over; you already thought about where data points would be used in the design when you created it. With those choices fresh in your mind, go back and mark up your HTML with data in whatever template language you prefer.
For my example, Iâm using a store selling art prints. Hereâs a snippet of my initial markup:
<h2>Two Acrobats with a Dog</h2>
<h3>Pablo Picasso</h3>
<img src="img/102.jpg" alt="Two Acrobats with a Dog" class="active" />
<ul class="info">
<li>8" x 11"</li>
<li>acid-free paper</li>
<li>suitable for matting</li>
</ul>
<span class="price">$49.99</span>
Think of your templates as places to define your requirements for both data and its formatting on the client side. If you can also reuse it for client-side rendering, thatâs awesomeâbut that may not be relevant to your application. As long as you have good data, converting from one template language to another is trivial, so donât agonize over which template engine to use.
You do need a template engine that will work in both the browser and Node.js, however. If youâre unsure, search for your template engine on GitHub and verify that thereâs a guide to installing it via npm in the manual, as well as a minified script for use on the client. I prefer doT.js, so hereâs that snippet again marked up to add data using doT:
<h2>{{=it.title}}</h2>
<h3>{{=it.artist.name}}</h3>
<img src="img/{{=it.id}}.jpg" alt="{{=it.title}}" class="active" />
<ul class="info">
{{~it.info :info_item}}
<li>{{=info_item}}</li>
{{~}}
</ul>
<span class="price">{{=it.price}}</span>
I like to save my templates in their own directory at the same level as my JavaScript directory, so now I store that as tmpl/detail.dot.
Since we want to be able to use our templates in both Node and the browser, they need to be stored outside of the HTML and loaded and compiled when we open the page. To start, save the minified version of your template engine and add a script tag to your page to include it. Once thatâs done, you can fetch the template, compile it, and then continue on with any other initialization work in your main JavaScript file. Iâm using jQuery in my example, so my code looks like this:
var detailTmpl;
$.when(
$.get( "tmpl/detail.dot", function( tmpl ) {
detailTmpl = doT.template( tmpl );
}, "text" )
).then( init );
That mysterious init function? Thatâs where Iâll put any interactivity I want to add to my currently static mockup. For the moment Iâm only creating one interaction, so my init function is pretty simple:
function init() {
$( "div.content" ).on( "click", "div.result", showDetail );
}
This code can be made much more elegant using Require.js with its text plugin. Thatâs beyond the scope of this demo, but I highly encourage it for production.
Weâll handle template rendering in showDetail(), but we have to add a server and data store before writing that function, since right now we lack any data to render.
If I reload my page now and open the browser console, I get a JavaScript error. Thatâs because Iâm trying to load my template via an XMLHttpRequest (XHR) on a page being served from the file system, in violation of the same origin policy. I canât even check that my template works until the page is served properly (i.e., from a server).
To whip up a simple Node server that allows me to run my XHRs, I do a few things:
publicnpm install expressWe could write everything from scratch, of course, but itâs more work than is necessary for a basic server. The Express framework provides a number of abstractions of server and application concepts. For the initial version of the server, the only one weâll need is its ability to serve static resources. We can use it by adding four lines of code to server.js:
var express = require( "express" ),
app = express();
app.use( express.static( __dirname + "/public" ) );
app.listen( 3000 );
Once you start your server by typing node server.js in your open terminal or command line, you can view your page at http://localhost:3000 (adding a filename if necessary), and the error related to loading the template ought to disappear.
While itâs certainly nice to be able to use XHRs, we’re creating the Node server to use it as a representation of the real serverâand real servers store data. Though itâs not hard to create a data store that works with a Node server, itâs even less difficult to create one big object literal. For a mockup, thatâs all we really need. One of the goals here is to define the data objects we need to support in our new design, so the format of this object can be determined by the template we just added. For my example, I need an object structured something like this:
var products = {
"102": {
id: 102,
title: "Two Acrobats with a Dog",
artist: {
name: "Pablo Picasso"
},
price: "$49.99",
info: [
"8\" x 11\"",
"acid-free paper",
"suitable for matting"
]
}
};
Note that products could just as easily be an array, but I want to be able to quickly find my productsâonce I have more than one in my fake data storeâby ID. Aside from that little twist, the data look exactly like the content hard-coded in my original HTML. If I want to add more data, including things that might break the layout in unpredictable ways, I can just copy this structure and make substitutions. Well, almost.
If youâve dealt with other server-side frameworks, creating endpoints for XHRs might seem intimidating, but Express makes it really easy. We donât need any special setup to define a server endpoint as a target for asynchronous requests. All we have to do is define the path on the server where we want to accept requests and a callback. The callback receives a request object (for doing things like getting passed-in data) and a response object (for defining what we return to the client). To return the data in my products object, I add a few lines of code at the bottom of server.js:
app.get( "/detail/:id", function( req, res ) {
res.send( products[ req.params.id ] );
});
app.listen( 3000 );
See? Easy. If I restart my server and go to http://localhost:3000/detail/102, I should see my object data. To break down whatâs going on with the ID in the path, weâve named the data at that position in the path "id" with the :id bit, and it then becomes available as a property of req.params.
The names and positions of parameters are up to us, and if our path were super complex, we could also use regular expressions to split out multiple pieces of data. Express also gives us the option of accepting data from the query string or from a POST. Of all the pieces weâre creating, however, the paths are the most likely to change in production, so itâs to our advantage to keep them as readable as possible.
Besides sending pure data to the client, we also want to be able to send rendered HTML, in case a user is linked directly to a product detail or doesnât have JavaScript available. We might also want HTML for our own consumption via XHR, if we find that client-side rendering is slowing us down. So we add a second endpoint below the one we just created to do that:
app.get( "/product/:id", function( req, res ) {
res.render( "detail", products[ req.params.id ] );
});
For simplicityâs sake, and because the first path served JSON for an overlay while this provides a full page, Iâve used a different pathname, but kept the same pattern. This time, instead of the responseâs send function, I use render(). Express provides some magic to make template rendering work out of the box, but since Iâm using doT instead of Jade (the default template engine of Express), I have to do some additional setup.
First I have to go back to the terminal or command line, stop my Node server, and install my template engine using npm install doT and the consolidate module (which provides Express compatibility for a number of popular template engines) using npm install consolidate. Now Iâve got both of those in my node_modules directory and can use them in server.js.
Since doT (and probably your template engine of choice, as well) is accessed through consolidate, consolidate is the only additional module I need to require at the top of server.js:
var express = require( "express" ),
app = express(),
cons = require( "consolidate" );
I want to continue serving some of my other pages statically, so I add my template configuration stuff below the existing app.use line in my code:
app.use( express.static( _dirname + "/public" ) );
app.engine( "dot", cons.dot );
app.set( "view engine", "dot" );
app.set( "views", _dirname + "/public/tmpl" );
Those three new lines set doT (as exposed by consolidate) as the view engine, register files ending in .dot as templates, and tell Express to look in /public/tmpl for templates to use. So when Node sees res.render( "detail", { ... } ), it knows to expand "detail" to /public/tmpl/detail.dot and render it as a doT template. Now I can restart my server, go to http://localhost:3000/product/102, and see my template rendered statically, without creating a separate server-side file.
Our template now works as a static page, but thereâs still one more step to get our mockup populated with the data from the server. Remember the showDetail function from our main client-side script? Itâs time to flesh that out.
In my simple example, the overlay my template will populate already exists as a hidden div on the main page, and it appears when the user clicks a div containing a summary of the content. This div has a data attribute storing the ID of the product that corresponds to the key and id property in my server-side data object. Once that click event happens and showDetail() is called, I just need to do this:
function showDetail( e ) {
var id = $( this ).data( "id" );
$.get( "detail/" + id, function( info ) {
$( "div.detail" ).html( detailTmpl( info ) );
$( "div.detail" ).show();
}
}
The path above is the same one I defined in server.js. If you chose a different name for yours, use that name here on the client. When I receive the data object from the server, I pass it to detailTmpl(), the compiled version of my template. The result of the detailTmpl function is the HTML to populate my overlay.
So there you have it! A mockup that mimics the interactions it will have with its production server precisely on the client, without the need for hard-coded data or temporary workarounds. Despite the simple exercise, the process Iâve outlined accomplishes a good deal of the setup necessary to create other workflows that require server interactions. For instance, I can fill my fake data store with more products and use that to render the initial page that triggers my overlay without having to revisit my mockup data, and my application will show the correct values in any view I add to it.
If youâd like to explore beyond just serving HTML and JSON, consider adding in Socket.io to allow real-time interaction for multiple clients or Require.js to manage your assets on the client. You could also move your CSS into templates and serve different builds of your site for different browsers or devices. Your mockup can be as sophisticated and reflect as many of its production requirements as you choose. At the end, the lionâs share of your client-side code is done and ready to use.
Designing in the browser has all sorts of benefits, like producing more accurate, comprehensive results and removing the extra step of converting from image file to markup and CSS. But even sites designed in a browser still require pasting in content, faking interactions with the server, and creating placeholder JavaScript that isnât usable on the live site.
Wouldnât it be nice if we could go from just designing layouts and interactions to designing the whole client side of the application during the same process?
This is where Node comes in.
Node.js is a server-side JavaScript platform. It isnât a web server, but it allows you to easily create one. It also lets you create utilities that run on web servers, like setup and minification utilities and general-purpose command line tools.
Node started in 2009 and generated considerable interest, probably because it gave JavaScript developers an opportunity to write server-side code even if they lacked a server-side background. It didnât hurt that Chrome had established a reputation for being solid and fast, and Node used its V8 engine.
Today, itâs possible to run production servers on Node, and many people are doing so successfully. Taking it that far, however, is an investment. The Node project, and all the community-created modules that make it so awesome, is still a moving target. But even if youâre not ready to write and launch entire sites with Node, itâs plenty stable enough to use as a development tool.
Itâs JavaScript, so if you can wire up a jQuery event handler, you can write a web server. Itâs lightweight, so you can run it on your laptop and keep streaming music in the background. Itâs dead simple to download, set up, and build in, so you donât need the esoteric knowledge of an IT support person to get going with it. And the payoff is that instead of mockups and hard-coded data, you can design a set of client-side assets, page templates, and data schemas that are ready to launch to production.
Installing Node locally for the most common environments is a piece of cake. You can download installers that include Node as well as npm, its package manager, from the projectâs site. Installing it on a remote server is not quite that easy, but good documentation is available to help you out. After running through the installation process, you should be able to go to your terminal or command line and test it out.
If you donât tell Node to run a specific file, you get a Read-Eval-Print Loop, or REPL. If you type node in your terminal or command prompt, you can begin to execute arbitrary JavaScript. For example, after starting the REPL, type var a = 9;. The REPL will respond with undefined. Now type a * 3 (or any other number) and it will respond with the correct result. You can make things more interesting by defining a function and then calling it:
> function sayHello( name ) { return âHello, â + name; }
undefined
> sayHello( âA List Apartâ );
âHello, A List Apartâ
To break out of the REPL, or end any other Node execution (like a running web server), press Ctrl+C. In the case of the REPL, youâll need to press it twice to confirm.
While itâs nice to know Node can perform basic arithmetic and string concatenation, its value to us as developers is in running programs. You can see an example of one such program, a basic web server, on the projectâs homepage. They suggest creating a file called example.js with this code:
var http = require(âhttpâ);
http.createServer(function (req, res) {
res.writeHead(200, {âContent-Typeâ: âtext/plainâ});
res.end(âHello World\nâ);
}).listen(1337, â127.0.0.1â);
console.log(âServer running at http://127.0.0.1:1337/â);
This makes use of only one module, the core module http. As you can probably guess, the http module contains all the basic stuff you need to serve a site over HTTP. Node contains a tightly edited collection of core modules that provide things like event handlers, file system access, and abstractions for various network protocols. But just as you probably use a JavaScript library or framework to speed up and bulletproof development on the client side, for Node development beyond a simple "Hello World" you generally add other non-core modules using npm.
The http module does contain a createServer function, though, which is all you need to create a bare-bones web server. In the code above, once the server has been created, it listens to port 1337 on your local machine. When it receives a request, it sends back a text response.
One thing to note is that the work here is done in event handlers, as are most things in Node. The callback in createServer() handles a connection event, which occurs every time a new client contacts the server. To start this server, type node example.js in your terminal, and then open a browser to http://127.0.0.1:1337. This triggers the connection event, and you should see the message in the callback.
To obtain any serious value from a Node serverâeven one not intended to ever go to productionâitâs best to get familiar with the modules in npm. There are thousands available, but those youâd need to create a basic web application are some of the oldest and most stable, so donât feel obligated to research them all before getting started. One that definitely comes in handy for designing an application is Express, an uncomplicated web application framework.
If youâre accustomed to installing open source projects by cloning a GitHub repository or downloading a zip file, youâll probably enjoy npm. To install Express with npm, for example, go to your terminal or command line and type npm install express. As long as youâre online and have permission to write to your machine, this fetches all the code and assets Express needs to run, as well as any modules it has as dependencies. The first time you run npm from your working directory, all these elements will end up in a new node_modules subdirectory. Now the module is ready to be used in Node programs the same way we used http, via the require function.
The ideal use case for designing your application with Node is a single-page application in which the server mostly provides data, but Node is still useful for a more traditional site. Of course, you want to begin development with requirements defined as precisely as possible, but implementation tends to expose requirements you hadnât considered, and some of those can have a considerable impact on your timeline. Even in a server-driven application where it may not be possible to reuse data structures and templates as-is, creating client-only versions helps test your assumptions about the data you need and how youâll use it.
If youâre developing a single-page app, the justification is much easier. Youâll need to think about optimizing your communication with the server to require as few requests as possible, which means knowing how data should be packaged up by each server endpoint and how youâll cache the data on receipt (if at all).
An advantage of having JavaScript on the server is that templates can be rendered by the same template engine on either the client or server side. This allows you to experiment on both sides and optimize for your situation. Itâs also a timesaver to render the templates with JavaScript objects and consider only the way data must eventually be grouped (not how it’s stored in a database). Designing these groupings of data is the bulk of the work we can do with Node toward the end of what we traditionally consider application design.
Piecing together each page from disparate parts from all over the server is messy for an application in any language. Instead, whatever renders a page should have clear dependencies, and the result of each page or data request should combine those dependencies into a cohesive and sensibly organized unit.
If youâve worked in a server-side framework in which a page or view is tied to a single object or model, and where additional data is imported and exposed in a different way, you probably understand how the alternative gets to be a nuisance. Youâre probably also aware that the solution is a good view-model whose data is defined by each view, not the models that feed it. With this exercise, we aim to map out what goes in those view-models.
Thereâs a strong likelihood that your production server does not run JavaScript, so you may end up converting templates you produce in this design phase. You could attempt to mitigate this by choosing a template engine like Mustache with existing parsers for a huge list of languages. Or you might choose one with minimal logic available (I find that the only things I want for a truly flexible template are conditionals, loops, and partials) and the option of changing the delimiters around the template tags to agree with your server template language. Iâd argue that the process of getting all the data correctly placed in your HTML is a lot more difficult than doing a find and replace on the end result, so creating a template in JavaScript that you can use easily is time well spent even if it canât be parsed by your production server.
You could choose to design the UI of your pages using hard-coded mockup data first and add the template tags afterward, or you could start with a template and some mockup data ready to go in your Node server. Even though itâs an extra step, I find the former easier, because the latter tends to require extra shifting of the mockup data. Starting with hard-coded data lets me examine the finished mockup and see what kinds of "objects" are present (e.g., a user, an item for sale, or a status update). That helps me create a flexible object hierarchy in my data more easily. But you may be naturally amazing at creating object hierarchies, so, by all means, do what you feel.
Wherever you begin, hammering out your templates should give you an indication of which parts of each page are dynamic and which data each requires. If subsections of your pages are rendered separately because theyâre reused on different parent pages or because theyâre also rendered by the client, converting your markup to templates also allows you to find the right balance between never repeating code and having absurdly tiny templates.
If youâve created high-fidelity wireframes that run in a browser, you know the annoyance of having only parts of a page be interactive, since every click means having to create a new view (even if you have a series of items that share the same behavior when clicked). You also know about copying and pasting the same data into multiple places, and updating each of them separately if the manner of presenting data should change. Designing your app with a server behind it removes those frustrations.
With the support of a server, itâs not a problem if the same data shows up in different displays all over the workflow youâre designing. Since the data lives on your Node server, you can write it once and reuse it as many ways as you like. You still have to consider how youâll move it from server to client, though. When a user clicks on one of many items in a list, will she be taken to a new page, or will more data appear inline? Is the former the non-JavaScript fallback for the latter? Working that out for your app will tell you which endpoints the server needs, and which parameters need to be sent to it in query strings, form posts, or URLs. Itâll also help define the API for those requests, telling anyone who might work on your production server which keys you expect to correspond to which pieces of data.
Having a server to work with is especially nice if youâre in the business of making asynchronous requests. Obviously, you can get your mockup data, which is excellent, but you can also lazy-load assets like templates or stylesheets to consume that data. Testing the process of getting data and assets to the client validates your assumptions about not only the way youâre packaging them, but how youâre storing and structuring them. And, of course, it means a lot less wasted client-side JavaScript.
The end result of all this should be that youâve moved all the mockup pieces out of your client-side JavaScript and HTML. You have a Node server that might not match your production framework, but does have clear definitions of everything the client side expects to existâpossibly even all viewable in a single file. You have templates and client-side requests that may require substitutions, but also separate your data from everything else and are at minimum easily convertible to whatever format is needed for production.
Could you do the same with any other server under the sun? Absolutely. But if you already know JavaScript and arenât aiming to become a server-side developer, it makes sense to use the skills you already have. Node makes that pretty easy, while also letting you dig as deeply as you want into more complex servers, should your ambitions change. Itâs simple to get going and flexible to extend, making Node an awesome tool for designing applications.
Ready to take your new Node skills for a spin? In “Node at Work: A Walkthrough,” Iâll take you through a live demo, and get specific about how to refine your own mockups.
Google Chrome OS users have long enjoyed the ability to open Microsoft Office documents right in the web browser. Now Google is expanding its MS Office support to include Chrome on Windows and Mac as well.
The new Office Viewer beta is an extension for Google Chrome. You’ll need to be using Chrome 27 or better (currently in the beta channel), but provided you’re willing to use the prerelease version, you can install the new Office Viewer (also a beta release) from the Chrome Store.
The new extension can open most Microsoft Office files including .doc, .docx, .xls, .xlsx, .ppt, .pptx. The interface is very similar to the existing PDF view in Chrome and comes from QuickOffice, which Google acquired last year.
The main downside to the new plugin is that it’s definitely still a beta — very buggy and rough around the edges. In my testing two very simple spreadsheets simply didn’t open and selecting text in .docx Word documents was hit or miss; sometimes it worked, other times it was as if the document had been converted to an image.
On the plus side your MS Office files open in a specialized sandbox which protects you from any malware and viruses lurking in the files.
Still, there are enough rough edges that Chrome’s Office plugin isn’t ready for prime time. While it’s a necessity on Chrome OS, which has no Microsoft Office suite, everywhere else you’re probably better off using Google Drive to view files when you’re online (assuming you want to use Google services, Zoho Docs works well if you don’t), and Microsoft Office or Open/Libre Office when you’re not.
We have a lot of data to parse through at 37signals. Our internal stats application, Dash, does the majority of heavy data lifting for us, including reports, application health, CI builds, and much more. Our Campfire bot named Tally happily pings us when a build fails, deploys are fired off, and when Nagios alerts pop up.
I had a problem though: I needed to have all of this data open constantly to absorb it. Either I had to look at the pages on Dash directly or make sure I’m in the reading through messages in the right Campfire room.
I decided it was time to fix this overload. The release of Status Board let me take a step back and understand what pieces of data really mattered to my daily work. As a programmer, I want to answer a few questions:
My iPad Mini now answers these questions for me. I just set it up next to my laptop and keep it on when working. Instead of swapping tabs over to Reddit or Hacker News to get distracted, I’ve been trying to use my Mini as a focus point instead.
Here’s what my board looks like, and what data it contains:

That’s a lot of data densely packed into one iPad screen! Integrating with Status Board really didn’t take that much effort. For a table, serve up an HTML table. For graph data, wire up some JSON. Need more than that? Drop in an entire HTML page if you need it. There’s guides for hooking up your data included, and I was able to test changes locally using xip.io.
I’ve focused my board to just data I personally need to react to. Exceptions are high? Let’s find out why. The queue looks deep? Pitch in and close a ticket or two. Why is that app’s status red? Dive into the alert and see what’s up.
The best part about it though: I can just open up my iPad and find out the answers to my questions, immediately.
Thanks to Jeremy once again for feedback!
Most corporate customer service departments seem to have been reduced to call scripts of apologies with no power whatsoever to actually address the problems they encounter. That’s the conclusion I’m left with after dealing with three business bureaucracies this year: Comcast, Verizon, and American Airlines.
All train their front line people to glaze the interaction with the plastic empathy that’s supposed to make you feel like they care, even when they demonstrably do not. It’s the customer service equivalent of empty calories, but worse, it’s also infuriating.
There’s simply nothing worse than someone telling you how sorry they are when you can hear they don’t give a damn. Nothing worse than someone telling you that they’re doing all they can, when they’re aren’t lifting a finger.
The emotional chain reaction is completely predictable: At first, you’re comforted that someone appears to care even if the tone is off (humans are remarkable at sussing out insincerity). Then you realize that their only job is to get you off the line, not solve the problem. Then follows the feelings of being powerless and betrayed. And then follows the anger.
That’s a vicious cycle and it must be almost as bad on the other side. Imagine having to field calls from customers every day who you want to help, knowing that the only thing you’re allowed to do is feign that “we apologize for any inconvenience you may have experienced”.
What’s so sad too is how little it would often take to resolve the situations. You bend a policy here, you expedite an order there, you bubble an issue up to a manager. A natural, caring organization designed to create passionate customers stretches and bends. A rigid business bureaucracy looks to nail every T on policies, procedures, and practices—customers be damned.
(This post was brought on by my recent experience in American Airlines earned an enemy)

Tubes so fast they’re blurry. Image: Wetsun/Flickr.
The team behind Nginx (pronounced engine-ex) have released version 1.4, which brings a number of new features, most notably support for the SPDY protocol.
SPDY, the HTTP replacement, promises to speed up website load times by up to 40 percent. Given that Nginx is the second most popular server on the web — powering big name sites like Facebook and WordPress — the new SPDY support should prove a boon for the nascent protocol. Apache, still far and away the most popular server on the web, also has a mod_spdy module.
SPDY support should also help make Nginx more appealing, not that it needs much help. Nginx’s winning combination of lightweight and fast have made it the darling of the web in recent years with everyone from Facebook to Dropbox relying on it in one form or another.
Indeed, part of Nginx’s success lies in its versatility. The server can be used for everything from a traditional high performance web server to a load balancer, a caching engine, a mail proxy or an HTTP streaming server.
It’s worth noting that if you’re installing Nginx 1.4 on a Linux server directly from your distro’s repos the new SPDY support may not be enabled. See the Nginx documentation for instructions on building from source with SPDY support enabled.
SPDY isn’t the only thing new in Nginx 1.4, there’s also support for proxying WebSocket connections and a new Gunzip module that decompresses gzip files for clients that do not support gzip encoded files.
For more details and to grab the latest Nginx source, head on over to the Nginx website.
By showing the shark less, the movie was even scarier, and as Steven Spielberg said in the documentary The Universal Story, âBy the shark not working, it allowed me to be much more experimental and find a way to make the surface of the water, and the threat of the unseen, as powerful as having seen the shark too early. I think the film would have made half the money had the shark worked.â
—Via Tested article Hubcap Spaceships, Giant Spiders, and The Charm of Low Budget Special Effects
Recent versions of Google Chrome on OS X mangle native input buttons. I don’t know precisely when it started but no amount of CSS brute-force seems to correct the text alignment. Have you found a work-around? Do you know a little birdie on the Chrome team?
(Update: Paul Irish kindly responded and filed this bug on the Chromium project.)
Chrome’s experimental Canary channel and Safari’s WebKit nightly builds both now support all of the Photoshop-inspired blend modes for CSS Shaders, part of Adobe’s effort to bring Photoshop-style filter tools to the web.
To see the new blend modes in action, grab a copy of the latest Chrome Canary or WebKit nightly builds, enable the CSS Shaders option in about:flags and point your browser to Adobe’s sample code over on Codepen. Previously, CSS Shaders required a special build of WebKit [Update: As Adobe's Alan Greenblatt points out in the comments, CSS shader support has been in Chrome stable since v25 (you still need to enable the flag). But if you want to play around with these new blend modes then you'll need Canary (or a WebKit nightly).]
The new blend mode support is part of Adobe’s CSS Shaders proposal, which recently became part of the W3C’s CSS Filter Effects specification. There are two types of shaders in the spec, CSS fragment shaders, which provide features similar to what Photoshop’s blending modes offer, and CSS vertex shaders, which handle the 3D animation filters we’ve showcased in the past.
The blending modes currently available include all the familiar options you’ll find in Adobe Photoshop, such as multiply, screen, overlay, luminosity and other photographer favorites.
For more details and links to the corresponding specs, be sure to check out this post from Max Vujovic, who is working on the CSS Filters implementation in WebKit and Blink.
As the CSS Filter Effects specification progresses through the standardization process (and stabilizes), hopefully other browsers will add support as well.
Electronic books are on the rise everywhere. For some this threatens centuries-old traditions; for others it opens up new possibilities in the way we think about information exchange in general, and about books in particular. Hate it or love it: electronic books are with us to stay.
A press release issued by the Pew Research Centerâs Internet & American Life Project in December 2012 describes an upward trend in the consumption of electronic books. The trends are similar in the UK, China, Brazil, Japan, and other countries.
ââŠthe number of Americans over age 16 reading eBooks rose in 2012 from 16 to 23 percent, while those reading printed books fell from 72 percent to 67. âŠthe number of owners of either a tablet computer or e-book reading device such as a Kindle or Nook grew from 18% in late 2011 to 33% in late 2012. âŠin late 2012 19% of Americans ages 16 and older own e-book reading devices such as Kindles and Nooks, compared with 10% who owned such devices at the same time last year.â
What does this mean for web professionals? Electronic books represent a market that’s powered by core web technologies such as HTML, CSS, and SVG. When you use EPUB, one of the primary standards for electronic books, you are creating a packaged website or application. EPUB3 is at the bleeding edge of current web standards: it is based on HTML5, CSS2.1 with some CSS3 modules, SVG, OpenType, and WOFF. EPUB3âs embrace of scripting is sure to encourage the development of more interactivity, which is sought after in education materials and childrenâs books.
Recently W3C has been working more closely with digital publishers to find out what else the Open Web Platform must do to meet that industryâs needs.
One comment weâve heard loud and clear is that people care deeply about centuries-old print traditions. For example, Japanese and Korean users have accepted that many websites display text horizontally, from left to right. While that may be ok for the web, when these users read a novel, they expect traditional layout: characters rendered vertically and from right to left. Japanese readers often find it more tiring to read a long text in any other way. To address these requirements, W3C is looking at the challenges that vertical layout poses for HTML, CSS, and other technologies; see for example CSS Writing Modes Module Level 3.
Requirement of Japanese Text Layout summarizes the typesetting traditions and resulting requirements for Japanese. These traditions should eventually be reproduced on the web as well as in electronic books. In June, W3C will hold a digital publishing workshop in Tokyo on the specific issues surrounding internationalization and electronic books.
We have also heard that the âpageâ paradigmâincluding notions of headers, footnotes, indexes, glossaries, and detailed tables of contentsâis important when people read books of hundreds or thousands of pages. Web technology will need to reintegrate these UI elements smoothly; see for example the CSS Paged Media Module Level 3 (Joe Clark talked about paged media and the production of ebooks in 2010, and Nellie McKesson gave us an update in 2012). In September in Paris, W3C will hold a workshop on the creation of electronic books using web technologies. Note that both this and the Writing Modes Module are still drafts and need further work. That means now is the right time for the digital publishing community to have its voice heard!
In the realm of metadata, important to publishers, librarians, and archivists, the challenge is to agree on vocabulary (and there are many: Harvard’s reference to metadata standards is only the tip of the iceberg). Pearson Publishing recently launched the Open Linked Education Community Group to examine creating a curated subset of Wikipedia data that can be used for tagging educational content.
Here are a few other places to look for activity and convergence:
Although publishing has some specific requirements not common to the web generally, I think that the distinction between a website (or app) and an ebook will disappear with time. As I have written before, both will demand high-quality typography and layout, interactivity, linking, multimedia, offline access, annotations, metadata, and so on. Digital publishersâ interest in the Open Web Platform is a natural progression of their embrace of the early web.
The first Firefox OS-powered mobile devices, manufactured by the Spanish company Geeksphone, went on sale today. Unfortunately for anyone hoping to get their hands on some hardware explicitly designed for Firefox OS, the phones have apparently already sold out.
For the average user that’s probably a good thing. Despite being a 1.0 release on real hardware these phones are not, according to Mozilla, ready for prime time.
Instead these devices are intended for developers looking to build and test applications for Firefox OS. And clearly there’s a lot of interested developers. That’s not terribly surprising given that apps for Firefox OS are built using web basics, like HTML, CSS and JavaScript, which means anyone who can build a website can build a Firefox OS app.
Indeed, thanks to the Firefox OS simulator there are already quite a few Firefox OS apps available. But while the simulator is helpful, it’s just not the same as testing on an actual device. Having actual hardware allows developers to “test the capabilities of Firefox OS in a real environment with a mobile network and true hardware characteristics like the accelerometer and camera,” writes Stormy Peters, Mozilla’s Director of Developer Engagement.
While Geeksphone may be the first company to produce an actual Firefox OS phone (albeit a “developer preview”), Mozilla has some more familiar hardware makers lined up to produce consumer devices, including Sony, LG and Alcatel, all of which have signed up to turn out Firefox OS mobile phones.
There’s still no official word on when these manufacturers will be joining the Firefox OS party, but Mozilla’s plan is to have a more polished version of its OS out in the next few months, with official releases in Brazil, Venezuela, Portugal, Spain and Poland over the next several months.
One of the Geeksphone devices is on its way to the Webmonkey lair, so we’ll give you the lowdown on what it’s like to develop for Firefox OS as soon as we get a chance to play with it. In the mean time, if you missed out on the Geeksphone today the company is hoping to have more available for sale later this week. Alternately, you can always install Firefox OS on your own device or just use the Firefox OS simulator.

IE voodoo doll by Cheryl Brind/Flickr.
Created to simplify the process of writing JavaScript and manipulating HTML, jQuery began life a mere seven years ago, but quickly found favor with developers sick of dealing with cross-browser JavaScript hassles. According to one survey published last year, jQuery turns up on roughly half of all sites on the web.
Will dropping support for older versions of IE change that? Probably not. If your site needs to maintain support for IE 8 and below (or even IE 9 and 10 running in compatibility mode) you’ll just need to stick with jQuery 1.9 or below.
“jQuery 2.0 is intended for the modern web,” writes jQuery’s Dave Methvin on the Query Foundation website. “We’ve got jQuery 1.x to handle older browsers and fully expect to support it for several more years.”
If you want the best of both worlds you can use a conditional comment to serve 2.0 to newer browsers and 1.9 to older ones, but the far easier way to go is sticking with jQuery 1.x. For now at least the primary use case for the 2.0 line is situations where IE support isn’t a consideration — think Chrome or Firefox add-ons, PhoneGap apps or node.js.
In this 60-minute video from An Event Apart Boston, Scott Berkun tackles designer disempowerment. He discusses how power actually works, and why developing salesmanship skills is a must, even if your job isn’t public-facing.
Last month, a U.S. District Court handed down a decision thatâs pretty awful if you care about consumer rights and digital content.
It all started in 2011, when a company called ReDigi launched a service to let folks resell their unwanted iTunes purchasesâthe digital equivalent of unloading your old vinyl at a swap meet. This annoyed the legal department at Capitol Records enough that they sued ReDigi in federal court to stop it. Unfortunately for consumers, Capitol Records succeeded. This isnât just bad news for ReDigi though. Whatâs really troubling is the courtâs take on current copyright protections.
When it comes to the CDs, DVDs, and paper books you own, U.S. law is clear. A legal concept called the first-sale doctrine establishes your right to sell them to another person, provided you’re handing over the item you originally bought, and that you didnât make any copies. That’s the idea behind garage sales, swap meets, and Craigslist. As repeated by the courtâs own decision in the ReDigi case, first-sale doctrine states:
âThe owner of a particular copy or phonorecord lawfully made…, or any person authorized by such owner, is entitled, without the authority of the copyright owner, to sell or otherwise dispose of the possession of that copy or phonorecord.â
That âownerâ is you. The âcopyright ownerâ is the record label, movie studio, or publisher. They make it. You buy it. You can sell it to somebody else if you donât want it anymore. Simple. But according to this court, you donât have that right if you send that movie, song, or book over an electronic network when you resell it.
Wait a minute. Howâd that happen?
In the district courtâs view, any transfer that takes place via the internet creates a reproduction of the work on the receiving machine, a new physical object that is âembodiedâ on the buyerâs hard drive. And that constitutes an illegal copy. In the judgeâs own words:
[W]hen a user downloads a digital music file or âdigital sequenceâ to his âhard disk,â the file is âreproduce[d]â on a new phonorecord within the meaning of the Copyright Act. Id.
This understanding is, of course, confirmed by the laws of physics. It is simply impossible that the same âmaterial objectâ can be transferred over the Internet. Thus, logically,… the Internet transfer of a file results in a material object being âcreated elsewhere at its finish.â
Yeah, you read that right. According to this decision, electronic transfers generate a new âmaterial objectâ on the receiving device. In legal terms, thatâs a copy, and a violation of copyright law.
Even when products like ReDigiâs take reasonable measures to remove the file from the sellerâs hard drive as itâs transferred, the court says it doesnât count. Because I canât physically hand you the original item over an electronic network, they say all bets are off.
This creates a world where weâre barred from ever transferring digital goods we own to another person if we use an electronic network. Insert internet, lose first-sale rights. The jury is still out on whether this interpretation really works from a legal standpoint. The scope of court decisions on copyright are typically papercut-narrow and excruciatingly literal. But the U.S. District Court for the Southern District of New York isnât really the one causing all the trouble here. The main culprit is the law itself.
The copyright law at play in Capitol Records v ReDigi predates the digital world by decades, and still talks about usage rights strictly in terms of âmaterial objects.â It doesnât recognize a difference between photocopying a printed book and reconstructing one from a set of bit-flipping instructions. The letter of the law hasnât caught up with the reality we live in. Right now itâs Zoolander smashing a tangerine iMac, hoping a bunch of paper files spill out.
That might not seem like a big deal now. But outdated laws arenât just discordant with the times, theyâre minefields filled with unintended consequences. Just think about your web browser. Anyone want to chat with the district court about the âmaterial objectsâ a typical browser cache leaves on your hard drive? Unless you feel like upending some of the basic mechanics of the internet, Iâd rather you didn’t.
And what happens as we shift to a future where the majority of our access to content is digital? Will we see the shuttering of all secondary resale markets? Who gains and who loses from that? If I canât transfer the digital goods I own over the network, what happens when I die? Will my executor have to ship my hard drive to my next of kin because she couldnât transmit its contents to them without risking legal action?
So far weâve largely ducked these questions by letting content companies push us toward rental/lease models online, where we constantly pay and repay for content without enjoying full rights of ownership. Thatâs okay for some things. But by ignoring the bigger picture on ownership, we leave ourselves open to even further reductions in the consumer rights weâve enjoyed for decades on movies, music, and books. We need to avoid a world where the only right we have left is the right of refusal.
Fixing the language of creaky old laws takes legislators, not courts. But we can do better than just petition Congress to drag copyright into the current century. We can set the standard ourselves. As entrepreneurs, developers, and technologists building products around digital content, we can incorporate progressive terms into our services. We can choose to grant users better rights than current law permits by default. We donât have to sit around waiting for the next ReDigi case to tell us how to treat our customers. We can, and should, do better than that.
The first-sale doctrine needs to be defended in the digital space. We need acceptable, liveable standards for ownership of digital goods, and we can start building them now.
Tools
|
|
|
|
|
|
|
|
|
|
More »
| Home | Create a Website | About Us | Premium | Browse | News | Store | Contact Us | Terms of Service | Privacy Policy | ||
![]() |
© 2006-2013 DynamicDevelop LLC
|
|

