Shnick
Shnick

Reputation: 1391

How to group and style tds in a table row?

I'm trying to "group" a set of cells/<td> elements within a row/<tr> in a <table> so that I can apply styles to them. The below code achieves what I somewhat want to do, but it has some limitations:

/* Styles I'm having issues with */
.row td:not(:first-child) {
  background-color: lightgray;
  /* potentially a box-shadow */
}

.row td:nth-child(2) {
  border-top-left-radius: 10px;
  border-bottom-left-radius: 10px;
}

.row td:last-child {
  border-top-right-radius: 10px;
  border-bottom-right-radius: 10px;
}


/* Base styles for table to make it look decent */
table {
  margin: 0 auto;
  font-size: 20px;
  border-collapse: separate;
  border-spacing: 0 1em; 
}
table td {
  padding: 10px;
}
<table>
  <thead>
    <th>A</th>
    <th>B</th>
    <th>C</th>
    <th>D</th>
  </thead>
  <tbody>
    <tr class="row">
      <td>1</td>
      <td>2</td>
      <td>3</td>
      <td>4</td>
    </tr>
    <tr class="row">
      <td>5</td>
      <td>6</td>
      <td>7</td>
      <td>8</td>
    </tr>
  </tbody>
</table>

The above achives the visual effect I want (minus a box-shadow surrounding the grey box for each group), where the last 3 cells of each row are grouped. But it has a few issues:

  1. This solution of stylying the last three cells involves me having to change the style of each <td>, which means that styling is tedious (eg: I have to style the border radius for each corner, and can't specify just one simple border-radius style for the group).

  2. Stylying the table in this way makes it hard to do things like add cell-spacing between each cell (as it adds a white gap), or to add a box-shadow that surrounds the entire grey box that groups the last three cells (with the above approach, each box-shadow would need to be applied to each <td>, which makes each cell appear as seperate, eg, whereas the desired look for the box-shadow for the group would be like this).

Is there a way that I can group <td>s together so that I can apply my styles hollistically to the group, and not to the individual <td>s? Ideally, I would be able to do something like:

<tr class="row">
  <td>1</td>
  <div class="row-group">
    <td>2</td>
    <td>3</td>
    <td>4</td>
  </div>
</tr>

And then I would apply my border-radius: 10px and background-color: lightgray and box-shadow stylying to the .row-group class. But the HTML spec doesn't allow <div>s within <tr>s and so the above doesn't work. I have also tried looking into <colgroup> and <col> tags, but these seem to apply styles per-column, and don't help me much with applying styles to a group of cells per-row. My only other thought is to use a sub-table, but I'm wondering if there is an easier way that will allow my to "group" and styles these <td>s collectively, maybe I'm missing something and it can be done with <col>s?

Upvotes: 1

Views: 1258

Answers (1)

Alvaro Men&#233;ndez
Alvaro Men&#233;ndez

Reputation: 9012

Posting my comment as an answer as You told me.

Basically we use the :after pseudoelement with the styles You are looking for (rounded grey box) and position it as absolute under your TD's. It will take all row width except the first:child width.

/* Styles I'm having issues with */
tbody tr {position:relative;}
tbody tr:after {
  content:'';
  display:block;
  position:absolute;
  top:0;
  right:0;
  bottom:0;
  left:30px; /*First child width*/
  margin:auto;
  background-color: lightgray;
  border-radius:10px;
}
td {position:relative; z-index:1}
/* Base styles for table to make it look decent */
table {
  margin: 0 auto;
  font-size: 20px;
  border-collapse: separate;
  border-spacing: 0 1em; 
}
table td {
  padding: 10px;
}
<table>
  <thead>
    <th>A</th>
    <th>B</th>
    <th>C</th>
    <th>D</th>
  </thead>
  <tbody>
    <tr class="row">
      <td>1</td>
      <td>2</td>
      <td>3</td>
      <td>4</td>
    </tr>
    <tr class="row">
      <td>5</td>
      <td>6</td>
      <td>7</td>
      <td>8</td>
    </tr>
  </tbody>
</table>

Edited: same snippet but adding a jquery script in case your first-child has a dynamic width:

$(document).ready(function(){
    var tdWidth = $("td:first-child").outerWidth();
  $( "<style>tbody tr:after { left: " + tdWidth + "px; }</style>" ).appendTo( "head" )
});
/* Styles I'm having issues with */
tbody tr {position:relative;}
tbody tr:after {
  content:'';
  display:block;
  position:absolute;
  top:0;
  right:0;
  bottom:0;
  margin:auto;
  background-color: lightgray;
  border-radius:10px;
}
td {position:relative; z-index:1}
/* Base styles for table to make it look decent */
table {
  margin: 0 auto;
  font-size: 20px;
  border-collapse: separate;
  border-spacing: 0 1em; 
}
table td {
  padding: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<table>
  <thead>
    <th>A</th>
    <th>B</th>
    <th>C</th>
    <th>D</th>
  </thead>
  <tbody>
    <tr class="row">
      <td>1111111</td>
      <td>2</td>
      <td>3</td>
      <td>4</td>
    </tr>
    <tr class="row">
      <td>5</td>
      <td>6</td>
      <td>7</td>
      <td>8</td>
    </tr>
  </tbody>
</table>

Upvotes: 1

Related Questions