Future of Web Apps Miami - Conference 22-24 February 2010

News Flash

A/Bingo, an open source Rails A/B testing framework: http://bingocardcreator.com/abingo

Tagged: Dev

4 December 2008

At The Future of Web Design in New York, the final session of the day was a panel discussion on the frictions and misunderstandings that often arise between designers and developers working together. The panel was chaired by Liz Danzico, while putting across the the developers’ point of view we had Joe Stump and Chris Lea, while on the design side of things we had Ryan Sims, and Daniel Burka.

The audience provided lots of great questions to ask the panel, but, unfortunately, there wasn’t enough time to answer them all (I have a stack of about 60 here on my desk). I thought I’d publish a collection of ten of the best unasked questions and see if the Vitamin audience, which is comprised of both designers and developers, can’t come up with some answers.

Here is the list of questions:

  1. Would I be a better designer to work with if I knew coding myself? Do developers appreciate knowledgeable designers?
  2. Designers: Developers don’t like you because you represent Work and don’t see why said work is wholly necessary. Developers: Designers are scared of you because you are the gatekeeper. This is the dynamic. Discuss.
  3. How can stronger communication be developed not only between designers and developers, but also between designers, developers, and creative teams (art director, copywriter)? How can a team bring them into the fold more effectively?
  4. To developers: if there was one thing ― an ability, a bit of knowledge, an understanding ― that you could instill in all designers with the wave of a magic wand, what would it be?
  5. How do you keep the goal of the project front and center so that design and development can keep a “common good” as their primary function?
  6. What’s the most helpful thing a designer can do before handing over design files?
  7. How soon should a developer be engaged to sense-check a design? At design brief? Before it goes to the client?
  8. Is it a mistake to make the lead developer the project manager?
  9. How can I get the developer to give me an absolute answer on whether something is doable?
  10. It seems that designers are under pressure to design an exceptional and unique experience and developers are under presssure to produce sites with high performance and little/no errors. Designer’s goals add pressure to developers and vice versa. How can our goals work together intead of causing pressure on each other?

Please provide your thoughts in the comments: it would be great to get comments from both designers and developers (no trolling, please!)

Continue reading 15
FOWA Miami banner ad

19 November 2008

Today, a talented web designer must be a modern-day MacGyver—that 80s TV action hero who could turn a rubber band and three tin cans into a serviceable aircraft. Turning the average site design mockup into a living, breathing slice of HTML and CSS is a comparably delicate miracle, which must be accomplished using whatever makeshift tools happen to be lying around in current browsers.

That’s exactly why so many professional designers still choose to use HTML tables for layout. How can we expect beginners to adopt CSS for layout when it takes someone with the resourcefulness (and snappy dress sense) of MacGyver to fully understand the techniques involved?

Thanks to the imminent release of Internet Explorer 8, CSS layout is about to become something anyone can learn to do—no chewing gum or makeshift explosives required.

HTML Tables Are a 90% Solution

HTML tables produce the grid-based layouts we want to achieve with relative ease, but the price is that users with screen readers and other technologies that rely on semantic markup have a hard time making sense of the page.

As standards-conscious designers, we have convinced ourselves that the benefits of semantically meaningful markup are worth the added hassle of using CSS for layout. Not everyone shares this conviction. Whenever I write about some new CSS layout technique, at least half the feedback I get boils down to “You’re kidding yourself if you think designers will use that instead of HTML tables.”

The reason this is such a contentious issue is that tables correspond so well to the way designers tend to think of pages: a semi-flexible grid that defines rectangular areas that make up the page. If you want three columns in a row, you just put three table cell tags inside a table row tag:

<table> <tbody> <tr> <td>column 1</td> <td>column 2</td> <td>column 3</td> </tr> </tbody>
</table>

The premise of using CSS for layout is sound: replace the HTML tables with semantically meaningful markup, plus semantically invisible div’s where needed:

<div id="container"> <div> <div id="menu">column 1</div> <div id="content">column 2</div> <div id="sidebar">column 3</div> </div>
</div>

The problem is the CSS code required to lay out this new markup. CSS was not initially designed to support blocks arranged horizontally across the page; consequently, we have had to get creative with the tools at our disposal. Current best practice requires the designer to master subtle interactions like overlapping floats, negative margins, and other black magic to achieve a simple multi-column layout. You don’t so much describe the layout you want as gradually build up a combination of positioning constraints that almost miraculously result in the layout you’re after. You couldn’t come up with a more convoluted way of expressing page layout if you tried!

If CSS layout code were as easy to write as HTML tables, making the leap would be a no-brainer; designers would flock to CSS willingly. Instead, we must drag them kicking and screaming, because the tools that CSS provides are not suited to the layout tasks we want to accomplish.

What if CSS provided a set of tools that applied to practical layout tasks as obviously as HTML tables do?

Bring the Tables to CSS

CSS actually includes a feature that works just like HTML tables: CSS tables. Using the CSS display property, you can instruct the browser to format any HTML element as if it were a table. For visual display purposes the element behaves like a table, but the element retains its non-table semantics for screen readers and other tools that look at the HTML markup.

In short, CSS tables let you perform table-based layout without misusing HTML tables!

The CSS to lay out our collection of div’s above as a row of three table cells is very straightforward:
#container { display: table; border-collapse: collapse; table-layout: fixed;
}
#container > div { display: table-row;
}
#container > div > div { display: table-cell;
}

We can then set the widths of each of our columns, again with very straightforward code:

#menu { width: 200px;
}
#content { width: 66%;
}
#sidebar { width: 33%;
}

From this foundation, applying borders and backgrounds to these columns is trivial. Check out this sample page, and the screenshot below for a fully-rendered example. Now this is the kind of page layout code that designers can embrace with confidence!

a simple page design featuring a three-column layout

Compared with HTML tables, CSS tables have only one notable weakness: CSS does not allow for table cells to span rows or columns the way they can in HTML tables (with the “rowspan” and “colspan” attributes). As it turns out, however, this is a relatively uncommon requirement for page layouts; and in the few cases where spans are required, there are ways to fake them with CSS tables.

Can You Start Now?

So, why isn’t everyone already using CSS tables for page layout? In an all-too-familiar twist, we have Internet Explorer to blame. CSS tables are supported in every major browser except Internet Explorer. However, the good news is that Internet Explorer 8 will have full support for CSS tables upon its release, setting the stage for CSS tables to become the preferred tool for page layout on the web!

The question you must ask yourself is, “When can I start making the switch?” The answer may depend on the type of site you work on.

If you work professionally on a mainstream website, chances are you will be expected to keep your site working on Internet Explorer 6 and 7 for some time to come. Since neither of these browsers support CSS tables, it may seem on the surface that you’re out of luck. In fact, CSS tables may still make your job easier.

Because CSS tables are so much easier to work with than previous CSS layout techniques, you may find it worthwhile to implement your design first using CSS tables, and then using older CSS techniques for IE6 and IE7. You can use conditional comments to insert your IE6/IE7 style sheet, while all other browsers will only get the table-based layout. This approach does mean you have to implement your layout twice, but it saves you the considerable headache of getting the older techniques from working both in Internet Explorer and in other browsers.

While you’re at it, you may find opportunities to simplify the layout slightly in the IE6/IE7 version of the site, and save yourself a lot of work. Something like not insisting that a column’s background color extend all the way to the bottom of the page can radically simplify the code, for example.

If you work on a site with a more technical audience, or owned by a more progressively-minded organization, you might have even more wiggle room. In this case, you should explore the possibility of providing a simplified page layout for IE6 and IE7.

A simplified, two-column layout is visible in the IE6 window.

If you find yourself having to defend this approach to a client, tell them how much of your time (and their money) will be saved by simplifying the layout a little in outdated browsers.

Even if you can’t justify working with CSS tables in your day job just yet, it’s worth finding excuses to use them where you can. When Internet Explorer 5.5 made CSS layout across browsers possible for the first time, Jeffrey Zeldman wrote To Hell With Bad Browsers, leading the call for designers to adopt CSS layout:

“For years, the goal of a Web that was accessible to all looked more like an opium dream than reality. Then, in the year 2000, Microsoft, Netscape, and Opera began delivering the goods. At last we can repay their efforts by using these standards in our sites. We encourage others to do the same.”

The response to this call to action was gradual, but effective. Initially, web designers began experimenting with CSS layout on their personal sites, before testing the waters with some of their riskier side projects. Major mainstream sites like ESPN began making the switch only a couple of years later.

With Internet Explorer 8 on the verge of release, the stage is set for another wave of change to sweep the Web, however gradually. Now is the time to ensure you’re on the leading edge, not paddling to catch up!

Everything You Know About CSS Is Wrong

Perhaps the most important benefit of CSS tables is that it finally makes page layout with CSS easy to learn. Finally, we can justifiably expect anyone designing a web site today to do it the right way, with a proper separation of content (HTML) and presentation (CSS).

In my just-released book, Everything You Know About CSS Is Wrong (available from Amazon: Everything You Know About CSS is Wrong!), Rachel Andrew of The Web Standards Project and I explore the realities of page layout with CSS tables, the new possibilities they open up, and how to work around limitations like the lack of row and column spans. A brisk read, it provides a valuable glimpse into the next evolution in CSS layout on the web.

Continue reading 16

13 November 2008

Undo and redo are two of the most essential features in any real rich application experience. In many cases, your user has already turned these commands into reflexes, automatically hitting the proper keys and expecting the right thing to happen. Unfortunately, this is often left unimplemented by developers when making the transition from the desktop to the web, serving as a rude awakening to your users when they make a mistake that can’t be undone. It makes sense that this doesn’t receive the attention it deserves since the actual functionality of your application should obviously come first, and it doesn’t help that implementing these features from scratch can be quite difficult. However, they add a necessary amount of polish that you should seriously consider adding to your web application.

Luckily for us, Cappuccino has built-in support that can allow you to plug undo and redo right in by just by adding a few lines of code. In this tutorial, we will be exploring how to add sophisticated undo and redo support to a graphical application in the browser. We won’t be creating the entire application from scratch however, but instead building off of an existing example. We’re doing this for two reasons. For starters, we don’t want to get distracted from our main task by having to wade through unrelated code. Instead we’ll simply review whatever code we need to as we get to it. More importantly, the sample provided is complex enough to serve as a true real-world example, as opposed to the contrived code we’d be forced to put together in the limited scope of space and time of this tutorial. This also has the benefit of displaying the modular nature of undo support in Cappuccino, and how we can add it to an application without knowing every detail of its implementation.

That being said, you can, of course, feel free to review the entire source of the application as well. The application itself is written entirely using Cappuccino, but you don’t really need any prior knowledge of Cappuccino to follow along with this tutorial. Feel free to review Cappuccino and Objective-J at cappuccino.org before you dig in, but it’s not a requirement to follow along.

Let’s start by taking a look at the application we’ll be modifying. You can see it and play with it live here. You’ll need to download the source in order to follow along with the changes in this tutorial. As you’ve probably noticed, it’s a simple floor planning app that lets you drag and drop and arrange furniture into the layout of a small apartment:

screenshot of floor planning application, showing furniture on left and floorplan on right

Have a play with the app. As you can see, it supports three actions that we’ll want the user to be able to undo:

actions the user should be able to undo: Drag-and-drop addition, drag-and-drop positioning, and rotation

  • drag-and-drop to add furniture: should remove the furniture when hitting undo, and add back in when hitting redo
  • drag-and-drop to a new location: should revert to previous location when hitting undo
  • rotate: should revert to previous rotation when hitting undo

Now, the main thing you should know before we dig into the code is we’ll be dealing with two classes, FloorPlanView, which represents the background and layout of the apartment:

screenshot of application with layout highlighted

The other is FurnitureView, which displays each individual piece of furniture in the apartment:

screenshot of application with furniture highlighted

The first action we’re going to tackle is undoing the movement of furniture pieces. All the code to handle moving furniture views is currently contained in two methods in FurnitureView.j: mouseDown: and mouseDragged:. Let’s review their current implementations:

- (void)mouseDown:(CPEvent)anEvent
{ dragLocation = [anEvent locationInWindow]; [[EditorView sharedEditorViewsetFurnitureView:self];
} - (void)mouseDragged:(CPEvent)anEvent
{ var location = [anEvent locationInWindow], origin = [self frame].origin;
[self setFrameOrigin:CGPointMake(origin.x + location.x - dragLocation.x,
origin.y + location.y - dragLocation.y)]; dragLocation = location;
}

mouseDown: simply stores the mouse down position, and additionally sets the furniture view as selected through the EditorView, which we won’t need to concern ourselves with. mouseDragged: then proceeds to update the origin of the view on every drag event. Despite being where the actual changes take place, we don’t want to register our undo action in mouseDragged: because if we do we’ll be registering an undo action for every pixel the user drags! So instead, we’ll want to add a new method right below it called mouseUp:. The mouseUp: method gets called when the user lifts the mouse and is thus done dragging:

- (void)mouseUp:(CPEvent)anEvent
{
// Register undo here.
}

Now, before we continue we’ll want to create one additional new method, setEditedOrigin:. The reason for this is that we want a way to change the furniture locations that notifies the undo architecture, and a way that doesn’t. Currently we’ve fullfilled one of these requirements: setFrameOrigin: can be used to change the position of a FurnitureView without registering any undos, so let’s now create an analog that will:

- (void)setEditedOrigin:(CGPoint)aPoint
{ if (CGPointEqualToPoint(editedOrigin, aPoint)) return; [[[self window]
undoManager] registerUndoWithTarget:self selector:@selector(setEditedOrigin:)
object:editedOrigin]; editedOrigin = aPoint; [self setFrameOrigin:aPoint];
}

This method is relatively straightforward and shows us how to talk to Cappuccino’s undo support. We create a new instance variable called editedOrigin which keeps track of the last “undoable” position. This way we can ignore all the origin changes that take place during while a drag is mid-flight. When the user passes in a new position, we compare it to editedOrigin to make sure they’re not the same. We do this in order to prevent undos being placed in the stack that have no percievable difference to our user (making it appear that the undo “didn’t register”). After this we do the most important step, which is tell our undo manager that it should register an undo. Every view has a window, and every window has its own undo manager (that way, different windows can have different undo stacks). So we grab our undo manager from our window. We then call registerUndoWithTarget:selector:object:. This method tells the undo manager what to do when the user hits undo. In this case, we want to just call this very same method, but with the old origin, editedOrigin. We then set editedOrigin to the current position, and of course update our actual origin, and we’re done. We do need a bit of book-keeping however; namely we need to declare this new instance variable in the class definition:

@implementation FurnitureView : CPView
{ CPString name; CPImage image; float rotationRadians; CGPoint dragLocation;
CGPoint editedOrigin;
}

as well as set its initial value in mouseDown::

- (void)mouseDown:(CPEvent)anEvent
{ editedOrigin = [self frame].origin; dragLocation = [anEvent locationInWindow];
[[EditorView sharedEditorView] setFurnitureView:self];
}

You may be wondering why we need this new instance variable at all, since we can just query our frame for our current origin. The reason is because when we only want to “remember” origins that are to be undone. If you hit refresh in your browser, you should be able to undo moving a furniture item by hitting command-z on a Mac and ctrl-z on a PC. You’ll also notice that you are capable of redoing these actions as well. That’s because setEditedOrigin: gets called for the undo action as well, thus registering another undo on the stack, which Cappuccino is smart enough to know should actually be a redo.

We can now move on to undoing the rotations which are slightly more complex. As we saw earlier, the goal is always to register an undo once editing is complete. You’ll notice that there are two empty methods in FurnitureView.j, willBeginLiveRotation and didEndLiveRotation, which the editing system is kind enough to send to us when the user begins and ends rotating, respectively:

- (void)willBeginLiveRotation
{
} - (void)didEndLiveRotation
{
}

Clearly we’ll want to add our actual undo action in didEndLiveRotation, but just as before we’re going to created an “Edited” version of setRotationRadians: for rotation actions that we want to register with the undo system:

- (void)setEditedRotationRadians:(float)radians
{ if (editedRotationRadians == radians) return; [[[self window] undoManager]
registerUndoWithTarget:self selector:@selector(setEditedRotationRadians:)
object:editedRotationRadians]; [self setRotationRadians:radians];
editedRotationRadians = radians;
}

This should look very familiar. It’s almost identical to our previous implementation, except we are dealing with radians instead of positions. Let’s not forget to add our new editedRotationRadians to the other necessary places, namely the class declaration:

@implementation FurnitureView : CPView
{ CPString name; CPImage image; float rotationRadians; float editedRotationRadians;
CGPoint dragLocation; CGPoint editedOrigin;
}

and willBeginLiveRotation, which is analogous to our mouseDown: since it’s what kick starts the rotation process:

- (void)willBeginLiveRotation
{ editedRotationRadians = rotationRadians;
}

Now all that’s left to do is to actually call setEditedRotationRadians when the user finishes rotating a furniture piece:

- (void)didEndLiveRotation
{ [self setEditedRotationRadians:rotationRadians];
}

Once again, if you refresh you should be able to undo and redo rotating furniture items, as well as being able to undo their positioning.

We are now done with editing the FurnitureView class, and we can move on to the last action that the user should be able to undo: actually adding furniture to the apartment layout. To do this, we’ll have to move to FloorPlanView.j, where the FloorPlanView class is contained. The two methods we are primarily concerned with are addFurnitureView: and removeFurnitureView:, which do just that:

- (void)addFurnitureView:(FurnitureView)aFurnitureView
{ [self addSubview:aFurnitureView]; [[EditorView sharedEditorView]
setFurnitureView:aFurnitureView];
} - (void)removeFurnitureView:(FurnitureView)aFurnitureView
{ var editorView = [EditorView sharedEditorView]; if ([editorView furnitureView]
== aFurnitureView) [editorView setFurnitureView:nil]; [aFurnitureView removeFromSuperview];
}

As you can see there’s quite a bit going on here, but again most of it is not of our concern. In fact, in this case, none of it is. This comes from one simple realization: these methods are opposites of each other, and thus undo each other. So to undo addFurnitureView:, we need to removeFurnitureView:, and vice versa, so the code is actually quite simple:

- (void)addFurnitureView:(FurnitureView)aFurnitureView
{ [[[self window] undoManager] registerUndoWithTarget:self
selector:@selector(removeFurnitureView:) object:aFurnitureView];
[self addSubview:aFurnitureView]; [[EditorView sharedEditorView]
setFurnitureView:aFurnitureView];
}
- (void)removeFurnitureView:(FurnitureView)aFurnitureView
{ [[[self window] undoManager] registerUndoWithTarget:self
selector:@selector(addFurnitureView:) object:aFurnitureView];
var editorView = [EditorView sharedEditorView]; if ([editorView
furnitureView] == aFurnitureView) [editorView setFurnitureView:nil];
[aFurnitureView removeFromSuperview];
}

And there it is, it’s that easy. All we had to do is register the opposite action in each method, and both of them are undable (and redoable) now.

Make undo and redo discoverable

Something interesting that I’ve noticed with undo and redo in our own applications is that many times people don’t realize they have this feature. When we first launched 280 Slides we got a number of “feature requests” asking for undo and redo support. They were thrilled when we told them they could just use the key commands they were used to, but apparently this was not discoverable enough. Because of this, we decided to add actual undo and redo buttons to make these actions more explicit. Let’s go ahead and do the same here by adding the following snippet of code to the end of the applicationDidFinishLaunching: method in AppController.j:

var undoButton = [[CPButton alloc] initWithFrame:CGRectMake(20.0, 400.0, 60.0, 18.0)],
redoButton = [[CPButton alloc] initWithFrame:CGRectMake(90.0, 400.0, 60.0, 18.0)];
[undoButton setTitle:“Undo”];
[undoButton setTarget:[theWindow undoManager]];
[undoButton setAction:@selector(undo)]; [redoButton setTitle:“Redo”];
[redoButton setTarget:[theWindow undoManager]];
[redoButton setAction:@selector(redo)]; [view addSubview:undoButton];
[view addSubview:redoButton];

Now if our users have “unlearned” expecting undo and redo to work, they’ll be able to idenitfy these buttons. With that, we’ve now made all the current actions in this application undoable and provided an easy way for our users to use this feature. As we continue to add new features to this application we can also incrementally add their associated undos. As we’ve seen here, it’s often a matter of just adding one or two lines of code per method, so it’s good to start early and not wait until the very end to begin incorporating this functionality. I hope you’ve enjoyed this tutorial and make sure to leave any questions you may have in the comments! The completed source with all the above additions is available here and you can give it a spin here.

Francisco will be speaking at The Future of Web Apps Miami

Continue reading 9

Subscribe to our Newsletter

Sign up to the Think Vitamin Newsletter to get updates on web design, web development and web entrepreneurship as well as special offers and discounts from Carsonified. Rest assured we never share your email address.

Subscribe to the Think Vitamin articles RSS feed

News

Twitter

Follow us on Twitter

Subscribe

Article Subscribers

Feedburner blog subscriber indicator

News Subscribers

Feedburner blog subscriber indicator

Subscribe by Email

You can receive Think Vitamin updates via email. Just pop your email address in the box below and click the arrows.

Subscribe by RSS

You can also receive new Think Vitamin posts via your RSS feed reader

Subscribe RSS

Ads Via The Deck