w3c / w3c/csswg-drafts

[selectors-5] 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

Open
#8,352 6 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

selectors-5
Dominant language
Bikeshed
Stars
4.9k
Forks
816
PR merge metrics
PR metrics pending

Description

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.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading this issue's examples and the linked WHATWG HTML issue 8772, then review the Selectors 4 draft's :nth-col() and :nth-last-col() definitions. Compare the rowSpan cases and determine the required row-based selector behavior. Done means the CSSWG has an agreed specification direction for row selectors and their interaction with table layout.

Written by the indexing model from the issue text.

Assessment

Tech stack
css
Domain
frontend, web-dev
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.