- From: Tab Atkins Jr. <jackalmage@gmail.com>
- Date: Mon, 18 Oct 2010 12:32:00 -0700
- To: www-style list <www-style@w3.org>
Since I've worked at Chrome, one of the things I've heard developers complain about a lot is the weakness of absolute positioning. For example, our app devs commonly want to position tooltips relative to arbitrary elements in a contenteditable area. As well, there are certain types of layouts that are not really possible to do in any existing or proposed layout mode in CSS. However, they may be easy to describe in terms of absolute positioning relative to particular edges of other elements. (I have an example, but at the moment it only works in dev channel Chrome because it uses classlist - I'll describe it later*.) To fix this, I've written a personal draft of a new Positioned Layout spec I'd like to see adopted by the group. It's currently hosted on my blog: <http://www.xanthir.com/blog/b48H0>. As it's fairly long (it's in a rough spec form), I'll summarize here the basic points: 1. I've specified the behavior of abspos-in-table as a general truth of positioned elements, so that future layout models will treat them consistently. I've come to realize that this behavior really is best; for one, it makes my draft a lot saner, as I can refer directly to the position of the placeholder for later properties. 2. I've slightly reinterpreted the 'position' values to be consistent with the above, and make all the values interact well with the new properties I've created. Pages still using 'position' as CSS2.1 defines it won't change at all. 3. I've introduced four new properties - position-root-top/right/bottom/left - and position-root as a shorthand to specify them all together. This is the meat of the proposal. I was inspired by Daniel's "position:new" proposal at <http://daniel.glazman.free.fr/weblog/position__new.html>. In simple terms, this just allows you to specify precisely which edge the top/right/bottom/left properties measure themselves from. There are several predefined keywords which provide useful references; you can specify edges of the previous element, parent element, containing block, root element, or viewport. You can specify edges of arbitrary elements in the document with the element() function (currently a moz-specific function used only as an <image> type). There's also a more complex value that can be used to specify more complex relationships. In the aforementioned complex layouts*, it's not always sufficient to specify the position of an element relative to the edge of a single other element; you need to be able to refer to the lowest edge amongst several elements, so you can position the element lower than any of them. I've defined the <edge-reference> value for this - it takes a set of element/edge pairs and selects the topmost/bottommost/rightmost/leftmost of them to use as the reference. This also uses an elements() function (note the plural), similar to element(), for referring to a set of elements that match a selector, so you can include the edges of all of them. 4. I haven't yet specced it, but I'll be including some way to restrict element edges from not going past a certain other edge. Right now I just have some brainstorming on how to do it. For example, when positioning a tooltip, you don't want it to extend out of the viewport. This also happens to be great for doing frozen table headers: thead { position: relative; position-root-top: bottommost(parent top, viewport top); position-contain: parent; top: 0; } This make the <thead> act normally if the table is on screen or below the screen, stay visible when the table starts to scroll off the top of the screen, but scroll away with the table when it goes completely off-screen, exactly like frozen headers are supposed to. A similar technique can be used on "tr > th". It still needs some fleshing out, but overall I think it's feature-complete (or will be when I decide how I want to do position-contain or whatever). What does everyone think? Can we adopt this? (Possibly we'd need to put it in the charter; is that okay?) ~TJ * Since I haven't yet gotten the layout demo separated into something that'll work in public builds, I'll describe it in ASCII for now. What I have is a newsreader app with the following layout: +------+--------+--------+--------+ | 10am | b1 | m1 | s1 | | | | |--------| | | |--------| s2 | | |--------| m2 |--------| | | b2 | | s3 | | | |--------|--------| | | | m3 | s4 | |------|--------| |--------| | 8am | b3 |--------| s5 | | | | m4 |--------| ... For each block of time, we subdivide stories by importance. "Big" news has a decent blurb and a picture, "medium" news has a small blurb, and "small" news just has a title. The edge of the timezones is ragged; m3 belongs to the 10am timezone but extends into the 8am block, so you don't have unsightly gaps between timezones because the story lengths are somewhat different. This isn't too difficult to do in traditional CSS right now, but then I throw a wrench into things. When you click on a story, it expands and shows the full story, looking something like this (assume I expanded m2): +------+--------+--------+--------+ | 10am | b1 | m1 | s1 | | | | |--------| | | |--------| s2 | | +--------------------------+ | | expanded m2 | | | | | | | | | | | +--------------------------+ | | b2 | m3 | s3 | | | | |--------| | | |--------| s4 | |------|--------| m4 |--------| | 8am | b3 | | s5 | | | |--------|--------| ... That is, the expanded story fills all three columns, and pushes stories in all three columns below it. This *cannot* be done with traditional CSS layout, because there is no way for an element to live in three columns at once. You can sort of fake this by giving up and using tables (one 4-cell row per timezone initially, split into multiple rows when you expand a story, with rowspans and colspans set appropriately), but that kills your ability to do continuous stories across timezones; you're forced to have gaps at the end of every timezone so that the next timezone can start fresh in a new row. (You're forced to have gaps above an expanded story, but that's both unavoidable and generally small, so it's okay.) That was unacceptable, so we ended up with an innovative solution - do the entire thing with absolute positioning, but pair it with a constraint solver in javascript so we could just specify which edges were tied to which other edges, and it would automatically compute positions for us. This works wonderfully, and the app is beautiful, but having the layout done by a js constraint solver isn't great. We could replace the entire thing by a handful of CSS rules using the concepts in my draft, just using js to decide which edges are tied to what when you expand/contract stories.
Received on Monday, 18 October 2010 19:32:58 UTC