- From: Benjamin Poulain <benjamin@webkit.org>
- Date: Tue, 13 Jan 2015 14:04:01 -0800
- To: www-style@w3.org
This is a very well written proposal. The main argument I have against this is performance. Any time a :n-children is evaluated, we would have to really go over all the children to find the elements and count them. The pseudo class :nth-child() does not have this problem. The tree is visited in-order depth-first. When evaluating a :nth-child(), the previous nodes have been evaluated and we know what the state is. The performance of :n-children would be more like :nth-last-child(). It is possible to cache the result, but the initial evaluation requires you to evaluate lots of node. Style invalidation is gonna be inefficient, but not worse than :nth-last-child(). Given that there is already :nth-last-child() support in the spec, I am okay with having :n-children. Benjamin On 1/13/15 10:52 AM, Matt Mastracci wrote: > (Apologies to the maintainer of the list — I sent this twice without being subscribed. Please delete those pending copies.) > > I'd like to propose addition of functionality to CSS selectors level 4 to style an element conditionally based on the number of direct descendants it has. > > Note that this is not entirely new functionality as you can emulate it in some cases by bending the current selectors around a bit. [1][2][3] > > Justification > ============= > > This is useful building block for responsive, script-free structures on a page that dynamically adjust to the number of elements they contain [4][9]. See the "example use case" section below for specific examples where it would allow novel behaviour or simplify an existing case. > > As mentioned before, this is not entirely new functionality. The case where one styles children based on the number of elements directly contained by their parent can be achieved today by specifying both :nth-child and :nth-last-child on a child and the general sibling selector (~). [1][2][3] More complicated cases (e.g.: the fourth, seventh, tenth, etc. child of n, where n+2 is a multiple of three) can be difficult to reason through and not easy to parse when found in an existing stylesheet. > > What this selector does is make this existing functionality easier to read and write, while also opening up additional possibilities to style an element based on the number of children it has. This selector is to :empty and :not(:empty) as :nth-child/:last-child is to :first-child/:last-child. > > This selector adds a new case where an element's style may change as an HTML document is streamed from a remote server. I believe there is a precedent for this in the existing :nth-last-child() and :empty() selectors which may change state as the document is loaded, and the browser should use the same strategy for the new selector. > > Proposed syntax > =============== > > The proposed new selector looks and acts as similar to the existing :nth-child() selector as possible: > > :n-children(An+B [of S?]) > > An+B [5] represents a formula determining the number of children in an element. "even" and "odd" are also valid in its place. > > The behaviour of "of S" is analogous to its definition for :nth-child in CSS Selectors Level 4. > > For a developer who understands nth-child, the result of the examples here should be unsurprising and for the most part, analogous to their nth-child counterpart: > > * :n-children(2) > matches an element with exactly two children, of any type > > * :n-children(2 of div.important) > matches an element with exactly two elements that match div.important (other elements are not considered) > > * :n-children(even) > matches an element with an even number of children (including zero) > > * :n-children(10n-1) > matches an element with 9, 19, 29, etc children > > * :n-children(10n+9) > matches an element with 9, 19, 29, etc children > > * :n-children(10n+-1) > syntactically invalid, and would be ignored > > * :n-children(n+1) > matches an element with 1 or more children (equivalent to :not(:empty)) > > * :n-children(n+2) > matches an element with 2 or more children > > * :n-children(-n+2) > matches an element with 2 or fewer children > > Example use cases > ================= > > This particular selector is not entirely novel. These are real-world use cases that would benefit from the addition of an n-children() selector: > > * Responsive image galleries that adjust cleanly to the number of elements [4] > * Shrinking the height of dynamically added elements as more are added [6] > * Turning on "overflow" UI when reaching a certain number of children (see example below) > * Simplified table sizing for small numbers of known cases [7] > * Responsive/auto-sizing widget layouts [8] > * List as a fully-justified grid [9] > > Example CSS > =========== > > A container that shows/hides an "overflow" toggle button if five or more .child items are contained within: > > div.container button.overflow { > display: none; > } > > div.container:n-children(n+5 of .child) button.overflow { > display: block !important; > } > > div.container:not(.expanded) .child:nth-child(n+5 of .child) { > display: none; > } > > Auto-sizing, fully-justified sidebar widgets (half-sized in pairs, first widget full-sized if there is an odd number): > > div.sidebar .widget { > width: 50px; > height: 50px; > display: inline-block; > } > > div.sidebar:n-children(odd of .widget) .widget:first-of-type { > width: 100px; > height: 100px; > } > > Alternatives > ============ > > 1. Rather than adding a selector to the parent, we can add a selector to an element that would select based on the number of siblings (i.e.: :n-siblings()). This has the advantage of being similar enough to existing code that the impact on CSS engines would be less than the full proposal. > > 2. Do nothing (if the case where styling a parent based on the number of children is not deemed important enough to add this functionality to the spec). For users wishing to style children based on the number of siblings, they can continue to use both :nth-child and :nth-last-child to do this. > > References: > > [1] http://grack.com/blog/2015/01/09/abusing-css3-selectors > [2] http://lea.verou.me/2011/01/styling-children-based-on-their-number-with-css3/ > [3] http://andr3.net/blog/post/142 > [4] http://grack.com/assets/2015/01/nth-child/image-count.html > [5] http://dev.w3.org/csswg/css-syntax/#anb > [6] http://bytesizematters.com/ > [7] https://plus.google.com/100749189589213497870/posts/dgz5imd3jDE > [8] https://wordpress.org/support/topic/media-query-breakpoints > [9] http://codepen.io/heydon/pen/bcdrl >
Received on Tuesday, 13 January 2015 22:18:57 UTC