- From: Tab Atkins Jr. <jackalmage@gmail.com>
- Date: Mon, 11 Apr 2011 14:35:46 -0700
- To: www-style list <www-style@w3.org>
The current OM APIs for determining the size and position of an element are verbose and confusing. There's been discussion on how to make this better, but it's been scattered and hasn't yet produced anything. Chrome is interested in doing some experimental implementation in this space, but there's a lot of possible ways to do it, so I'd like to collect and restart the various discussions here. Determining the Size of an Element ================================== Right now there are four ways of asking for the width of an element: elem.clientWidth, elem.scrollWidth, elem.getBoundingClientRect().width, and getComputedStyle(elem,'').width (similarly for height). It's completely unobvious what each of these do - the only thing that you can really gather is that .scrollWidth has something to do with scrolling. The term 'client' used in two of the methods is completely opaque; even worse, the two methods don't even refer to the same rectangle! (In case people are unaware of what the first two actually do, I made a diagram some time ago at <http://www.xanthir.com/diagrams/scrollwidth-clientwidth.html>.) The first three return the size in pixels as an integer, while the fourth returns size in pixels as a string with 'px' at the end. The third is transform-aware, while the others ignore any transforms on the element. Libraries like jQuery offer some simple, relatively-well-named functions for querying various sizes that you might want. jQuery gives you .width() for the content box, .innerWidth() for the padding box, and .outerWidth() for the border box. All in all, these are the boxes that we might want to get sizing information about: 1. content box, ignoring scrollbars 2. content box, subtracting scrollbars 3. content box, scrollable area 4. padding box (+/- scrollbars? Depends on exactly where the impl puts the scrollbars.) 5. border box 6. transform-aware bounding box of at least the border box, possibly other boxes Determining the Position of an Element ====================================== Right now, there are two ways to get the position of an element: elem.offsetTop/Left (gives you coords relative to the element's positioning root), and elem.getBoundingClientRect().top/right/bottom/left (post-transform coords of the bounding box relative to the viewport). All of the boxes listed in the above, though, can be useful to get the dimensions of. For example, I made a simple test page earlier today as a precursor for a talk I'll be giving, and I used getBoundingClientRect to help convert the mousemove event coordinates into coordinates relative to my <canvas> element. Unfortunately, the rectangle returned by getBoudingClientRect is the border box, when I'd have liked the content box - I had to manually subtract the size of the borders from my results, which is brittle if I ever change the width of the border in my CSS and forget to update my JS. (Alternately, I could have gotten getComputedStyle().borderTopWidth and .borderLeftWidth and parsed them into integers.) Position Relative to Another Element ==================================== Right now you can determine the position of an element relative to another element by figuring out their position relative to the same thing manually with one of the above methods, then subtracting one's top/left from the other. Does this need to be made more convenient, so you can directly ask for something's position relative to something else? Mouse Positioning ================= On a closely related tangent, the mouse events expose .clientX and .clientY properties which are relative to the viewport. If you're trying to find the position of the mouse relative to an element (for example, if you're drawing something to a <canvas> where the mouse is), you have to find the position of the element relative to the viewport and subtract the two positions. I think this is a good candidate for being made easier, so you can just request the mouse coords relative to an element. Again, all of the boxes of an element are potential targets for being measured relative to. Mouse Positioning and Transfoms =============================== When an element is being transformed, the position of the mouse relative to it is subtler. You may want the actual position of the mouse relative to the current post-transform layout position of the element - this is easy to do by just subtracting the mouse position from the bounding-box position. If you're drawing into a transformed <canvas>, though, you may want the position back in pre-transform coordinates, as if you took the stated mouse position and applied the element's inverse transform, so you can easily draw into the canvas and still have the visual display track the mouse. Proposal ======== I'm not sure! There's a lot of different possible approaches here. I'd like to optimize for author comprehensibility, which often means optimizing for terseness as well, but I'm not certain how best to do that. For the simple measurement case, something like elem.cssBorderRect.width/height/top/right/bottom/left would work. We could similarly expose cssPaddingRect, cssContentRect, cssScrollRect, etc. Bounding boxes for transform-awareness can be requested as cssBoundingBorderRect - in the absence of transforms, these return the same information as their non-bounding equivalents. Doing relative measurement is harder. I'm not sure how I can tersely expose that information. It may be acceptable to just say "hey, subtract the positions", given that getting the positions relative to the same thing would be easier. If anyone has better ideas, feel free to pipe up. The mouse positioning case has already received some attention - the last proposal I saw was for a MouseEvent.getCoordsAt(elem) function, which returns an object with .x and .y. This is the point in the transformed space (the one you can easily use to draw something under the mouse with <canvas>). This isn't *quite* sufficient, since it would presumably give you coordinates relative to the border box of the element, when you may want one of the other boxes, but it's close. Finding the mouse position relative to an element in normal space can probably be done by just subtracting the positions, same as finding the relative positions of two elements. Thoughts? ~TJ
Received on Monday, 11 April 2011 21:36:34 UTC