Unwanted shifting using fixed column and rowspan in table - html

I have a table that uses rowspan for one of the table headers. This table also switches to a fixed column style on smaller sizes. The issue I'm running into is on smaller sizes, when the th with the rowspan becomes fixed, it messes up the structure of the remaning th.
A solution I thought of was to just have an empty th above Foods so I didn't have to use a rowspan, but due to ADA requirments, that's not an option.
Here's some code: CODEPEN
This is the large screen view - you can see there's a Foods column as well as two groups, each of which containing two columns.
Here's a view of when it goes to the fixed column layout. You can see that Group 1 - Col 1 now takes the place where Foods used to be, and the entire 2nd shifted.
HTML:
<div class="wrap">
<table>
<thead>
<tr>
<th rowspan="2" class="fixed">Foods</th>
<th colspan="2">Group 1</th>
<th colspan="2">Group 2</th>
</tr>
<tr>
<th>Col 1</th>
<th>Col 2</th>
<th>Col 3</th>
<th>Col 4</th>
</tr>
</thead>
<tbody>
<tr>
<td class="fixed">Tacos</td>
<td>blank</td>
<td>blank</td>
<td>blank</td>
<td>blank</td>
</tr>
<tr>
<td class="fixed">Pizza</td>
<td>blank</td>
<td>blank</td>
<td>blank</td>
<td>blank</td>
</tr>
</tbody>
</table>
</div>
CSS:
table {
border: solid 1px black;
border-spacing: 0;
border-collapse: collapse;
width: 900px;
}
th {
vertical-align: bottom;
padding: 5px 10px;
border-left: solid 1px grey;
}
th[colspan="2"] {
border-bottom: solid 1px grey;
}
td {
border-top: solid 1px grey;
}
tbody tr:nth-child(odd) td {
background: grey;
}
.fixed {
border-left: none;
}
#media (max-width: 600px) {
.fixed {
position: absolute;
width: 50px;
left: 0;
}
.wrap {
overflow-x: scroll;
overflow-y: visible;
margin-left: 50px;
}
}

I am not really sure about the issue but it seems to be related to the use of position:fixed. You are removing the elements from the flow so it's like they no more belong to the table making the table algorithm behave strange.
An idea of fix is to consider a extra element that you make visible on small screen to avoid this issue. Basically this element will correct the table layout when you make some of the element position:fixed
* {
text-align: center;
font-weight: normal;
}
table {
border: solid 1px black;
border-spacing: 0;
border-collapse: collapse;
width: 900px;
}
th {
vertical-align: bottom;
padding: 5px 10px;
border-left: solid 1px grey;
}
th[colspan="2"] {
border-bottom: solid 1px grey;
}
td {
border-top: solid 1px grey;
}
tbody tr:nth-child(odd) td {
background: grey;
}
.fixed {
border-left: none;
}
.fix {
padding:0;
border:none;
}
#media (min-width:700px) {
.fix {
display:none;
}
}
#media (max-width: 700px) {
.fixed {
position: absolute;
width: 50px;
left: 0;
}
.wrap {
overflow-x: scroll;
overflow-y: visible;
margin-left: 50px;
}
}
<div class="wrap">
<table>
<thead>
<tr>
<th rowspan="2" class="fixed">Foods</th>
<th colspan="2">Group 1</th>
<th colspan="2">Group 2</th>
</tr>
<tr>
<th class="fix"></th>
<th>Col 1</th>
<th>Col 2</th>
<th>Col 3</th>
<th>Col 4</th>
</tr>
</thead>
<tbody>
<tr>
<td class="fixed">Tacos</td>
<td>blank</td>
<td>blank</td>
<td>blank</td>
<td>blank</td>
</tr>
<tr>
<td class="fixed">Pizza</td>
<td>blank</td>
<td>blank</td>
<td>blank</td>
<td>blank</td>
</tr>
</tbody>
</table>
</div>
To avoid extra element you can consider pseudo element:
* {
text-align: center;
font-weight: normal;
}
table {
border: solid 1px black;
border-spacing: 0;
border-collapse: collapse;
width: 900px;
}
th {
vertical-align: bottom;
padding: 5px 10px;
border-left: solid 1px grey;
}
th[colspan="2"] {
border-bottom: solid 1px grey;
}
td {
border-top: solid 1px grey;
}
tbody tr:nth-child(odd) td {
background: grey;
}
.fixed {
border-left: none;
}
thead > tr:last-child::before {
content:"";
display:table-cell;
padding:0;
border:none;
}
#media (min-width:700px) {
thead > tr:last-child::before {
display:none;
}
}
#media (max-width: 700px) {
.fixed {
position: absolute;
width: 50px;
left: 0;
}
.wrap {
overflow-x: scroll;
overflow-y: visible;
margin-left: 50px;
}
}
<div class="wrap">
<table>
<thead>
<tr>
<th rowspan="2" class="fixed">Foods</th>
<th colspan="2">Group 1</th>
<th colspan="2">Group 2</th>
</tr>
<tr>
<th>Col 1</th>
<th>Col 2</th>
<th>Col 3</th>
<th>Col 4</th>
</tr>
</thead>
<tbody>
<tr>
<td class="fixed">Tacos</td>
<td>blank</td>
<td>blank</td>
<td>blank</td>
<td>blank</td>
</tr>
<tr>
<td class="fixed">Pizza</td>
<td>blank</td>
<td>blank</td>
<td>blank</td>
<td>blank</td>
</tr>
</tbody>
</table>
</div>

Related

fixed column tables are getting border issue with horizontal scrolling

The border disappears when scrolling. I want the border to appear. How can I do this? Or how can I start the scroll only from the scrolled part?
HTML - Table Structure
<div class="wrapper">
<table>
<thead>
<th class='fix'>Fixed</th>
<th>Col 1</th>
<th>Col 2</th>
<th>Col 3</th>
<th>Col 4</th>
<th>Col 5</th>
<th class='fix'>Fixed</th>
</thead>
<tbody>
<tr>
<td class='fix'>First Content</td>
<td>A1</td>
<td>A2 (with longer content)</td>
<td>A3</td>
<td>A4</td>
<td>A5</td>
<td class='fix'>Last Content</td>
</tr>
</tbody>
</table>
</div>
CSS - Table CSS
.wrapper {
overflow-x:scroll;
width:100%;
}
table {
table-layout: fixed;
width: 100%;
border-collapse: collapse;
background: white;
}
thead {
font-family: arial
}
tr {
border-bottom: 1px solid #ccc;
}
td, th {
vertical-align: top;
text-align: left;
width:100px;
padding: 5px;
border: 1px solid red;
}
.fix {
position:sticky;
background: white;
}
.fix:first-child {
left:0;
width:120px;
}
.fix:last-child {
right:0;
width:120px;
}
Play with code: https://jsbin.com/marezen/1/edit?html,css,output
In order to have fixed table borders you need to:
remove border-collapse from css
table {
table-layout: fixed;
width: 100%;
/*border-collapse: collapse;*/
background: white;
}
Also add cellspacing="0" to remove the cellspacing
<table cellspacing="0">
for having same borders like your example, combined with my solution:
CSS-
.wrapper {
overflow-x:scroll;
width:100%;
}
table {
table-layout: fixed;
width: 100%;
/* border-collapse: collapse; */
background: white;
border-top:1px solid red;
/* border-left:1px solid red; */
}
thead {
font-family: arial
}
tr {
/* border-bottom: 1px solid #ccc; */
}
td, th {
vertical-align: top;
text-align: left;
width:100px;
padding: 5px;
/* border: 1px solid red; */
border-right:1px solid red;
border-bottom:1px solid red;
}
.fix {
position:sticky;
background: white;
border-left:1px solid red;
}
.fix:first-child {
left:0;
width:120px;
}
.fix:last-child {
right:0;
width:120px;
}
td:nth-child(6),
th:nth-child(6){
border-right:none;
}
HTML-
<div class="wrapper">
<table cellspacing="0">
<thead>
<th class='fix'>Fixed</th>
<th>Col 1</th>
<th>Col 2</th>
<th>Col 3</th>
<th>Col 4</th>
<th>Col 5</th>
<th class='fix'>Fixed</th>
</thead>
<tbody>
<tr>
<td class='fix'>First Content</td>
<td>A1</td>
<td>A2 (with longer content)</td>
<td>A3</td>
<td>A4</td>
<td>A5</td>
<td class='fix'>Last Content</td>
</tr>
<tr>
<td class='fix'>First Content (with longer content)</td>
<td>B1</td>
<td>B2</td>
<td>B3</td>
<td>B4</td>
<td>B5</td>
<td class='fix'>Last Content</td>
</tr>
<tr>
<td class='fix'>First Content</td>
<td>C1</td>
<td>C2</td>
<td>C3</td>
<td>C4</td>
<td>C5</td>
<td class='fix'>Last Content (with longer content)</td>
</tr>
</tbody>
</table>
</div>
The solution is to add border-left to the wrapper. Then I removed the border property from td, tr and instead added border selection to them like border-top in order to remove the wrapper's border overlapping those borders.
https://jsbin.com/niluyefacu/edit?html,css,output

How to add scrollbar only to tbody and not fixed thead

I am trying to create a table that has a scrollable <tbody> with a fixed <thead>. I have achieved that here https://jsfiddle.net/ghnfzwm6/16/.
However, this is not quite what I would like. I want the scroll bar to start where the <tbody> starts. I have attempted to do so by adding
height: 546px;
max-height: 546px;
overflow-y: scroll; /* only Y axis scroll */
to <tbody> and removing it from #tasks-table-wrapper. I also made <tbody> and <tr> display: block;
Here is the result https://jsfiddle.net/4gLwp697/3/. The problem now is that <thead> does not line up with <tbody>. I can fix that by specifying column widths, but I want them to be auto.
How can I fix this?
consider this code snippet, There is no direct solution to your problem, This is determined by the 'table' feature. The solutions for the current mainstream frameworks are as follows, You need to set the width of 'columns'.
* {
margin: 0;
padding: 0;
}
#content {
overflow: hidden;
height: 100%;
text-align: center;
}
#tasks-table-wrapper {
text-align: left;
display: inline-block;
width: auto;
}
.scrollbar-wrap {
overflow: auto;
height: 100px;
}
.black-table {
border-collapse: separate;
font-size: 0;
background-color: #121212;
text-transform: uppercase;
border-spacing: 0;
}
.black-table td {
color: #bbb;
font-size: 11px;
letter-spacing: 1px;
padding: 15px 30px;
}
.black-table th {
color: #fff;
font-size: 12px;
font-weight: 700;
letter-spacing: 2px;
padding: 15px 25px;
border-bottom: 1px solid #1c1c1c;
position: sticky; /* keep TH on top */
top: 0;
background-color: #121212;
white-space: nowrap;
}
<div id="content">
<div id="tasks-table-wrapper">
<table class="black-table">
<colgroup>
<col width="180">
<col width="180">
<col width="180">
<col width="180">
</colgroup>
<thead>
<tr>
<th>Column 1</th>
<th>Column 2</th>
<th>Column 3</th>
<th>Column 4</th>
</tr>
</thead>
</table>
<div class="scrollbar-wrap">
<table class="black-table">
<colgroup>
<col width="180">
<col width="180">
<col width="180">
<col width="163">
</colgroup>
<tbody>
<tr>
<td>AAA</td>
<td>BBB</td>
<td>CCC</td>
<td>DDD</td>
</tr>
<tr>
<td>AAA</td>
<td>BBB</td>
<td>CCC</td>
<td>DDD</td>
</tr>
<tr>
<td>AAA</td>
<td>BBB</td>
<td>CCC</td>
<td>DDD</td>
</tr>
<tr>
<td>AAA</td>
<td>BBB</td>
<td>CCC</td>
<td>DDD</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
You can see VUE Table with fixed header, Review the table elements.
Replace
#tasks tr {
display: block;
}
with
#tasks tr {
display: table;
width: 100%;
table-layout: fixed;
}
https://jsfiddle.net/5nt18cL0/

Table tr border width 100%

I want to make my border-top full table width but it's only taking my table data (td) size...
The last tr have my border-top but it's not taking the full size of the table.
th {
border: 0 solid #581D74;
border-bottom-width: 1px;
padding: 15px;
}
tr, td, th {
text-align: left;
padding: 15px;
}
.add-btn {
min-width: 0;
color: white;
}
.add-icon {
color: #581d74;
}
.total-row {
border: 0 solid #581d74;
border-top-width: 1px;
padding: 15px;
border-collapse: collapse;
}
<table class="disinves-table">
<tr class="table-header">
<th></th>
<th>head 1</th>
<th>head 2</th>
<th>head3</th>
</tr>
<tr>
<td><button mat-button class="add-btn"><mat-icon class="add-icon">add_circle</mat-icon></button></td>
<td>first data</td>
<td>19%</td>
</tr>
<tr class="total-row">
<td>Total</td>
<td></td>
<td>8654</td>
</tr>
</table>
If you are complaining about the gaps you see in the border, that is because the default style of a table is to have a few pixels of space between the cells.
Solution: set the table's border-spacing to 0.
.disinves-table {
border-spacing: 0;
}
th {
border: 0 solid #581D74;
border-bottom-width: 1px;
padding: 15px;
}
tr, td, th {
text-align: left;
padding: 15px;
}
.add-btn {
min-width: 0;
color: white;
}
.add-icon {
color: #581d74;
}
.total-row {
border: 0 solid #581d74;
border-top-width: 1px;
padding: 15px;
border-collapse: collapse;
}
<table class="disinves-table">
<tr class="table-header">
<th></th>
<th>head 1</th>
<th>head 2</th>
<th>head3</th>
</tr>
<tr>
<td><button mat-button class="add-btn"><mat-icon class="add-icon">add_circle</mat-icon></button></td>
<td>first data</td>
<td>19%</td>
</tr>
<tr class="total-row">
<td>Total</td>
<td></td>
<td>8654</td>
</tr>
</table>

Table elements doesn't respond to edit no matter what I do

I want to make a table for foods and nutrition,but there is a problem.No matter what i do width of the<td> and <th> elements won't change...I want my table to look something like this (without the header) Instead of THIS
#table1{
table-layout:fixed;
width:100%;
}
.row1 > th{
border-right:1px solid #ddd;
padding:0.75em;
}
<table id="table1">
<thead>
<tr class="row1">
<th>Foods</th><th>Carbohydrates</th><th>Proteins</th><th>Fats</th><th>Calories Total</th>
</tr>
</thead>
<tbody>
<tr class="row2">
<th>Foods</th><th>Carbohydrates</th><th>Proteins</th><th>Fats</th><th>Calories Total</th>
</tr>
</tbody>
</table>
Thanks.
Ther's no .Table1 class in your html. Simply use .row1 > th
To set width of th you can use:
th:nth-child(1) {
width: 15%;
}
#table1{
table-layout:fixed;
width:100%;
}
.row1 > th{
border-right:1px solid #ddd;
padding:0.75em;
}
.row2 > th{
border-right:1px solid #ddd;
padding:0.75em;
}
th:nth-child(1) {
width: 10%;
}
th:nth-child(2) {
width: 35%;
}
th:nth-child(3) {
width: 15%;
}
th:nth-child(4) {
width: 15%;
}
th:nth-child(5) {
width: 20%;
}
<table id="table1">
<thead>
<tr class="row1">
<th>Foods</th><th>Carbohydrates</th><th>Proteins</th><th>Fats</th><th>Calories Total</th>
</tr>
</thead>
<tbody>
<tr class="row2"><th>Foods</th><th>Carbohydrates</th><th>Proteins</th><th>Fats</th><th>Calories Total</th></tr>
</tbody>
</table>
Is that what you are looking for?
#table1{
table-layout:fixed;
width:100%;
}
.row1 > th, .row2 > td{
border-right:1px solid #ddd;
padding:0.75em;
text-align: left;
}
<table id="table1">
<thead>
<tr class="row1">
<th style="width:40%;">Foods</th>
<th style="width:20%;">Carbohydrates</th>
<th style="width:15%;">Proteins</th>
<th style="width:10%;">Fats</th>
<th style="width:15%;">Calories Total</th>
</tr>
</thead>
<tbody>
<tr class="row2">
<td>Foods</td>
<td>Carbohydrates</td>
<td>Proteins</td>
<td>Fats</td>
<td>Calories Total</td>
</tr>
</tbody>
</table>

Table Row Border - Half In, Half Out

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>
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.