Bug 17152 - Support centering an element when scrolling into view.
Support centering an element when scrolling into view.
Status: NEW
Product: CSS
Classification: Unclassified
Component: CSSOM View
unspecified
All All
: P2 normal
: ---
Assigned To: Simon Pieters
public-css-bugzilla
:
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2012-05-22 21:47 UTC by Thaddee TYL
Modified: 2015-03-12 18:42 UTC (History)
4 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Thaddee TYL 2012-05-22 21:47:25 UTC
The main reason why we might use `scrollIntoView()` is to bring an
element into the viewport.

However, showing that element at the top or at the bottom of the
viewport is detrimental to understanding the context in which this
element is. As a result, what authors really want is to center
the element.

I know we are implementing that in JS again and again throughout Firefox,
and web developers are, too.


Webkit has a method called
`void scrollIntoViewIfNeeded(optional boolean center);`,
which scrolls the page so that an element, if not completely shown,
becomes completely shown, and appears vertically centered in the viewport
if the boolean is true.

The reason I bring this method up is to highlight its bad design.

1. Boolean flags are unreadable: it is unclear from reading
   `scrollIntoViewIfNeeded(false)` what that `false` means, and even if
   we know that it is about centering the element, which one, of `true`
   and `false`, does indeed center the element.

2. We already have `void scrollIntoView(optional boolean top)`.
   Having many methods whose intents are collinear is wrong.
   Different methods should have orthogonal goals.

I therefore suggest the following addition:

    partial interface Element {
      void scrollIntoView(ScrollPosition options);
    };

    dictionary ScrollPosition {
      float top = 0.5;
      float left = 0.0;
      boolean notIfViewed = true;
    };

where `top` and `left` are meant as percentages of
`max(0, scrollY - element.clientHeight)` and
`max(0, scrollX - element.clientWidth)` respectively.

If `notIfViewed` is true, and the element is completely in the viewport,
then this method does nothing.
If `notIfViewed` is true, and the element is partially hidden,
then scroll just enough so that the element appears completely
in the viewport.

In all other cases, scroll so that the element is positioned at
`options.top * max(0, scrollY - element.clientHeight)` with respect
to the top border edge, and at
`options.left * max(0, scrollX - element.clientWidth)` with respect
to the left border edge.

Overloading of `scrollIntoView` happens
as described at <http://www.w3.org/TR/WebIDL/#idl-overloading>.

An intended effect of this design is that calling
`element.scrollIntoView({});` automatically does the right thing and
centers the element on the screen, while you can still get the
old behavior by calling `element.scrollIntoView()`.
Comment 1 Glenn Adams 2012-05-23 17:06:30 UTC
see also http://lists.w3.org/Archives/Public/www-style/2012May/0808.html
Comment 2 Thaddee TYL 2012-06-19 22:17:52 UTC
Some additional discussion occurred on the mailing-list.

As a result, the proposal has changed a little.

The WebIDL corresponding to this proposal is the following:

    partial interface Element {
      void scrollIntoView(ScrollPosition options);
    };

    dictionary ScrollPosition {
      float horizontal = 0.5;
      float vertical = 0.5;
      boolean evenIfViewed = false;
    };

The following paragraph is non-normative.

`horizontal` and `vertical` are meant as percentages of
the viewport width minus the width of the bounding box of the element, and
the viewport height minus the height of the bounding box of the element,
respectively.

(Having a boolean flag does what is already specified.)

Having a dictionary as a parameter runs the following algorithm:

1. If the Document associated with the element to be scrolled into view is not same origin with the Document associated with the element or viewport associated with the scrolling box, terminate these steps.

2. If `evenIfViewed` is false:
- If the bounding box of the element this method is applied to is completely out of the viewport, scroll the element to ((innerWidth of the window - offsetWidth of the element) * horizontal ; (innerHeight of the window - offsetHeight of the element) * vertical).
- Else if the element is partially visible:
 * If the lower part of the bounding box of the element this method is applied to is partially visible, align the top of the border box of the element to be scrolled into view with the top of the scrolling box,
 * If the higher part of the bounding box of the element this method is applied to is partially visible, align the bottom of the border box of the element to be scrolled into view with the bottom of the scrolling box,
 * If the right part of the bounding box of the element this method is applied to is partially visible, align the left of the border box of the element to be scrolled into view with the left of the scrolling box,
 * If the left part of the bounding box of the element this method is applied to is partially visible, align the right of the border box of the element to be scrolled into view with the right of the scrolling box,

3. If `evenIfViewed` is true, scroll the element to ((innerWidth of the window - offsetWidth of the element) * horizontal ; (innerHeight of the window - offsetHeight of the element) * vertical).

4. If scrolling the element caused content to move queue a task to fire an event named scroll at the element, unless a task to fire that event at that element was already queued.

Finally, a polyfill for this proposal has been implemented, and is available for public consumption at <http://jsbin.com/3/ilecok/13/edit?javascript>.


Robert O'Callahan raised concerns related to CSS-regions, which may cause elements to be fragmented between several scrollable containers. The specification I give above depends on the concept of "scrolling an element", which should be changed anyway to accommodate this possibility.
Comment 3 Glenn Adams 2012-08-03 05:55:17 UTC
reassign to myself; apparently i am not the default assignee for this component
Comment 4 Simon Pieters 2013-05-14 16:00:33 UTC
(In reply to comment #0)
> As a result, what authors really want is to center
> the element.

If that's what authors want, why does the proposal do more than that? What's the use case for arbitrary positioning? What's the use case for `evenIfViewed`?
Comment 5 Thaddee TYL 2013-05-14 20:00:36 UTC
(In reply to comment #4)
> (In reply to comment #0)
> > As a result, what authors really want is to center
> > the element.
> 
> If that's what authors want, why does the proposal do more than that? What's
> the use case for arbitrary positioning? What's the use case for
> `evenIfViewed`?

There are two reasons to use this.

One is to perform search. In that case, preserving the surroundings of the element that currently matched (in a series of matches) allows the user to see in which context the element is. A common UI decision in this case is to highlight the element in some way. As a result, it is not necessary to actually bring the element at the center of the viewport; furthermore, not changing the viewport allows the user to see the spatial relationship between the element that currently match with the next one in the list. In this case, the author will probably want to set `evenIfViewed` to false.

The other one is simply to bring an element into the viewport. In that case, there is no list of matches, we simply want to force a certain element into the viewport in a specific way. The author will then want to set `evenIfViewed` to true.

In that latter case, the author may also want to position the element in a different way than simply centering the element in the viewport. For instance, if the bottom of the element is what is relevant for the user, it must be shown. If the element is too big vertically for the viewport, the author may want to set `vertical` to 1, to force the bottom of the element into view.
Comment 6 Simon Pieters 2013-06-18 08:55:42 UTC
The 'top' argument is now aware of vertical writing modes. I think it would make sense for these settings to be aware of vertical writing modes, too (otherwise it wouldn't be possible to specify the equivalent of "top" and also set eventIfViewed without having to check what the writing mode is).

The question is whether the names vertical and horizontal make sense with that in mind. The writing-mode aware spec terms are "inline base direction" and "block flow direction", but I don't think such names are exposed to Web authors currently.
Comment 7 Simon Pieters 2014-09-18 11:32:27 UTC
Would the following additions satisfy your use cases?

* Ability to center in the block direction (vertically for top-to-bottom)
* The "evenIfViewed" thing (how about calling it "force"?)

That is, are there use cases for aligning in the inline direction?
Are there use cases for aligning on the physical axes instead of the logical axes?
Are there use cases for aligning to arbitrary values 0..1 instead of just start/center/end?
Comment 8 Thaddee TYL 2014-09-18 20:40:11 UTC
(In reply to Simon Pieters from comment #7)
> Would the following additions satisfy your use cases?
> 
> * Ability to center in the block direction (vertically for top-to-bottom)

I am not sure what the block direction is. If it is about writing systems, both axes are necessary for my use case. Centering horizontally is useful for context; for instance, on a long line that you need to scroll horizontally to see, search should center terms horizontally.

> * The "evenIfViewed" thing (how about calling it "force"?)

I agree that would be useful. I picked the name "evenIfViewed" partly based on WebKit's "scrollIntoViewIfNeeded" and partly based on an attempt at expressiveness.

> That is, are there use cases for aligning in the inline direction?

Do you mean left-to-right? The use-case for left-to-right is the same as that for top-to-bottom, when dealing with a webpage that can be scrolled left-to-right. Searching for terms in a page should center things horizontally as well.

> Are there use cases for aligning on the physical axes instead of the logical
> axes?

I am not sure I understand the difference between physical axes and logical axes. At any rate, I believe all developers would understand vertical and horizontal.

> Are there use cases for aligning to arbitrary values 0..1 instead of just
> start/center/end?

Providing a value from 0 to 1 allows webpages to specify exactly how much context they want to give. For instance, when scrolling to a graph embedded in a textual document, we would want to have the top of the graph roughly at the top, but we may want to show a piece of the text that introduces the graph to the reader.

In any case, scrolling a graph into view and having its top appear exactly at the top is ugly, and having its top appear exactly in the middle of the viewport is equally ugly (the majority of the viewport should be dedicated to the graph).

Also, I have seen cases where that percentage was used as a way to visually know where we are in a larger picture, specifically when zooming in in rectangular maps. When searching a spot on the map, that spot appears on the viewport such that its distance to the top and the left of the viewport reflects, by proportionality, the distance of the viewport itself to the edges of the map.

PS: based on the feedback about graphs in text, specifying whether what we want to scroll into view is the top, bottom, left, right, or center of the element can be seen as valuable. However, those are not expressive tools to the programmer who might want to center around the top left instead. Using percentages (as values between 0 and 1) for both horizontal and vertical covers all those possibilities and more, and it isn't much harder to implement.
Comment 9 Simon Pieters 2014-09-19 11:53:22 UTC
(In reply to Thaddee TYL from comment #8)
> I am not sure what the block direction is. If it is about writing systems,

Yes. http://dev.w3.org/csswg/css-writing-modes-3/#block-flow-direction

> both axes are necessary for my use case. Centering horizontally is useful
> for context; for instance, on a long line that you need to scroll
> horizontally to see, search should center terms horizontally.

OK, I see that some browsers do that for page search, so that seems reasonable.

> > * The "evenIfViewed" thing (how about calling it "force"?)
> 
> I agree that would be useful. I picked the name "evenIfViewed" partly based
> on WebKit's "scrollIntoViewIfNeeded" and partly based on an attempt at
> expressiveness.
> 
> > That is, are there use cases for aligning in the inline direction?
> 
> Do you mean left-to-right?

When the block flow direction is top-to-bottom, yes. :-)

> The use-case for left-to-right is the same as
> that for top-to-bottom, when dealing with a webpage that can be scrolled
> left-to-right. Searching for terms in a page should center things
> horizontally as well.
> 
> > Are there use cases for aligning on the physical axes instead of the logical
> > axes?
> 
> I am not sure I understand the difference between physical axes and logical
> axes. At any rate, I believe all developers would understand vertical and
> horizontal.

The difference is that the logical axes change when the writing system changes, while the physical axes don't.

Currently scrollIntoView is specified to scroll to the logical top (or bottom).

> > Are there use cases for aligning to arbitrary values 0..1 instead of just
> > start/center/end?
> 
> Providing a value from 0 to 1 allows webpages to specify exactly how much
> context they want to give. For instance, when scrolling to a graph embedded
> in a textual document, we would want to have the top of the graph roughly at
> the top, but we may want to show a piece of the text that introduces the
> graph to the reader.

Wouldn't you scroll the introductory text into view, then, and align that to the top?

> In any case, scrolling a graph into view and having its top appear exactly
> at the top is ugly, and having its top appear exactly in the middle of the
> viewport is equally ugly (the majority of the viewport should be dedicated
> to the graph).

Yeah, I imagined that "center" would properly center the element, not align the top of the element with the center of the viewport. That is, align the center of the element with the center of the viewport. (Possibly aligning the top of the element with the top of the viewport if the element is taller than the viewport, and similarly in the other direction.)

> Also, I have seen cases where that percentage was used as a way to visually
> know where we are in a larger picture, specifically when zooming in in
> rectangular maps. When searching a spot on the map, that spot appears on the
> viewport such that its distance to the top and the left of the viewport
> reflects, by proportionality, the distance of the viewport itself to the
> edges of the map.

Do you have a URL for a page that does this?

> PS: based on the feedback about graphs in text, specifying whether what we
> want to scroll into view is the top, bottom, left, right, or center of the
> element can be seen as valuable. However, those are not expressive tools to
> the programmer who might want to center around the top left instead. Using
> percentages (as values between 0 and 1) for both horizontal and vertical
> covers all those possibilities and more, and it isn't much harder to
> implement.

Hmm, so sometimes you want the anchor point of the element to be its center, and sometimes its top left? If we only support the top left you have to measure the element's dimensions to really center it, which seems annoying. On the other hand, having background-position-like behavior is also annoying if you want exact positioning.