简体   繁体   中英

How can I apply styling to only first <tr> in a table, regardless of the <tbody> element?

I have a table which contains multiple tbody elements — some created by the browser, and some that I have written in myself for programmatic reasons. I want to apply styling to only the first tr within my table, which I would normally use table > tr for. However, my styling cannot assume that a tbody element does or does not exist, because I don't know that every user's browser is adding in tbody elements automatically in every case.

As you can see, an unwanted border styling is applied to the first tr within the second tbody of this table. How can I get this to be applied to only the first tr in my table without regards to the presence of a tbody tag?

带有不必要样式的Tr

JSFiddle demo

CSS

.my-table {
    border-collapse: collapse;
}
    .my-table td,
    .my-table th {
        text-align: left;
        padding: 6px 8px;
        align-content: center;
        box-sizing: border-box;
    } 
    .my-table td[colspan="42"] {
      text-align: center;
      background-color: lightgray;
    }
    .my-table th {
        padding-top: 12px;
        padding-bottom: 12px;
        background-color: #0e3e64;
        color: white;
        text-align: center;
    }
    .my-table tr:not(:first-child) {
        border: 1px solid #efefef;
    }

    /*here's the styling I don't want applied to that third tr in my table*/
    .my-table tr:first-child {
        border: 1px solid #0e3e64;
    }

HTML

<table class="my-table">
  <tr>
    <th>Column 1</th>
    <th>Column 2</th>
    <th>Column 3</th>
  </tr>
  <tr>
    <td colspan="42">Section 1</td>
  </tr>
  <tr>
    <td>Cell 1</td>
    <td>Cell 2</td>
    <td>Cell 3</td>
  </tr>
  <tbody>
    <tr>
      <td colspan="42">Section 2</td>
    </tr>
    <tr>
      <td>Cell 1</td>
      <td>Cell 2</td>
      <td>Cell 3</td>
    </tr>      
  </tbody>
</table>

Unfortunately in your case, CSS does not provide a "first occurrence on page", nor a "first occurrence within parent" selector that ignores immediate-parent. As CSS stands for Cascading Style Sheets, it doesn't exactly fit within the inherent functionality of the language - default behavior is directly related to parent elements, rather than an entire page.

If your table was always going to have a tbody , you could do the following:

.my-table tbody:first-of-type tr:first-child { ... }

Though, if you truly wanted to select the first occurrence of a <tr> within .my-table , you'd need a JavaScript solution. For this, I'd suggest jQuery, simply because it makes DOM/element manipulation much simpler:

$(".my-table tr").first().css("border", "1px solid #0e3e64");

EDIT: As torazaburo mentions in the comments, the second portion of this answer isn't exactly necessary. Regardless of whether or not a tbody is declared, the browser will automatically insert one into all <table> elements. For this reason, selecting "first row of first tbody" should be a sufficient solution in all cases.

A good method is to use additional classes:

css :

/* Custom CSS class */
tr .custom {
color: #ff0000;
}

html :

<tr class="custom"><th>Column 1</th></tr>

Note, you can add this to existing class as <tr class="otherCls custom">

You can assign a specific "id" to your third tr and use it in the css.

<style>
.my-table {
    border-collapse: collapse;
}
    .my-table td,
    .my-table th {
        text-align: left;
        padding: 6px 8px;
        align-content: center;
        box-sizing: border-box;
    } 
    .my-table td[colspan="42"] {
      text-align: center;
      background-color: lightgray;
    }
    .my-table th {
        padding-top: 12px;
        padding-bottom: 12px;
        background-color: #0e3e64;
        color: white;
        text-align: center;
    }
    .my-table tr:not(:first-child) {
        border: 1px solid #efefef;
    }

    /*here's the styling I don't want applied to that third tr in my table*/
    #third{
        border: 5px solid #0e3e64;
    }
</style>
</head>
<body>
<table class="my-table">
  <tr>
    <th>Column 1</th>
    <th>Column 2</th>
    <th>Column 3</th>
  </tr>
  <tr>
    <td colspan="42">Section 1</td>
  </tr>
  <tr>
    <td>Cell 1</td>
    <td>Cell 2</td>
    <td>Cell 3</td>
  </tr>
  <tbody>
    <tr>
      <td colspan="42">Section 2</td>
    </tr>
    <tr id="third">
      <td>Cell 1</td>
      <td>Cell 2</td>
      <td>Cell 3</td>
    </tr>      
  </tbody>
</table>
</body>
</html>

As @Santi stated in his answer, what I'm asking for isn't really possible with raw CSS, because table tr:first-child doesn't translate as "first tr within table", it translates more like "first tr within its parent element within table", which may be the table itself, or it may be tbody or thead .

His answer works perfectly fine, but for those reading this who don't want to use JavaScript, I'll share what solution I'm going to use.

I'm just going to explicitly surround the header row in each of my tables with a thead wrapper, and change my problematic styling code to look like this:

.my-table > thead > tr:first-child {
    border: 1px solid #0e3e64;
}

It still requires me to manually change old tables, but it doesn't require me to worry about multiple occurrences of tbody elements.

According to this post , any browser worth their salt will insert a <tbody> into a <table> , and according to this :

8.2.5.4.9 The "in table" insertion mode ...

A start tag whose tag name is one of: "td", "th", "tr"

Act as if a start tag token with the tag name "tbody" had been seen, then reprocess the current token.

Coincides with that default behavior. Can you show us any example of which this doesn't happen? So using:

 .my-table tbody:first-of-type tr:first-of-type { ... } 

or

 .my-table tbody:first-of-type tr:first-child { ... } 

wouldn't work?

This Snippet shows a basic <table> with <tr> please review it in different browsers and the result in console should report the same:

SNIPPET

 var row = document.querySelector('tr'); console.log(row.parentNode.nodeName); 
 <table> <tr></tr> </table> 

Ok, here you are. Style only applied to the first tr child no matter if you have <thead> , <tbody> , both or none:

 table { width: 200px; height: 400px; } thead { height: 100px; } tr { background-color: grey; height: 100px; } table > :nth-child(1) > tr:nth-of-type(1) { background-color: red; } 
 <body> Head and body <table> <thead> <tr><td>Head</td></tr> </thead> <tbody> <tr><td>Body</td></tr> <tr><td></td></tr> <tr><td></td></tr> </tbody> </table> No head <table> <tr><td></td></tr> <tr><td></td></tr> <tr><td></td></tr> <tr><td></td></tr> </table> </body> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM