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.
Jean Moniatte
on 22 Jan 09Nicely done!
Just a quick CSS note: there is no need to specify a unit when the value is 0. For example, “right:0px;” looks better as “right:0;” – I think.
Chris Doyle
on 22 Jan 09Another benefit of absolute positioning is cross-browser stability. At Smartsheet, we position:absolute almost every node in our app and as a result spend very little time worrying about how to make it work in IE or Safari.
Anatoli Papirovski
on 22 Jan 09This reminds me of sites that bold links upon :hover, thus making the whole text shift with it to accommodate for the bigger size.
It’s great to see that you guys are paying attention even to the smallest details.
In regards to Jean, I believe that the only reason there is 0px there is for demonstration purposes, as in the real app they would’ve had to set the right value to negative and the bottom one to positive to get the icon balanced on baseline.
Steven
on 22 Jan 09Bring the speed to backpack that basecamp and highrise enjoy.
Backpack is annoyingly slow in comparison to the other two apps on the same computer, same connection etc.
Is this being addressed?
Noel Hurtley
on 22 Jan 09Thanks for the tip!
Evgeny
on 22 Jan 09But why position it bottom:0 instead of top:0 ? What if the text does wrap, but the second line is just one short word in length…. then the comment icon will be at the very end of the “almost empty” second line. no?
RS
on 22 Jan 09Right, and that’s what we want. We want the icon to display after the last word of the text, wherever it appears.
Matt Hooks
on 22 Jan 09I was just wondering when you were going to fix this! I ran into it again today.
Vasily
on 22 Jan 09Great information bit, thanks for sharing. As a matter of fact I am going to try it in the UI I am working on right now.
Vasily
on 22 Jan 09Came in really handy, I am enjoying the results, sure the users of my interface will as well.
Thanks again.
Josh B.
on 22 Jan 09RS: Following on your response to Evgeny—I am picturing the absolutely positioned image positioning itself relative to the box of the relatively positioned parent, rather than displaying inline with the ragged last line of text… is my mental css parser on the fritz again?
Ben
on 22 Jan 09Hmm, I had been expecting this markup to make the icon follow the last word, even if it wraps, since it’s a span rather than a div. In Safari (3.2.1), it does.
However, in Firefox 3.0.5 and 3.1b2, in both quirks mode and standards compliance mode, this code results in the icon following the last word of the first line... when the text wraps, the icon doesn’t move down.
It could be that there is some other bit of unspecified CSS that would make it follow the last word of the paragraph even in Firefox, but actually for this situation (the comment icon), staying adjacent to the first line of text seems like a good spot anyway.
(Disclaimer: I haven’t checked Backpack to see how 37s’s live version renders in FF. Like I said, maybe there’s a further CSS trick that isn’t documented here.)
Mike Rundle
on 22 Jan 09FYI, back in September 2003 Doug Bowman wrote about this technique and how he used it on the Adaptive Path website. Many people (including myself) hadn’t heard about it before then so I like to think that Doug was one of the first to popularize the absolute-within-relative technique.
I can’t remember what I had for dinner 2 nights ago but I can remember a CSS tutorial written 5+ years ago. Go figure.
RS
on 22 Jan 09Josh and Ben,
Yes FF interprets the CSS differently. In my opinion Safari is doing the right thing by interpreting bottom to be the bottom of the last wrapped segment of the inline element. FF ignores the wrapping and places the comment icon to the bottom right of the first line before the wrap point.
Mike: Yeah thanks for finding that. That’s where I first learned the technique too.
Ionut Popa
on 22 Jan 09What about adding a right padding for the span so the icon doesn’t break out of the container?
Yari McGauley
on 22 Jan 09For the sake of simplicity, keeping the HTML nice and lean, you could use the CSS ‘span:hover’ class to display the icon in the same position as a background image (and add 10px padding-right to the span).
This way the icon only needs to be loaded once, in the CSS, and keeps it out of the HTML, saving quite a bit of code.
Problem is, the icon needs to be a clickable link… if you could be bothered doing all of the above to save the ‘img src’ code in your HTML, then an empty ‘a href’ link with above mentioned background image would also work.
Stefan Seiz
on 22 Jan 09This commenting feature needs not to be hidden anyway. With your implementation, this feature can only be discovered by accident as most will focus on the checkbox and not care to mouse over the text. I would have thought 37Signals’ philosophy of keeping it simple would have lead you to the final conclusion to not hide the comment bubble at all and simply constantly display it without the need for a hover.
Always showing the bubble might add a little visual noise, but a carefully crafted bubble icon is surely not uglier than the standard browser checkbox.
I’d be curious to hear your reasoning Ryan on why you need to hidde the comment button and only show it on hover?
Morgan Roderick
on 22 Jan 09Very interesting read, thanks for sharing Ryan :-)
I agree with with Stefan; hiding functionality from your users defeats the purpose of making it in the first place, unless it is something that will rarely be used.
You would think that being able to comment on items, would be of some importance.
Also, using a link with a background (and maybe even :hover), would make it perform nicely with caching and will even work with javascript disabled.
Rimantas
on 22 Jan 09@Stefan and Morgan — once you discover this feature, you will know it is here but it won’t clutter the display. Options to edit or move items work the same way, no problem here.
Blake
on 22 Jan 09Positive: Comment icon is no longer on its own line if the text completely fills the previous line. Negative: There’s a massive space between the end of the text and the comment icon if the text doesn’t take up ~80% of the space.
What occurs more often: the text being the perfect length to knock off the comment icon to a new line or the text being any length that leaves a massive void between it and the icon?
Rimantas
on 22 Jan 09I just want to add that besides “display” there is a nice little “visibility” property in CSS which lets you to hide elements without giving up the space occupied by them. You can see that in action on my test page.
RS
on 22 Jan 09No, there is no gap between the to-do text and the comment icon. The icon appears immediately to the right of the text with no space in between, as the screenshots show. That is the reason for positioning relative to an inline element (the span) instead of a block element.
Anonymous Coward
on 22 Jan 09Unless I duplicated it wrong, this looks pretty bad in Firefox. It sticks to the end of the first line, even if the second line takes a longer amount of space. For instance if the todo item is “Go to TheStoreWithTheAnnoyinglyLongName” and make sure the wrap breaks after to.
So the comment bubble might actually be above text for the same todo item. Didn’t you guys just post about spacing and context? This makes it seem like the bubble is part of the todo.
All I did was apply these styles to your example HTML:And to be fair, I don’t use either basecamp or backpack to check the final implementations for this.
Justin
on 22 Jan 09Just for the record, previous comment was by me. Forgot to fill out the top.
Also, I really like Rimantas’ solution.
Oakmad
on 22 Jan 09For everyone this technique is new to, might I suggest Transcending CSS by Andy Clarke. Its 2 years old now but I still look to it for some great tips like this
Jared
on 22 Jan 09This technique is sometimes known as absolute-relative positioning. What’s great is that in most cases making an element relative will not affect it’s positioning/layout.
Ryan Cannon
on 23 Jan 09Not sure I understand why you went absolute here. It looks very odd to have that comment bubble outside the box. Why not just use a non-breaking space ( )? That’s exactly what it’s meant for, and it saves you a bit of complexity.
RS
on 23 Jan 09Ryan: A non-breaking space doesn’t solve the problem. The problem is that when the comment icon is displayed on hover, it sometimes wraps below the to-do text and pushes the other comments down. A non-breaking space wouldn’t prevent the comment icon from wrapping. On the contrary, it would force the comment icon, the non-breaking space, and the preceding word to wrap together as a unit.
mikemike
on 23 Jan 09Does that say “Harry Pottery Barn”? wahahaaa!
giulio
on 23 Jan 09why not adding to to-dos a feature to update the % of completion of each to-do?
Mitch
on 23 Jan 09I’m glad you guys did the SvN survey. Since then the quality of your posts has gone back to your old awesomeness!!!
This is the pure gold I come here for.
Thanks!
Sascha
on 23 Jan 09Why not using white-space: nowrap; ?
Andrew Dudley
on 24 Jan 09My brother is a little more vocal than I am on svn (Charles Dudley) as I usually stick to just reading, but I wanted to say that this is the kind of post that I really appreciate. From the ‘silent following,’ “Keep it up guys!”
Daniel Brockman
on 26 Jan 09What if you let it do that, but used visible: hidden instead of display: none? That way, unless I’m missing something, the line would be forced to wrap before the icon is even displayed, thus avoiding both the flickering and the risk of having the icon end up alone on its own line. Right?
Mark Turner
on 26 Jan 09Great post. Excellent tip. Thank you for sharing.
Justin
on 26 Jan 09@Daniel Brockman:
That is literally the solution presented by Rimantas.
Richard
on 27 Jan 09I realize the point of this was probably just to talk about the general theory, but I’d like to see the full code, or at least the smallest amount of code that gets it working cross browser. I spent twenty minutes hacking at it in Firefox before I read the comments saying it doesn’t work as written in that browser.
Behrang Javaherian
on 27 Jan 09Hi
I have another suggestion for this problem; using CSS for comment image:
<div class=”comment”>
This is a comment.
</div>
and then:
div.comment {
display:inline;
padding: 3px 16px 3px 0;
background: url(”/images/comment-icon.png” no-repeat right
}
Regards
intuitive online timesheet software
This discussion is closed.