Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Table Row Border - Half In, Half Out

Tags:

html

css

I'm trying to style table with what I thought would be a fairly simple style to achieve but have run in to a little issue.

The table will show a coloured indicator on the left hand side of each row so I'm using border-left: 5px solid red; to add it. However, although the border applies - half of it is inside the row and half outside. I've tried adding border-collapse: collapse to no avail, I'm also using box-sizing: border-box but still have the same issue.

Finally, I've also tried adding the border to the first-child cell (td) but the same issue appears.

I've set up an example of what's happening - I've put in an oversized border to highlight the issue:

http://www.cssdesk.com/TVa67

Has anyone run into this before or have any solutions?

body {
  background: blue;
}
table {
  border-collapse: collapse;
  box-sizing: border-box;
  table-layout: fixed;
  width: 100%;
}
th,
td {
  background-color: #fff;
  padding: 10px 15px 8px;
}
th {
  border-bottom: 1px solid blue;
  font-weight: normal;
  text-align: left;
}
td {
  border-bottom: 1px solid gray;
}
tr.low {
  border-left: 25px solid red;
}
<table style="
    border-collapse: collapse;
">
  <tbody>
    <tr>
      <th>#</th>
      <th>Status</th>
      <th>Title</th>
      <th>Project</th>
      <th>Assigned To</th>
      <th>Age</th>
    </tr>

    <tr class="low">
      <td>1</td>
      <td>New</td>
      <td>This is an example ticket</td>
      <td>Something</td>
      <td>Something</td>
      <td>2 days ago</td>
    </tr>
  </tbody>
</table>
like image 876
0Neji Avatar asked Jul 19 '15 18:07

0Neji


1 Answers

However, although the border applies - half of it is inside the row and half outside

This behaviour is expected and is as per specs. Refer to: http://www.w3.org/TR/CSS2/tables.html#collapsing-borders where it says:

Borders are centered on the grid lines between the cells...

It also illustrates that with a diagram with description.

Has anyone run into this before or have any solutions?

Yes, it can be easily demonstrated as in this fiddle: http://jsfiddle.net/abhitalks/xs7L9wn1/1/ and the below Snippet:

* { box-sizing: border-box; }
table {
    border-collapse: collapse;
    border: 1px solid gray;
    table-layout: fixed; width: 70%; 
    margin: 0 auto;
}
th, td {
    border: 1px solid gray;
    padding: 6px;
    text-align: center;
}
tbody > tr:nth-child(1) > td:first-child { border-left: 16px solid red; }
tbody > tr:nth-child(2) > td:first-child { border-left: 8px solid green; }
tbody > tr:nth-child(3) > td:first-child { border-left: 24px solid blue; }

tbody > tr:nth-child(1) > td:last-child { border-left: 16px solid red; }
tbody > tr:nth-child(2) > td:last-child { border-left: 8px solid green; }
tbody > tr:nth-child(3) > td:last-child { border-left: 24px solid blue; }
<table>
    <thead>
        <tr>
            <th>#</th>
            <th>Header 1</th>
            <th>Header 2</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>1</td>
            <td>Caption</td>
            <td>Description</td>
        </tr>
        <tr>
            <td>2</td>
            <td>Caption</td>
            <td>Description</td>
        </tr>
        <tr>
            <td>3</td>
            <td>Caption</td>
            <td>Description</td>
        </tr>
    </tbody>
</table>

Solution:

Just add a transparent border of the same width to all rows. That way the border-width will be same and it will neatly align. (Update: added a white border-left to first column to hide the hanging border on highlighted cell. As pointed out by your comment.)

th, td { border-left: 15px solid transparent; }
tr > td:first-child, tr > th:first-child { border-left: 5px solid #fff; }
tr.low > td:first-child { border-left: 5px solid red; }

Example Fiddle: https://jsfiddle.net/abhitalks/s9taanz7/5/

Snippet:

* { box-sizing: border-box; }
body { background-color: blue; }
table {
    border-collapse: collapse;
    table-layout: fixed; width: 100%;
}
th, td {
    background-color: #fff;
    padding: 10px 15px 8px 8px;
    border-left: 5px solid transparent;
    border-bottom: 1px solid gray;  
}
th {
    border-bottom: 1px solid blue;
    font-weight: normal; text-align: left;
}
tr > td:first-child, tr > th:first-child { border-left: 10px solid #fff; }
tr.low > td:first-child { border-left: 10px solid red; }
<table>
	<thead>
		<tr>
			<th>#</th>
			<th>Status</th>
			<th>Title</th>
			<th>Project</th>
			<th>Assigned To</th>
			<th>Age</th>
		</tr>
	</thead>
	<tbody>
		<tr class="">
			<td>1</td>
			<td>New</td>
			<td>This is an example ticket</td>
			<td>Something</td>
			<td>Something</td>
			<td>2 days ago</td>
		</tr>
		<tr class="low">
			<td>2</td>
			<td>New</td>
			<td>This is an example ticket</td>
			<td>Something</td>
			<td>Something</td>
			<td>2 days ago</td>
		</tr>
		<tr class="">
			<td>3</td>
			<td>New</td>
			<td>This is an example ticket</td>
			<td>Something</td>
			<td>Something</td>
			<td>2 days ago</td>
		</tr>
	</tbody>
</table>

However, this approach will have a side-effect of hidden border-bottom because the border-left overlaps it.


Solution 2:

You could have an extra cell on the left to use as indicator. You can then control this by use of colgroup. This approach is neater than above and also requires you to have the width specified only once in css.

Example Fiddle 2: http://jsfiddle.net/abhitalks/z7u1nhwt/1/

Snippet 2:

* { box-sizing: border-box; }
body { background-color: blue; }
table {
    border-collapse: collapse;
    table-layout: fixed; width: 100%;
}
th, td {
    background-color: #fff;
    padding: 10px 15px 8px 8px;
    border-bottom: 1px solid gray;  
}
th {
    border-bottom: 1px solid blue;
    font-weight: normal; text-align: left;
}
.col1 { width: 10px; }
tr.low > td:first-child {
    background-color: #f00;
}
<table>
	<colgroup>
        <col class="col1" />
        <col class="coln" span="6" />
	</colgroup>
	<thead>
		<tr>
			<th></th>
			<th>#</th>
			<th>Status</th>
			<th>Title</th>
			<th>Project</th>
			<th>Assigned To</th>
			<th>Age</th>
		</tr>
	</thead>
	<tbody>
		<tr class="">
			<td></td>
			<td>1</td>
			<td>New</td>
			<td>This is an example ticket</td>
			<td>Something</td>
			<td>Something</td>
			<td>2 days ago</td>
		</tr>
		<tr class="low">
			<td></td>
			<td>2</td>
			<td>New</td>
			<td>This is an example ticket</td>
			<td>Something</td>
			<td>Something</td>
			<td>2 days ago</td>
		</tr>
		<tr class="">
			<td></td>
			<td>3</td>
			<td>New</td>
			<td>This is an example ticket</td>
			<td>Something</td>
			<td>Something</td>
			<td>2 days ago</td>
		</tr>
	</tbody>
</table>

And of course, you can also try the approach of using pseudo-element as proposed by @misterManSam, depending on ease of implementation for you.

like image 160
Abhitalks Avatar answered Oct 14 '22 05:10

Abhitalks