How to put spacing between TBODY elements
Asked Answered
F

13

116

I have a table like this:

<table>
    <tfoot>
        <tr><td>footer</td></tr>
    </tfoot>
    <tbody>
        <tr><td>Body 1</td></tr>
        <tr><td>Body 1</td></tr>
        <tr><td>Body 1</td></tr>
    </tbody>
    <tbody>
        <tr><td>Body 2</td></tr>
        <tr><td>Body 2</td></tr>
        <tr><td>Body 2</td></tr>
    </tbody>
    <tbody>
        <tr><td>Body 3</td></tr>
        <tr><td>Body 3</td></tr>
        <tr><td>Body 3</td></tr>
    </tbody>
</table>

I'd like to put some spacing between each tbody element, but padding and margin have no effect. Any ideas?

Feigin answered 17/11, 2008 at 4:29 Comment(2)
Is is right to repeat 'tbody' tags? What I have seen always is all the "<tr>..</tr>" are inside a single "tbody' tag.Ambiguity
Yes this is valid. The spec says: <!ELEMENT TABLE - - (CAPTION?, (COL*|COLGROUP*), THEAD?, TFOOT?, TBODY+)> meaning that there has to be one or more tbodies. w3.org/TR/html4/struct/tables.html#h-11.2.1Feigin
H
65

Try this, if you don't mind not having borders.

<style>
table {
  border-collapse: collapse;
}

table tbody {
  border-top: 15px solid white;
}
</style>

<table>
    <tfoot>
        <tr><td>footer</td></tr>
    </tfoot>
    <tbody>
        <tr><td>Body 1</td></tr>
        <tr><td>Body 1</td></tr>
        <tr><td>Body 1</td></tr>
    </tbody>
    <tbody>
        <tr><td>Body 2</td></tr>
        <tr><td>Body 2</td></tr>
        <tr><td>Body 2</td></tr>
    </tbody>
    <tbody>
        <tr><td>Body 3</td></tr>
        <tr><td>Body 3</td></tr>
        <tr><td>Body 3</td></tr>
    </tbody>
</table>
Halfhardy answered 17/11, 2008 at 4:31 Comment(3)
Try border-top: 15px solid transparent;Framboise
Wanted to stress this. Use transparent as the border color. What @SteveAlmond said.Lissotrichous
if the table/tbody/tr/td has a background-color, setting the border color to transparent will give it the background-color of the element, essentially indisinguishable from the element's body. You would need to explicitly color the border the color you want it to appear as (to make it supposedly invisible)Brittanybritte
A
104

Something like this will work, depending on your browser support requirements:

tbody::before
{
  content: '';
  display: block;
  height: 15px;

}
Anagrammatize answered 26/5, 2012 at 0:3 Comment(4)
This is the only solution that works when your cells have a background that the space should not have.Selda
This worked well for me. Are there any drawbacks? Also, why two colons?Undersexed
@nh2: double-colons are for pseudo-content and single-colon is for pseudo-selectors. It's an update to the CSS syntax. Everything used to just use the single colon. Older browsers don't support double colon (like, IE <=8).Widgeon
Isn't it safer to use display: table-row;?Phage
H
65

Try this, if you don't mind not having borders.

<style>
table {
  border-collapse: collapse;
}

table tbody {
  border-top: 15px solid white;
}
</style>

<table>
    <tfoot>
        <tr><td>footer</td></tr>
    </tfoot>
    <tbody>
        <tr><td>Body 1</td></tr>
        <tr><td>Body 1</td></tr>
        <tr><td>Body 1</td></tr>
    </tbody>
    <tbody>
        <tr><td>Body 2</td></tr>
        <tr><td>Body 2</td></tr>
        <tr><td>Body 2</td></tr>
    </tbody>
    <tbody>
        <tr><td>Body 3</td></tr>
        <tr><td>Body 3</td></tr>
        <tr><td>Body 3</td></tr>
    </tbody>
</table>
Halfhardy answered 17/11, 2008 at 4:31 Comment(3)
Try border-top: 15px solid transparent;Framboise
Wanted to stress this. Use transparent as the border color. What @SteveAlmond said.Lissotrichous
if the table/tbody/tr/td has a background-color, setting the border color to transparent will give it the background-color of the element, essentially indisinguishable from the element's body. You would need to explicitly color the border the color you want it to appear as (to make it supposedly invisible)Brittanybritte
D
27

People will always have controversial opinions about using empty table elements to layout a page (as evidenced by this answer's downvote). I recognize this, but sometimes its easier to use them this way when you are working in a "quick and dirty" way.

I've used empty rows in past projects to space groups of table rows. I assigned the spacer rows a css class of their own and defined a height for that class that acted as a top and bottom margin for that group of table rows.

    .separator{
             height: 50px;
    }

   <table>
           <tr><td>Cell 1</td><td>Cell 2</td></tr>
           <tr><td>Cell 1</td><td>Cell 2</td></tr>
           <tr><td>Cell 1</td><td>Cell 2</td></tr>

           <tr class="separator" colspan="2"></tr>

           <tr><td>Cell 1</td><td>Cell 2</td></tr>
           <tr><td>Cell 1</td><td>Cell 2</td></tr>
           <tr><td>Cell 1</td><td>Cell 2</td></tr>

           <tr class="separator" colspan="2"></tr>

           tr><td>Cell 1</td><td>Cell 2</td></tr>
           <tr><td>Cell 1</td><td>Cell 2</td></tr>
           <tr><td>Cell 1</td><td>Cell 2</td></tr>
   </table>

If you don't have borders on your table cells, you could also define a height to your typical cell or row in your style sheet that evenly spaces out all rows of your table.

tr{
   height: 40px;
}
Dearing answered 17/11, 2008 at 18:0 Comment(5)
well if you're going to be adding extra markup, why not just put a class on the first row of each tbody?Feigin
Well, that could be because the rows are generated code, and adding a separate row in the markup might be more maintainable than creating a special case for the first row of generated content.Denten
Downvote all you want, but this is the only solution without drawbacks -- and even if it does violate seperation, an empty row isn't that big of a deal IMO.Hydropathy
Without drawbacks, my butt! Try using a screenreader on this and notice the incorrect row counts. Better yet, try copying and pasting the table into a spreadsheet. You'll be reformatting for hours if you have a lot of content. Tables are meant to display data (and be extremely accessible), not shim presentation between sections.Bayern
It's only visual. Keep in mind that html are also documents that can be processed, therefore content inside them should be well formatted. As mentioned above, copy-paste table or usage of screen reader will just fail. Such design should not be encouraged. ::content solution is better cause it does not mess up the markup.Scotch
S
21

I had been having trouble with cross-browser support for spacing multiple <tbody>'s using the ::before pseudo-selector if any <td>'s had a rowspan.

Basically, if your <tbody> is structured like this:

<tbody>
    <tr>
        <td>td 1</td>
        <td rowspan"2">td 2</td>
        <td>td 3</td>
        <td>td 4</td>
    </tr>
    <tr>
        <td>td 1</td>
        <td>td 2</td>
        <td>td 4</td>
    </tr>
</tbody>

...and your ::before pseudo-selector displays the content as a block like this:

tbody::before
{
    content: '';
    display: block;
    height: 10px;
}

...then this will cause the table to cut off any columns that use rowspan.

The solution is to style ::before pseudo as a table-row:

tbody::before
{
    content: '';
    display: table-row;
    height: 10px;
}

This should have good cross-browser support.

Here's a fiddle

Stratopause answered 15/9, 2015 at 13:6 Comment(2)
Looking at the Fiddle, I see no differences between the 2 options. In which browsers did you have issues with this?Mcdonnell
7 years have passed, I think the noticeable differences in the fiddle have now been overcome by the updates of the internal engines of the browsers.Stratopause
H
10

Here's another possibility that relies on :first-child which is not available in all browsers:

<style>
table {
  border-collapse: collapse;
}

td {
  border: 1px solid black;
}

tbody tr:first-child td {
  padding-top: 15px;
}

</style>

<table>
    <tfoot>
        <tr><td>footer</td></tr>
    </tfoot>
    <tbody>
        <tr><td>Body 1</td></tr>
        <tr><td>Body 1</td></tr>
        <tr><td>Body 1</td></tr>
    </tbody>
    <tbody>
        <tr><td>Body 2</td></tr>
        <tr><td>Body 2</td></tr>
        <tr><td>Body 2</td></tr>
    </tbody>
    <tbody>
        <tr><td>Body 3</td></tr>
        <tr><td>Body 3</td></tr>
        <tr><td>Body 3</td></tr>
    </tbody>
</table>
Halfhardy answered 17/11, 2008 at 5:9 Comment(2)
This one won't work very well if you have anything that happens to rely on the position of the content relative to the size of the cell, like box-shadow, background images, or pretty much anything else.Hydropathy
Just to clarify for others finding this answer on google, I presume as this was written in 2008, this answer now (2015) has full support across all major browsers? At least checking on caniuse.com first-child seems well supported?Proportionable
D
4

Of all of the answers given above, only djenson47's answers retain separation of presentation and content. The drawback of the collapsed border model method is that you can no longer use the table's border or cellspacing attributes to separate the individual cells. You could argue that this is a good thing, and there are some workarounds, but it can be a pain. So I think the first-child method is the most elegant.

Alternatively, you could also set your TBODY class' overflow property to anything other than "visible." This method allows you to retain a separated borders model as well:

<style>
tbody {
    overflow: auto;
    border-top: 1px solid transparent;
}
</style>
<table>
    <tfoot>
        <tr><td>footer</td></tr>
    </tfoot>
    <tbody>
        <tr><td>Body 1</td></tr>
        <tr><td>Body 1</td></tr>
        <tr><td>Body 1</td></tr>
    </tbody>
    <tbody>
        <tr><td>Body 2</td></tr>
        <tr><td>Body 2</td></tr>
        <tr><td>Body 2</td></tr>
    </tbody>
    <tbody>
        <tr><td>Body 3</td></tr>
        <tr><td>Body 3</td></tr>
        <tr><td>Body 3</td></tr>
    </tbody>
</table>
Delagarza answered 2/4, 2009 at 6:36 Comment(2)
I was looking to do something similar, this is perfect for meMenam
It seems like this doesn't work, I tried using a 50px border-top and nothing happened: jsfiddle.net/stramin/zrsq0dmkGuardant
B
4

You can use border-spacing in a table with table row groups to add a space between those groups. Though, I don't think there is a way to specify which groups are spaced and which are not.

<table>
  <thead>
    ...
  </head>
  <tbody>
    ...
  </tbody>
  <tbody>
    ...
  </tbody>
  <tfoot>
    ...
  </tfoot>
</table>

CSS

table {
  border-spacing: 0px 10px; /* h-spacing v-spacing */
}
Bechler answered 15/12, 2012 at 19:7 Comment(0)
S
4

Just set display as block and it will work.

table tbody{
    display:block;
    margin-bottom:10px;
    border-radius: 5px;
}
Sidney answered 15/5, 2014 at 15:26 Comment(2)
this answer should be the accepted answer because is the only one that allows to use a bordered tbody with "no-border" columns.Hammered
display:block breaks the column alignment between tbody elements. You no longer get the benefit of the table layout engineExtravagant
D
4

Because padding can be applied to TD's, you can do a trick with the + sign. Then it will be possible to give a top padding to the TD's of the first TR of a tbody:

// The first row will have a top padding
table tbody + tbody tr td {
    padding-top: 20px;
}

// The rest of the rows should not have a padding
table tbody + tbody tr + tr td {
    padding-top: 0px;
}

I have added the "tbody + tbody" so the first tbody won't have a top padding. However, it's not required.

As far as I know there are no drawbacks :), though didn't test the older browsers.

Divebomb answered 11/7, 2014 at 11:0 Comment(0)
B
0

NEW ANSWER

You can use as many <tbody> tags as you like. I didn't realize that was ok by W3C until now. Not to say my below solution doesn't work (it does), but to do what you're trying to do, assign your <tbody> tags classes and then reference their individual <td> tags through CSS like so:

table tbody.yourClass td {
    padding: 10px;
}

and your HTML thusly:

<table> 
<tbody>
<tr><td>Text</td></tr>
<tr><td>Text</td></tr>
<tr><td>Text</td></tr>
</tbody>
<tbody class="yourClass">    
<tr><td>Text</td></tr>
<tr><td>Text</td></tr>
<tr><td>Text</td></tr>
</tbody>
<tbody>
<tr><td>Text</td></tr>
<tr><td>Text</td></tr>
<tr><td>Text</td></tr>
</tbody>
</table>

Try that guy out :)

OLD ANSWER

whatever you do, DON'T insert blank rows...

you shouldn't have more than 1 tbody element in your table. what you can do is set the class or id attribute in your <tr> elements and give their corresponding <td> tags padding:

table {
    border-collapse: collapse;
}

tr.yourClass td {
    padding: 10px;
}

You can even assign the top and bottom <tr>'s an additional class so that they only do top or bottom padding, respectively:

tr.yourClass.topClass td {
    padding: 10px 0 0 0;
}

tr.yourClass.bottomClass td {
    padding: 0 0 10px 0;
}

and in your HTML, your <tr> tag would look like this:

<table> 
<tbody>
<tr><td>Text</td></tr>
<tr><td>Text</td></tr>
<tr><td>Text</td></tr>
<tr class="yourClass topClass"><td>Text</td></tr>
<tr class="yourClass"><td>Text</td></tr>
<tr class="yourClass bottomClass"><td>Text</td></tr>
<tr><td>Text</td></tr>
<tr><td>Text</td></tr>
<tr><td>Text</td></tr>
</tbody>
</table>

Hope this helps!

Bayern answered 2/4, 2009 at 6:51 Comment(0)
B
0

djensen47 answer works great for newer browsers, however, as it was pointed out, IE7 it does not work in.

My workaround for this issue to support the older browsers was to wrap each cells contents inside a div. Then add a margin-top to the div.

<table class="tbl">
<tr></tr>
<tr></tr>
<tr></tr>
<tr><td><div></div></td></tr>
</table>

CSS

.tbl tr td div {
    height:30px;
    margin-top:20px;
}

The height setting keeps the cells at least 30px high to prevent any cell coloring used inside the div from collapsing around the text. The margin-top creates the desired space by making the entire row taller.

Begay answered 13/9, 2013 at 19:23 Comment(0)
T
0

Came across this while trying to solve it myself. I had success with putting a <br> tag right before the closing </tbody> tag. It is a purely visual fix, but seems to work on most browsers I tested.

<table>
    <tbody>
        <tr>
            <td></td>
        </tr>
        <br>
    </tbody>
    <tbody>
        <tr>
            <td></td>
        </tr>
    </tbody>
</table>

Should be accessible as well.

Thirtytwomo answered 10/5, 2019 at 14:58 Comment(0)
A
0

With credit to everyone else who answered first ...

table {
  border-collapse: collapse;
  table-layout: fixed;
  width: 50%;
}
tbody:before {
  content: "";
  display:block;
  border-top: 15px solid white;
}
tbody tr {
  border-color: #000;
  border-style: solid;
}
tbody tr:first-of-type{
  border-width: 2px 2px 0 2px;
}
tbody tr:nth-of-type(1n+2){
  border-width: 0 2px 0 2px;
}
tbody tr:last-of-type{
  border-width: 0 2px 2px 2px;
}
tbody tr:nth-child(odd) {
  background-color: #ccc;
}
tbody tr:hover {
  background-color: #eee;
}
td {
  text-align: right;
}
<table>
  <tbody>
    <tr>
      <th colspan="3">One</th>
    </tr>
    <tr>
      <td>1</td>
      <td>2</td>
      <td>3</td>
    </tr>
    <tr>
      <td>1</td>
      <td>2</td>
      <td>3</td>
    </tr>
    <tr>
      <td>1</td>
      <td>2</td>
      <td>3</td>
    </tr>
    <tr>
      <td>1</td>
      <td>2</td>
      <td>3</td>
    </tr>
  </tbody>
  <tbody>
    <tr>
      <th colspan="3">Two</th>
    </tr>
    <tr>
      <td>1</td>
      <td>2</td>
      <td>3</td>
    </tr>
    <tr>
      <td>1</td>
      <td>2</td>
      <td>3</td>
    </tr>
    <tr>
      <td>1</td>
      <td>2</td>
      <td>3</td>
    </tr>
    <tr>
      <td>1</td>
      <td>2</td>
      <td>3</td>
    </tr>
  </tbody>
</table>
Allottee answered 29/10, 2020 at 13:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.