W3C home > Mailing lists > Public > www-style@w3.org > December 2009

Re: Proposal: Fixed Table Headers in CSS

From: Tab Atkins Jr. <jackalmage@gmail.com>
Date: Tue, 15 Dec 2009 13:19:33 -0600
Message-ID: <dd0fbad0912151119v37733c47v342c49bb88589b59@mail.gmail.com>
To: Brad Kemper <brad.kemper@gmail.com>
Cc: Doug Schepers <schepers@w3.org>, "Eric A. Meyer" <eric@meyerweb.com>, Mikko Rantalainen <mikko.rantalainen@peda.net>, www-style CSS <www-style@w3.org>
On Tue, Dec 15, 2009 at 12:47 PM, Brad Kemper <brad.kemper@gmail.com> wrote:
> On Dec 15, 2009, at 6:06 AM, Tab Atkins Jr. wrote:
>> 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.

Yes.  However, if the table is, say, one screen-height tall, and
starts off halfway down the screen, then both the thead and tfoot
would appear on-screen immediately, with some of the table between
them.  As you scrolled down the thead would raise and the tfoot would
stay at the bottom of the screen, until the bottom of the table is
visible.

> 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:

Indeed.  If things are sticky relative to their containing block, then
the iPhone Contacts app would be coded with each group of contacts
being a containing block for the sticky heading.  They don't
accumulate because as each heading reaches the top, the bottom of the
previous containing block also approaches the top of the screen, which
will push the previous heading out-of-view with it.

> 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).

That's an elegant way to handle it, and I like it.  I'm not sure what
you mean in the last paragraph, though.  Can you explain what it means
in terms of an example, like how the following code would work?

<h1>Foo</h1>
<p>foo foo foo</p>
<h2>Bar</h2>
<p>bar bar bar</p>
<h2>Baz</h2>
<p>baz baz baz</p>
<style>
h1,h2 { position: sticky; top: 0; }
</style>

In my conception, these should all accumulate, since they all have the
same containing block (<body>) and sticky boxes aren't allowed to
overlap.  In order to get them to accumulate in the way you would
expect, you'd instead do:

<h1>Foo</h1>
<p>foo foo foo</p>
<section>
  <h2>Bar</h2>
  <p>bar bar bar</p>
</section>
<section>
  <h2>Baz</h2>
  <p>baz baz baz</p>
</section>
<style>
h1,h2 { position: sticky; top: 0; }
section { position: relative; }

This way the <h1> stays on the screen at all times, as it's sticky
relative to <body>, but the <h2>s only stay on the screen as long as
their containing <section> does, and so will *appear* to displace each
other as the <section>s scroll on or off of the screen.

How would each of these examples work in the way you're envisioning things?

>>> * 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.

That's my thought too.  You have to listen for scroll events, but
that's not difficult.

~TJ
Received on Tuesday, 15 December 2009 19:20:09 GMT

This archive was generated by hypermail 2.2.0+W3C-0.50 : Tuesday, 22 May 2012 03:47:12 GMT