W3C home > Mailing lists > Public > www-style@w3.org > June 2012

Re: Sticky Positioning

From: Simon Fraser <smfr@me.com>
Date: Thu, 28 Jun 2012 11:16:56 -0700
Cc: Edward O'Connor <eoconnor@apple.com>, "www-style@w3.org" <www-style@w3.org>
Message-id: <D5DE9562-ED1E-4FA9-B3EC-1172F5889C02@me.com>
To: Brad Kemper <brad.kemper@gmail.com>
On Jun 28, 2012, at 10:37 AM, Brad Kemper <brad.kemper@gmail.com> wrote:

> On Jun 26, 2012, at 4:50 PM, Edward O'Connor <eoconnor@apple.com> wrote:
> 
>> A feature like this has been a long time coming. It was first proposed
>> (for table headers) by the OEBPS (EPUB) folks on www-style in 2002[1]:
>> 
>>> One of the examples of the desired layout\formatting behavior would be
>>> that the header column would stay frozen if horizontal scrolling is
>>> required to view additional columns of the table (similar to the
>>> "Freeze Panes" option in Excel).
>> 
>> Mikko Rantalainen proposed generalizing such a feature to elements other
>> than table headers[2]:
>> 
>>> Perhaps a new position value (e.g. "fixed-relative") that is a mix of
>>> "relative" and "fixed": the content still reserves space in the flow
>>> similar to relative but it would be displayed as fixed if the element
>>> would not fit in the viewport but its containing block is visible. In
>>> that case, the element would be "moved" within its containing block
>>> until it would fully fit in the viewport.
>> 
>> Mikko's proposal is very close to what we have in mind: a new value for
>> the 'position' property, similar to relpos, but with a new method of
>> calculating the element's offset.
>> 
>> You'd use it like this:
>> 
>> h1 {
>> position: sticky;
>> top: 10px;
>> }
>> 
>> This means that every <h1> in the document will "stick" 10 pixels from
>> the viewport top when things scroll such that the <h1> would have been
>> partially off-screen. When the viewport has scrolled such that the
>> visible portion of the <h1>'s containing box is too small to fit the
>> <h1>, it should stop at the containing box's edge and only be partially
>> displayed.
> 
> I think this would be great. But I don't think the tbrl keywords should be only be relative to the viewport, but rather to the nearest potentially scrollable ancestor (overflow: auto | scroll). In many designs that might be the main scrollable content area with the viewport itself not scrolling at all.

We've had others suggest this too.

A complication is that an ancestor may only be scrollable in one direction (overflow-y: scroll), so you may want to sticky-position on the Y axis relative to your overflow:scroll ancestor, and sticky-position on the X axis relative to the viewport. That's slightly crazy.

> I'm not sure what you mean by the containing box's edge, especially if you are talking about only the viewport being the measure of what the 'top: 10px' is relative to. Wouldn't it stop at the edge of the same box, ie the viewport?

The sticky element is positioned inside a box that is the intersection of the viewport (inset by the top/right/bottom/left values), and the containing block (inset by the sticky element's margins).

So the sticky element never escapes its containing block.

> 
>> There are a lot of details to work out, of course. Doug raised several
>> questions about such a feature in [3]; here are some preliminary
>> thoughts on them.
>> 
>> Doug wrote:
>>> * should sticky content accumulate?
>> 
>> No. In some future level of this feature, it might be worth
>> investigating a new property or set of properties which could cause such
>> accumulation. We should avoid this problem in the first level of this
>> feature by having the sticky elements simply overlap, just as other
>> positioned elements do.
> 
> I would prefer that other position:sticky items (or perhaps sticky items with the same z-index) could push others out of the way, rather than overlap, in the way that list section labels do in iOS scrolling navigation lists (you know authors are going to want that). Thus is there are two items with 'top:0', the bottom one would push the top one out of the visible area until it could stick at 0 without overlap. Or if there are two items with 'left:0', the rightmost one would push the leftmost one off to the left. This is something important to have in first iteration, as it would be more clumsy to add it on later through a separate property, and I strongly suspect it will be the preferred mode.

We'd prefer to not do this initially. It adds enormous complexity. For example, do margins collapse between accumulating sticky-position elements? If so, it's very weird for margin-collapsing behavior to change as something starts acting stickily.

You'd also have to specify how accumulating sticky-position things accumulate if they don't overlap on an axis. I think it could get as complex as something like floats.

You can get the "pushing out of the way" behavior if you group your items in separate containing blocks.

> By the way, I think it is important for position:sticky to support z-index layering, so that the items can be interleaved with other position:relative and position:absolute items (since using 'position:relative' to get such z control would no longer be an option for sticky items).

z-index would apply on position: sticky elements (just as it does with position:relative).

> 
>> Doug wrote:
>>> * 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, just like any other positioning
>> scheme.
> 
> Yeah, I don't see the problem here.
> 
>> Doug wrote:
>>> * 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?
>> 
>> No. A big advantage of this feature over emulations of it in JS is the
>> lack of events.
> 
> I've no strong opinion on that, although it seems useful to have an event for sticking and unsticking, in case the author wants to change transparency or hide/show another element or something. You are doing away with all related events anyway, right? You still have scroll events, for instance.

I've also seen a suggestion that a pseudoclass be applied when an element is behaving stickily. Again, to preserve scrolling performance, I'd prefer to not do this or fire events.

> 
> Some other points:
> 
> * if top and bottom are both specified, they set the sticky limits for each; they do not change the height the way they would with absolute or fixed positioning. Same with left/right/width.

Correct.

> * if only z-index-same items could push each other aside, then you could still get overlap if you want, by giving the items different z-indexes.

Only apples if you do accumulation, which we want to leave until some later version.
> 
> * if top and bottom are both non-auto, and the element is taller than the scrolling container (or if left and right are both non-auto, and the element is wider than the scrolling container), then writing direction gives precedence. Thus in English lrtb, left and top would override right and bottom if both could not be satisfied simultaneously. 

Right, we need to determine behavior in this case.

Simon
Received on Thursday, 28 June 2012 18:17:26 GMT

This archive was generated by hypermail 2.3.1 : Tuesday, 26 March 2013 17:20:55 GMT