Re: Proposal: Fixed Table Headers in CSS

On Dec 15, 2009, at 6:06 AM, Tab Atkins Jr. wrote:

> On Mon, Dec 14, 2009 at 9:46 AM, Doug Schepers <schepers@w3.org> wrote:
>> * should this include both headers and footers?  (My intuition is yes.)
> 
> Sure.  We're looking at it as a generic mechanism now.  

I've been thinking about this sort of mechanism ever since I got my iPhone a couple years ago, because they have something like list headers that scroll with the rest of the list until they get to the top, and then they become fixed and the list scrolls underneath them. It is very similar to what you've described for table headers, and I've always wanted something like that too. 

> Note, though,
> that putting it on both a header and footer means that they'll both be
> visible at all times while the table is visible.  They'll appear
> first, then they'll separate and show the data.

Assuming the table fit within the viewport, they would appear normally at first. Then when the thead reached the top it would look like it was fixed. Eventually the tfoot would scroll up to touch the bottom of the thead. The same thing would happen in reverse when scrolling down instead of up, with the tfoot becoming fixed at the bottom of the viewport.

>> * how should vertically-scrolled content (e.g. row headers, maybe more
>> complex non-table content?) be handled? (my first instinct is that this
>> effect should be defined as for scrolling
> 
> You mean like if a row header gets horizontally scrolled off the
> screen?  We should define a mechanism for saying that we only care
> about it remaining visible in certain directions.
> 
>> * should sticky content accumulate?
> 
> Yes.  That's the only way to go when you do this generically, I
> believe.  That means that sticky content still has a notion of
> 'thereness' that normal abspos or fixpos content doesn't (that is,
> abspos/fixpos elements will gladly overlap each other).  Sticky
> elements (a) need to reserve their old space in the element (like a
> relpos) when they switch from normal flow to sticky (so that
> subsequent content doesn't suddenly 'jump up' now that the sticky
> heading or whatever isn't there), and (b) need to avoid overlapping
> other sticky elements, like how floats avoid overlapping each other.
> I feel like the exact details of (b) will depend on how we define the
> 'directionality' of stickyness (like with the row-headers that are
> only sticky if scrolled off horizontally).

The iPhone interface for such iPhone apps as "Contacts" solves this very neatly. The sticky content does not accumulate within the viewport, but instead gets pushed off-screen when other sticky content scrolls up to meet it. If you are not familiar with this iPhone convention, then first take a look at this jQuery-based demo I found on the Web:

http://demo.marcofolio.net/iphone_contact/

Now imagine that the letter markers ("A", "B", "C", etc.) are table headers. Scroll the "B" to the top (using the scroll bar), and note that the "A" then disappears. The demo simulation is not perfect in the above link. It looks nicer on the actual iPhone, because instead of just disappearing, the "A" is pushed off screen, and returns the same way in reverse when scrolling the other way. Here are some screen captures from my own phone to show what happens there:

http://www.flickr.com/photos/bkemper/4188214308/in/photostream/
http://www.flickr.com/photos/bkemper/4188214978/in/photostream/
http://www.flickr.com/photos/bkemper/4187452377/in/photostream/
http://www.flickr.com/photos/bkemper/4187452569/in/photostream/
http://www.flickr.com/photos/bkemper/4188215810/in/photostream

(And yes, some of you on this list had your e-mail addresses automatically added to my contacts when I replied to you at some point, and then that got synced to my phone, so don't be alarmed to see your name there.)


>> ** i.e. will a sticky <h1> stay on the screen when its "child" <h2>s stick?
>> will multiple <h2>s stick together? (I would guess that different "levels"
>> of heading could accumulate, but not "siblings".)
> 
> In my current idea of how this works, sticky elements use their
> containing element to decide how long to stick around.  When their
> containing element completely scrolls off the screen, they go with it.
> So yes, both the <h1> and the <h2> would stack.  As long as you used
> <section> elements to establish the <h2>s in new containing blocks,
> though, they won't stack - as one comes up, the previous one scrolls
> off along with its containing block.

My idea is that this would be a position property, such as 'position: sticky' or 'position: scroll-limited' or 'position: semi-fixed'. And thus, it would use 'top', 'bottom', 'right', and 'left' properties, in this case to determine where within the viewport (or within the containing block) the element would "stick" and become semi-fixed, relative to that side. Thus, for a table header, you might have this:

thead { position: scroll-limited; top:0; }

Or, suppose you already had a position:fixed page header that was 100px tall, and you wanted the table headers to stop below that when scrolling, along with a little extra room:

#page-header { postion: fixed; top:0; height: 100px; }
thead { position: scroll-limited; top: 110px; }

The thead would stay fixed at the 'top' value for as long as it's "natural" scroll position would be that number or less relative to the top of the scroll port. Once it became more than that number, it would assume normal scrolling (like position:static).

You could also get items to stick to the bottom this way, when they would ordinarily be scrolled off-screen:

tfoot { position: scroll-limited; bottom:0; }

Or you could use the 'left' or 'right' properties to get columns (or, more likely, THs within a column) to stick in place horizontally.

So... items wouldn't really accumulate around the edges of the viewport because they get pushed offscreen by elements that also have the same edge set. If two elements, a 'top' and a 'bottom' for instance, did not fit in the same viewport, then they would be pushed outward from where they touch (and you wouldn't see anything that was between them).


>> * what should be the behavior when a user jumps to the middle of a
>> containing block that would otherwise have a sticky header/footer when
>> scrolled (e.g. a row in the middle of a very long table, a paragraph under a
>> sticky <h2> itself under a sticky <h1>)?  (I think it the sticky content
>> effect should be applied, though I suspect this will make implementation
>> rather more difficult.)
> 
> The sticky effect should be applied.  The way I'm imagining it is that
> you specify the directions that the sticky element doesn't want to
> scroll off (by default, this would just be 'top').   Jumping straight
> down, frex by an anchor link, still scrolls things off (and most UAs
> actually animate an anchor link as a scroll now anyway).

Yeah, if you jumped to the middle of a table with a sticky header and footer, then you'd still see both, with the row you jumped to also visible.

>> * should there be an event that is thrown when content sticks, so that the
>> author can choose to enhance the effect via script or declarative animation
>> (change the background color of the sticky content, widen it to fill the top
>> like the Slashdot example, shrink the font size and fade the color to make
>> it more subtle, etc.)?
>> ** if so, should there be another event when it unsticks?
>> ** should there be an event attribute to indicate whether the content stuck
>> to the top, bottom, left, right?
>> ** any other events or attributes?
> 
> I dunno.  We don't usually have events thrown by CSS interactions,
> though it does sound like this sort of thing might be useful.

I'd think you could just compute its position relative to the viewport pretty easily to do the same thing.

Received on Tuesday, 15 December 2009 18:48:22 UTC