Last week we launched a new feature for Backpack that allows people to comment on the to-do items and notes on their Backpack pages. We had actually built this feature a few months earlier for Basecamp. Since we had already built commentable to-do items for Basecamp, we could have just retraced our steps and built a look-a-like feature in Backpack. However there were a couple bumps in the experience that we didn’t want to carry over. We took the Backpack implementation as a chance to reconsider those bumps in the earlier Basecamp version so that both apps can be better in the end. Along the way we found a really nice method for positioning our comment icons relative to the flowing text of a to-do item.
Here’s how the feature works in Basecamp. When you hover your mouse over a to-do item, a comment icon appears on the right side of the to-do text:
We implemented this by rendering the comment icon after the text of the to-do item as an inline element. The to-do text and the icon are rendered within the same containing block like this:
<div> This is the text of the to-do. <img src="comment_icon.png" style="display: none;" /> </div>
(Of course this code is simplified to focus on the positioning. You would also find code to show and hide the comment icon when the user mouses over or out of the to-do item.)
This approach works fine when there is space after the to-do text to render the icon. The problem arises when the text of the to-do is so long that it reaches the edge of the container and it is almost about to wrap. When the user hovers over the to-do, the inline comment icon becomes visible, wraps below the text of the to-do, and forces any to-do items below the hovered to-do to move down the page:
This wrapping and unwrapping happens as your mouse runs up and down the page. To-do items shift from under you, and it just feels sloppy. This is something we didn’t want to duplicate on our Backpack implementation. So we took a different approach to the positioning.
The Backpack feature works the same way at first glance. The comment appears after the text of the to-do item when you hover over the to-do item:
What’s different is the implementation. Instead of rendering the comment icon inline after the to-do text, we realized we could position the icon absolutely. The trick with absolute positioning is that you need a reference point. Elements with ‘position: absolute’ take a ‘top’ or ‘bottom’ property and a ‘left’ or ‘right’ property. The question is: position at the top of what? Position to the right or left of what? The “what” is your reference element. Absolutely positioned elements look to their nearest parent with ‘position: relative’ for reference*, and that parent can be an inline element or a block element. Combine these facts together, and you’ve got everything you need for a better implementation:
<div> <span style="position: relative;"> This is the text of the to-do. <img src="comment_icon.png" style="position: absolute; right: 0px; bottom: 0px;" /> </span> </div>
This markup positions the comment icon absolutely to the bottom right corner of the to-do text. More specifically, it positions the icon relative to the containing ‘span’ element. That span ends at the very last character of the to-do text because it’s an inline element, not a block element. Recall that inline elements don’t have a width. They shrink-wrap themselves to whatever it is that they contain. So the span shrink-wraps the to-do text, and the icon is positioned relative to the bottom-most and right-most point of the shrink-wrap.
We tweaked the pixel values for the ‘right’ and ‘bottom’ properties so the icon is aligned nicely at the correct distance from the edge of the text. Here’s the result. Hovering over an item displays the comment icon like before, but now the icon never affects the wrapping because it’s positioned absolutely:
The end result is that the page never jumps, shifts or re-wraps when you run your mouse over it. The page feels solid and stable. That’s something I always aim for. UI elements should feel like furniture. They should stay where they are and remain fixed and solid unless the user specifically picks them up and operates on them.
Our approach to positioning these icons in Backpack represents one small divergence from the Basecamp implementation. Still, small changes can have big effects when it comes to interface design. We’ll be copying the approach back into Basecamp so our customers on both apps can benefit from the polished experience. I hope this little trick is useful to you as well.
* Nit pickers: Technically, absolutely positioned elements look for the nearest parent with a position other than ‘static’ for their reference point.