Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[selectors-4] Grid-structural selectors like :nth-col(): having pseudo-classes for rows e.g. :nth-row() is needed for CSS to cope with tables and rowSpan #8352

Open
DavidJCobb opened this issue Jan 23, 2023 · 5 comments
Labels

Comments

@DavidJCobb
Copy link

The current Selectors 4 draft introduces the :nth-col() and :nth-last-col() selectors, as a way to select grid elements (including table cells) that exist within a given column. However, no similar pseudo-classes exist for rows. The draft justifies this on the grounds that tables and similar grid structures are typically row-major; however, that doesn't account for things like the rowSpan attribute on table cells.

Consider the following table:

<table>
   <tbody>
      <tr>
         <td rowSpan="2"> A </td>
         <td> B </td>
      </tr>
      <tr>
         <td> C </td>
      </tr>
   </tbody>
</table>
<!--
   layout:
   A B
   A C
-->

In this scenario, there is no way to tell that the "A" cell extends to the bottom of the table. Tables are row-major, but we can only tell what row "A" starts in; there's no way to tell what row it ends in. This causes a few problems:

  • Setting a border-radius on a table will round off the table's corners, but not the corners of its corner cells; the cells remain rectangular and are drawn overtop the table's rounded corners. To give a table proper rounded corners, we must set border-top-left-radius and friends on the top-left, top-right, bottom-left, and bottom-right cells. However, we can't reliably identify the bottom-left cell in the above table using selectors alone.
  • Setting border-collapse on a table will prevent you from using border-radius, and may additionally prevent other effects that rely on separated borders to work. In order to work around this, you have to leave the borders separated, and then emulate border-collapse by selectively setting some border widths to zero in order to manually collapse those borders. However, if a cell is rowspanned from a non-bottom row down into the bottom row, you can't reliably detect this, and so you can't collapse its bottom border into the table's bottom border.

Typically, we would detect when a cell is on any edge of the table using the following selectors:

/* Top edge: */
table > :is(thead,tbody,tfoot):first-child > tr:first-child > :is(td,th) {}

/* Bottom edge: */
table > :is(thead,tbody,tfoot):last-child > tr:last-child > :is(td,th) {}

/* Left edge: */
table > :is(thead,tbody,tfoot) > tr > :is(td,th):first-child {}

/* Right edge: */
table > :is(thead,tbody,tfoot) > tr > :is(td,th):last-child {}

The selectors above fail for rowspanned cells, and for cells adjacent to them (i.e. "B" in our example above would wrongly test as a leftmost-column cell).

With the column pseudo-classes introduced in Selectors 4, I believe the syntax would now be:

/* Top edge: */
table > :is(thead,tbody,tfoot):first-child > tr:first-child > :is(td,th) {}

/* Bottom edge: */
table > :is(thead,tbody,tfoot):last-child > tr:last-child > :is(td,th) {}

/* Left edge: */
table   :is(td, th):nth-col(0) {}

/* Right edge: */
table   :is(td, th):nth-last-col(0) {}

This fixes the "B" case; however, the rowspanned "A" cell in our example table above still won't test as being on the bottom edge. We would need :nth-row() and :nth-last-row() counterparts in order to cope with rowSpan.

I offer a more detailed breakdown of use cases, including links to examples, in the issue I originally opened in the WHATWG HTML repo by mistake. Those examples were written before I was aware of the yet-to-be-implemented :nth-col() and :nth-last-col() selectors, but I believe they still adequately demonstrate the utility of row-based selectors.

@johannesodland
Copy link

Maybe related to this issue?
#1943

@tabatkins
Copy link
Member

Nah, unrelated. The grid-structural pseudos are based on language semantics, not CSS layout as #1943 is.

@FremyCompany
Copy link
Contributor

I don't know about this, because elements could have display values changing their semantic, too. Is this suppose to work only for well-formed html tables? If so, this should maybe be specified in html.

@Loirooriol
Copy link
Contributor

Like || and :nth-col(), row membership would be determined based on the semantics of the document language only: whether and how the elements are presented is not considered.

@tabatkins
Copy link
Member

Yup, if you display:none a cell (thus shifting the columns of following cells in the row) that's your problem; the selector won't care.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants