I have two html tables. The first table is for the header and the second table is for the body. The reason for having two separate table is to be able to have a fixed header and a scrollable body.
How will I make the table header aligned with the table body?
Below is my code. current output
HTML
.scroll {
height: 100px;
overflow: auto;
}
#containerdiv {
width: 80%;
border: 2px solid brown;
}
<div id="containerdiv">
<div class="header">
<table>
<thead>
<!-- column names are going to be generated automatially with angular -->
<tr>
<th style="border: red solid 2px">Id</th>
<th style="border: red solid 2px">Customer Name</th>
<th style="border: red solid 2px">Address</th>
<th style="border: red solid 2px">Phone</th>
</tr>
</thead>
<!-- this is to set size for the column headers-->
<tbody>
<tr>
<td style="width:2%;"></td>
<td style="width:5%;"></td>
<td style="width:6%;"></td>
<td style="width:4%;"></td>
</tr>
</tbody>
</table>
</div>
<div class="scroll">
<table id="tablebody">
<tr>
<td style="width:4%;border: red solid 2px;">1</td>
<td style="width:5%;border: red solid 2px;">Customer 1</td>
<td style="width:6%;border: red solid 2px;">Address 1</td>
<td style="width:4%;border: red solid 2px;">phone number 1</td>
</tr>
<tr>
<td style="width:4%;border: red solid 2px;">2</td>
<td style="width:5%;border: red solid 2px;">Customer 2</td>
<td style="width:6%;border: red solid 2px;">Address 2</td>
<td style="width:4%;border: red solid 2px;">phone number 2</td>
</tr>
<tr>
<td style="width:4%;border: red solid 2px;">3</td>
<td style="width:5%;border: red solid 2px;">Customer 3</td>
<td style="width:6%;border: red solid 2px;">Address 3</td>
<td style="width:4%;border: red solid 2px;">phone number 3</td>
</tr>
<tr>
<td style="width:4%;border: red solid 2px;">4</td>
<td style="width:5%;border: red solid 2px;">Customer 4</td>
<td style="width:6%;border: red solid 2px;">Address 4</td>
<td style="width:4%;border: red solid 2px;">phone number 4</td>
</tr>
<tr>
<td style="width:4%;border: red solid 2px;">5</td>
<td style="width:5%;border: red solid 2px;">Customer 5</td>
<td style="width:6%;border: red solid 2px;">Address 5</td>
<td style="width:4%;border: red solid 2px;">phone number 5</td>
</tr>
</table>
</div>
</div>
Your main problem is that your widths 1. don't match, and more importantly 2. don't make sense.
Note that in your header, the first column inside the tbody is set at width: 2%, but the equivalent column in the next table is at width: 4%. Those values are gonna have to match, or things won't line up.
But more importantly, assuming we change that 2% to 4%, your columns only add up to 19% wide.
Percentage widths are based on their parents, not on the overall page width. So since you have set #containerdiv to 80% wide, by setting a column to 4% wide, you're making that column 4% of 80% of the page width = 0.32% of the page width.
What you really want to do is think of the table as 100% wide, and divide your columns up so their widths add up to 100%.
#containerdiv {
width: 80%;
}
#containerdiv table {
width: 100%;
}
#containerdiv table td:nth-child(1) { /* first column */
width: 15%;
}
/* and so on for other columns */
The other thing you can do to make this easier is to use box-sizing to include borders in the widths of your columns, so if you want a column to be, say, 25% wide with a 4 pixel border, you don't have to worry about setting a width like calc(25% - 4px). That is, if you want to continue with non-collapsed borders and spacing between table cells.
Lastly, note that your border shorthand property was out of order. It should be border-width, border-style, then border-color.
In this example, I took all your inline styles out and moved them into the stylesheet to make things easier to visualize, but if you're going to end up with inline styles in your app, that's fine. Follow the principles here, and it'll work:
.scroll {
height: 100px;
overflow: auto;
}
#containerdiv {
width: 80%;
border: 2px solid brown;
}
#containerdiv table {
width: 100%;
}
.header table {
padding-right: 17px;
}
#containerdiv table * {
box-sizing: border-box;
}
#containerdiv th,
#containerdiv td {
border: 2px solid red;
}
#containerdiv .header tbody td {
border: none;
}
#containerdiv th:nth-child(1),
#containerdiv td:nth-child(1) {
width: 15%;
}
#containerdiv th:nth-child(2),
#containerdiv td:nth-child(2) {
width: 30%;
}
#containerdiv th:nth-child(3),
#containerdiv td:nth-child(3) {
width: 30%;
}
#containerdiv th:nth-child(4),
#containerdiv td:nth-child(4) {
width: 25%;
}
<div id="containerdiv">
<div class="header">
<table>
<thead>
<!-- column names are going to be generated automatially with angular -->
<tr>
<th>Id</th>
<th>Customer Name</th>
<th>Address</th>
<th>Phone</th>
</tr>
</thead>
<!-- this is to set size for the column headers-->
<tbody>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
</div>
<div class="scroll">
<table id="tablebody">
<tr>
<td>1</td>
<td>Customer 1</td>
<td>Address 1</td>
<td>phone number 1</td>
</tr>
<tr>
<td>2</td>
<td>Customer 2</td>
<td>Address 2</td>
<td>phone number 2</td>
</tr>
<tr>
<td>3</td>
<td>Customer 3</td>
<td>Address 3</td>
<td>phone number 3</td>
</tr>
<tr>
<td>4</td>
<td>Customer 4</td>
<td>Address 4</td>
<td>phone number 4</td>
</tr>
<tr>
<td>5</td>
<td>Customer 5</td>
<td>Address 5</td>
<td>phone number 5</td>
</tr>
</table>
</div>
</div>
Edit regarding scrollbar: I have fixed the scrollbar issue on PC by adding padding-right to the only first table, so that there is a gap to the right of it where the scrollbar appears next to the second table. I chose 17px as the value because that's the scrollbar width for the most common browsers on Windows. But note that this isn't a perfect solution because not all browsers' scrollbars are exactly the same width.
A real-life perfect execution of that approach would use JavaScript to detect the scrollbar width and then set the padding-right accordingly.
However, an alternate approach that doesn't require any JavaScript is to set the table widths in viewport units, for example, to 75vw.
That's because 100vw is equivalent to the entire width of the window, including the scrollbar, whereas 100% (on body) is equivalent to the window width to the left of the scrollbar. So basically using vw units would let you ignore the scrollbar so that both tables come out the same width. Just choose a value that's small enough to leave space for the scrollbar on the bottom table, and the top table will match, even though it doesn't have a scrollbar.
Finally, note that all of this is really just to get around problems you're causing for yourself by the overall approach you're using here of using two separate tables to achieve the fixed header. Really, in my opinion, you should only have one table and just freeze the thead in place and be done with it. Then you wouldn't even have the scrollbar issue. Revising the whole thing to work that way is beyond the scope of this question, but it's something for you to consider.
I would use one table and fix the header like below.
Note: in <th> tags, the text has to be placed twice: once in a <div> (this will be the fixed one) and once normally (this will stay inside the table structure and ensure column width). Latter one can be hidden with some additional styling.
thead th div {
position: fixed;
}
<table>
<thead>
<tr>
<th>
<div>header 1 which is longer</div>
header 1 which is longer
<!-- yes, it's needed! -->
</th>
<th>
<div>header 2</div>
header 2
<!-- yes, it's needed! -->
</th>
</tr>
</thead>
<tbody>
<tr>
<td>content 1</td>
<td>content 2</td>
</tr>
<tr>
<td>content 1</td>
<td>content 2</td>
</tr>
<tr>
<td>content 1</td>
<td>content 2</td>
</tr>
<tr>
<td>content 1</td>
<td>content 2</td>
</tr>
<tr>
<td>content 1</td>
<td>content 2</td>
</tr>
<tr>
<td>content 1</td>
<td>content 2</td>
</tr>
<tr>
<td>content 1</td>
<td>content 2</td>
</tr>
<tr>
<td>content 1</td>
<td>content 2</td>
</tr>
<tr>
<td>content 1</td>
<td>content 2</td>
</tr>
<tr>
<td>content 1</td>
<td>content 2</td>
</tr>
<tr>
<td>content 1</td>
<td>content 2</td>
</tr>
<tr>
<td>content 1</td>
<td>content 2</td>
</tr>
<tr>
<td>content 1</td>
<td>content 2</td>
</tr>
</tbody>
</table>
Related
I have table in the a page where I need to implement a vertical scroll only for the tbody part of the table. My table has columns of dynamic width, there's horizontal scrolling implemented if increase in width of a column causes the table to overflow. What I want is for only the body of the table to scroll on vertical overflow, but want the table header to remain visible. What I have implemented scrolls the entire table vertically
Following is my code for now. It has dummy data, as I cant post the actual code, but the structure is the same(jsfiddle link):
th,
td {
text-align: left;
padding: 5px;
outline: solid 0.5px;
}
table {
table-layout: auto;
width: 100%;
white-space: nowrap;
overflow-x: scroll;
overflow-y: scroll;
height: 100px;
display: block;
}
.container {
width: 300px;
}
<div class="container">
<table>
<thead>
<tr>
<th>Title 1</th>
<th>Name</th>
<th>Address</th>
<th>Col4</th>
<th>Col5</th>
<th>Col6</th>
</tr>
</thead>
<tbody>
<tr>
<td>Title 2</td>
<td>Jane Doe</td>
<td>dfss</td>
<td>sdffsffsfd</td>
<td>sfsfs</td>
<td>sfsff</td>
</tr>
<tr>
<td>Title 3</td>
<td>John Doe</td>
<td>sasas</td>
<td>eeeee</td>
<td>eEe</td>
<td>sfff</td>
</tr>
<tr>
<td>Title 4 is a long title</td>
<td>Name1</td>
<td>dfss</td>
<td>sdffsffsfd</td>
<td>sfsfs</td>
<td>sfsff</td>
</tr>
<tr>
<td>Title 5 is shorter</td>
<td>Name 2</td>
<td>dfsf</td>
<td>sdfsf</td>
<td>dfsf</td>
<td>sdfsf</td>
</tr>
<tr>
<td>Title 6</td>
<td>Name 3</td>
<td>sasas</td>
<td>eeeee</td>
<td>eEe</td>
<td>sfff</td>
</tr>
</tbody>
</table>
</div>
I have checked multitiple solutions on stackoverflow for this problem but they all set a fixed width for their columns and then use wrap the content inside if it exceeds the width. table with fixed thead and scrollable tbody
is the only solution that didn't completely mess up my page, but doesn't work, it gives different column widths for columns in header and body.
All other solutions, even the ones that use nested table use fixed width column, and the ones which don't use js/jQuery which I would rather not use unless its the absolute, last ever option. Can anyone please suggest something?
To make the <tbody> scrollable :
tbody{
display: block;
height: 100px;
width: 100%;
overflow-y: scroll;
}
And if you want to the <thead> to stay fixed while the body scrolls:
thead tr{
display: block
}
I'm unsure whether this is answering your question.
If the y axis is always to have a scroll and the x axis only to have
a scroll if there is too much information
CSS
overflow-x:auto;
overflow-y:scroll;
I came across this issue myself and found an alternate solution to the answer posted by #Abe Caymo
Simple non-ideal solution (by Abe)
The problem with Abe's solution is that it works fine up until you start to use thead and tfoot. Once you add these you will soon realize that the table column layout no longer syncs the column width across tbody, thead and tfoot. See demo below...
th,
td {
text-align: left;
padding: 5px;
outline: solid 0.5px;
}
table {
white-space: nowrap;
display: block;
}
tbody{
display: block;
height: 100px;
overflow-y: auto;
}
<div class="container">
<table>
<thead>
<tr>
<th>Title 1</th>
<th>Name</th>
<th>Address</th>
<th>Col4</th>
<th>Col5</th>
<th>Col6</th>
</tr>
</thead>
<tbody>
<tr>
<td>Title 2</td>
<td>Jane Doe</td>
<td>dfss</td>
<td>sdffsffsfd</td>
<td>sfsfs</td>
<td>sfsff</td>
</tr>
<tr>
<td>Title 3</td>
<td>John Doe</td>
<td>sasas</td>
<td>eeeee</td>
<td>eEe</td>
<td>sfff</td>
</tr>
<tr>
<td>Title 4 is a long title</td>
<td>Name1</td>
<td>dfss</td>
<td>sdffsffsfd</td>
<td>sfsfs</td>
<td>sfsff</td>
</tr>
<tr>
<td>Title 5 is shorter</td>
<td>Name 2</td>
<td>dfsf</td>
<td>sdfsf</td>
<td>dfsf</td>
<td>sdfsf</td>
</tr>
<tr>
<td>Title 6</td>
<td>Name 3</td>
<td>sasas</td>
<td>eeeee</td>
<td>eEe</td>
<td>sfff</td>
</tr>
</tbody>
<tfoot>
<tr>
<th>Title 1</th>
<th>Name</th>
<th>Address</th>
<th>Col4</th>
<th>Col5</th>
<th>Col6</th>
</tr>
</tfoot>
</table>
</div>
Slightly more ideal solution
A better solution which maintains the auto table-layout is to set the thead and tfoot to position: sticky.
A few caveats and things to understand about this approach.
The overflow or element actually scrolling, is the div container of the table. You must have this and this is what you may use to control the size of the table. As such, the scroll bar will always be the full height of the scrollable table.
The background-color must be set to an opaque value otherwise the rows in the tbody will show behind the header as it passes below when scrolling.
The borders/outlines are much harder to get right but with a little finessing you can find a compatible style. Adding a border or outline to either thead or tfoot will not be sticky.
.container {
height: 140px;
min-height: 100px;
overflow: auto;
resize: vertical; /* only for demo */
}
thead,
tfoot {
/* must background-color otherwise transparent will show rows underneath */
background-color: white;
position: sticky;
}
thead {
margin-bottom: 0;
top: 0;
}
tfoot {
margin-top: 0;
bottom: 0;
}
th,
td {
text-align: left;
padding: 5px;
outline: solid black 0.5px;
}
table {
width: 100%;
}
<div class="container">
<table>
<thead>
<tr>
<th>Title 1</th>
<th>Name</th>
<th>Address</th>
<th>Col4</th>
<th>Col5</th>
<th>Col6</th>
</tr>
</thead>
<tbody>
<tr>
<td>Title 2</td>
<td>Jane Doe</td>
<td>dfss</td>
<td>sdffsffsfd</td>
<td>sfsfs</td>
<td>sfsff</td>
</tr>
<tr>
<td>Title 3</td>
<td>John Doe</td>
<td>sasas</td>
<td>eeeee</td>
<td>eEe</td>
<td>sfff</td>
</tr>
<tr>
<td>Title 4 is a long title</td>
<td>Name1</td>
<td>dfss</td>
<td>sdffsffsfd</td>
<td>sfsfs</td>
<td>sfsff</td>
</tr>
<tr>
<td>Title 5 is shorter</td>
<td>Name 2</td>
<td>dfsf</td>
<td>sdfsf</td>
<td>dfsf</td>
<td>sdfsf</td>
</tr>
<tr>
<td>Title 6</td>
<td>Name 3</td>
<td>sasas</td>
<td>eeeee</td>
<td>eEe</td>
<td>sfff</td>
</tr>
</tbody>
<tfoot>
<tr>
<th>Title 1</th>
<th>Name</th>
<th>Address</th>
<th>Col4</th>
<th>Col5</th>
<th>Col6</th>
</tr>
</tfoot>
</table>
</div>
The final result will look something like that below with all columns aligned respectively...
Also see this solution using display: grid on the table element.
I have create a table using <td> with 5 columns. i have set table width as 100%. When i set the <td> width of the table as 100% and above the horizontal scrollbar does not work.
I have raised a related question already. since i did not get any answer for that question. I am again raising it here. Hope some one can help me solve this.
I have seen lot of questions regarding the size of Horizontal property given in pixels but could not see anything on %.
Any help is greatly appreciated.
I want to create something like that is shown in the picture.
enter image description here
I have used Pixels to create it. But i need to give in %.
Previous Question Pasted by me:
link:
Html table - td width in percentage with overflow not working
Html:
table {
width: 100%;
border-collapse: collapse;
}
td {
border: 1px solid black;
}
<table>
<tr>
<td style="width: 25%">Column 1</td>
<td style="width: 25%">Column 2</td>
<td style="width: 25%">Column 3</td>
<td style="width: 25%">Column 4</td>
<td style="width: 25%">Column 5</td>
</tr>
</table>
I have used Pixels to create it. But i need to give in %.
HTML Table Pixels and %:
table {
width: 100%;
border-collapse: collapse;
}
td {
border: 1px solid black;
}
<div class="tableDiv" style="width: 100%; overflow-x: auto; ">
<table >
<tr>
<td style="min-width:250px;">Column 1</td>
<td style="min-width:250px;">Column 2</td>
<td style="min-width:250px;">Column 3</td>
<td style="min-width:250px;">Column 4</td>
<td style="min-width:250px;">Column 5</td>
</tr>
</table>
</div>
<br/>
<div style="width: 100%; overflow-x: auto;">
<table>
<tr>
<td style="min-width:25%;">Column 1</td>
<td style="min-width:25%;">Column 2</td>
<td style="min-width:25%;">Column 3</td>
<td style="min-width:25%;">Column 4</td>
<td style="min-width:25%;">Column 5</td>
</tr>
</table>
</div>
Use the CSS Unit vw, see docs: https://www.w3schools.com/cssref/css_units.asp
vw = Relative to 1% of the width of the viewport^
^ Viewport = the browser window size. If the viewport is 50cm wide, 1vw = 0.5cm.
Then make your td as min-width 25vw
table td {
min-width: 25vw;
...
}
In order to have the horizontal scroll on the table only you can wrap it and then apply the overflow...
Html:
<div class="table-wrapper">
<table>
[...]
</table>
</div>
The CSS:
.table-wrapper {
overflow: auto;
}
.table-wrapper {
overflow: auto;
}
table {
border-collapse: collapse;
}
table td {
min-width: 25vw;
border: 1px solid black;
}
<div class="table-wrapper">
<table>
<tr>
<td>Column 1</td>
<td>Column 2</td>
<td>Column 3</td>
<td>Column 4</td>
<td>Column 5</td>
</tr>
</table>
</div>
table {
width: 100%;
border-collapse: collapse;
}
td {
border: 1px solid black;
}
<div style="width: 100vw; overflow:scroll;">
<table style="width: 130vw;">
<tr>
<td style="width: 50vw">50=50</td>
<td style="width: 50vw">50 + 50 =100</td>
<td style="width: 30vw">50 + 50 +30 =130(this td 30% need to horizontal scrollbar)</td>
</tr>
</table>
</div>
This answer for your previous question. try this.
You should try instead to use min-width rather than width alone.
<table>
<tr>
<td style="min-width: 25%">Column 1</td>
<td style="min-width: 25%">Column 2</td>
<td style="min-width: 25%">Column 3</td>
<td style="min-width: 25%">Column 4</td>
<td style="min-width: 25%">Column 5</td>
</tr>
</table>
Or if you were trying to get the scrollbar you could increase the table width
table {
width: 125%;
border-collapse: collapse;
}
td {
border: 1px solid black;
}
<table>
<tr>
<td style="min-width: 25%">Column 1</td>
<td style="min-width: 25%">Column 2</td>
<td style="min-width: 25%">Column 3</td>
<td style="min-width: 25%">Column 4</td>
<td style="min-width: 25%">Column 5</td>
</tr>
</table>
I believe the width: 1px; white-space: nowrap; trick worked before but it seems not anymore now? Ref. CSS table column autowidth (there the table was also in fixed layout but thats back in 2011)
Here is the HTML and CSS:
table {
table-layout: fixed;
width: 100%;
}
td,
th {
border: 1px solid #D5D5D5;
padding: 15px;
}
.auto {
width: 1px;
white-space: nowrap;
}
<table cellspacing="0" cellpadding="0" border="0">
<thead>
<tr>
<th>Column 1 even width</th>
<th>Column 2 even width</th>
<th>Column 3 even width</th>
<th class="auto">Auto</th>
</tr>
</thead>
<tbody>
<tr>
<td>Data 1</td>
<td>Data 2</td>
<td>Data 3</td>
<td class="auto">Data4</td>
</tr>
</tbody>
</table>
I also have an example setup in the following jsfiddle:
http://jsfiddle.net/hCkch/21/
How do you make the last column auto width based on the content while the other columns respect table-layout: fixed?
Note: the three columns given above is just an example. So please no hardcoded answers to make each column width 100/3%. This is a general question and the answer should fit for n columns with even width but the last one auto width based on the content.
With table-layout, you will want to set the widths of the cells in the first row of the table (https://developer.mozilla.org/en-US/docs/Web/CSS/table-layout). You'll also want to add a width of 100% for the final column that is meant to auto-expand. Here is an edit of your jsfiddle:
http://jsfiddle.net/jessbodie/hCkch/31/
<table cellspacing="0" cellpadding="0" border="0">
<thead>
<tr>
<th class="col1st">Column 1 even width</th>
<th class="col2nd">Column 2 even width</th>
<th class="col3rd">Column 3 even width</th>
<th class="auto">Auto</th>
</tr>
</thead>
<tbody>
<tr>
<td>Data 1</td>
<td>Data 2</td>
<td>Data 3</td>
<td class="auto">Data4</td>
</tr>
</tbody>
</table>
table {
table-layout: fixed;
width: 100%;
}
td, th {
border: 1px solid red;
padding: 15px;
}
.col1st {
width: 100px;
}
.col2nd {
width: 100px;
}
.col3rd {
width: 100px;
}
.auto {
width: 100%;
white-space: nowrap;
}
For making the first n columns the same width, in SASS you can use the calc function to come up with the widths.
As mentioned in the comments, the only way I know to do this that should work cross browser is to get rid of table-layout: fixed; and set the width of the remaining columns. Fixed layouts are good for lots of things but automatically calculating based on content doesn't seem to be one of them.
table {
width: 100%;
}
td, th {
border: 1px solid #D5D5D5;
padding: 15px;
width: 33.33%
}
.auto {
white-space: nowrap;
}
<table cellspacing="0" cellpadding="0" border="0">
<thead>
<tr>
<th>Column 1 even width</th>
<th>Column 2</th>
<th>Column 3</th>
<th class="auto">Auto</th>
</tr>
</thead>
<tbody>
<tr>
<td>Data 1</td>
<td>Data 2</td>
<td>Data 3</td>
<td>Data4</td>
</tr>
</tbody>
</table>
I realize you clarified that you don't want markup specific rules, but it does in fact accomplish your goal with the one requirement that you know how many columns you will be dealing with beforehand. In general, this should not be prohibitive.
Another possibly work around is to assign the widths client side using js after the fact:
$(document).ready(function() {
var width = 100 / $('table tr:first th:not(.auto)').length;
var cols = $('table th:not(.auto)');
cols.css('width', width + '%');
});
table {
width: 100%;
}
td, th {
border: 1px solid #D5D5D5;
padding: 15px;
}
.auto {
white-space: nowrap;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table cellspacing="0" cellpadding="0" border="0">
<thead>
<tr>
<th>Column 1 even width</th>
<th>Column 2</th>
<th>Column 3</th>
<th class="auto">Auto</th>
</tr>
</thead>
<tbody>
<tr>
<td>Data 1</td>
<td>Data 2</td>
<td>Data 3</td>
<td>Data4</td>
</tr>
</tbody>
</table>
And finally, I'll mention there is a Firefox specific implementation of min-content that actually does exactly what you want. Unfortunately, it only works on Firefox:
table {
width: 100%;
table-layout: fixed;
}
td, th {
border: 1px solid #D5D5D5;
padding: 15px;
}
.auto {
width: -moz-min-content;
white-space: nowrap;
}
<table cellspacing="0" cellpadding="0" border="0">
<thead>
<tr>
<th>Column 1 even width</th>
<th>Column 2</th>
<th>Column 3</th>
<th class="auto">Auto</th>
</tr>
</thead>
<tbody>
<tr>
<td>Data 1</td>
<td>Data 2</td>
<td>Data 3</td>
<td>Data4</td>
</tr>
</tbody>
</table>
I've been trying to figure out a way to take a standard table and create a fixed-column table where the first column is fixed while the rest scrolls. There's a couple ways that I think make sense, so I'll start with that.
The first way that makes sense to me is to simply break the table code format by creating a separate table as the column that we want to be by itself, something like this:
<div class="table-container">
<div class="table-column">
<table>
<thead><tr><th> </th></tr></thead>
<tbody>
<tr><td>Side Header 1</td></tr>
<tr><td>Side Header 2</td></tr>
<tr><td>Side Header 3</td></tr>
<tr><td>Side Header 4</td></tr>
<tr><td>Side Header 5</td></tr>
<tr><td>Side Header 6</td></tr>
</tbody>
</table>
</div>
<div class="table-column" style="overflow-x: auto;">
<table>
<thead>
<tr><th>Top Header 1</th><th>Top Header 2</th></tr>
</thead>
<tbody>
<tr><td>Row 1, Cell 1</td><td>Row 1, Cell 2</td></tr>
<tr><td>Row 2, Cell 1</td><td>Row 2, Cell 2</td></tr>
<tr><td>Row 3, Cell 1</td><td>Row 3, Cell 2</td></tr>
<tr><td>Row 4, Cell 1</td><td>Row 4, Cell 2</td></tr>
<tr><td>Row 5, Cell 1</td><td>Row 5, Cell 2</td></tr>
<tr><td>Row 6, Cell 1</td><td>Row 6, Cell 2</td></tr>
</tbody>
</table>
</div>
</div>
We make the first column have a <th> of just blank space so that the styling for the whole table still fits.
What I really want to do though is make this more of a dynamic process... Obviously in that case (especially using the word 'dynamic') I could just use some JS, but there must be a way to do this in CSS... but there doesn't seem to be anything solid online... so I thought I'd give it a go.
The closest I've been able to come is through using data-attribute:; and td::before, like this:
<div class="box-table">
<table class="text-center hover stripes">
<thead>
<tr>
<th data-label="Cat 1">Cat 1</th>
<th>Cat 2</th>
<th>Cat 3</th>
<th>Cat 4</th>
<th>Cat 5</th>
<th>Cat 6</th>
</tr>
</thead>
<tbody>
<tr>
<td data-label="Col 1">Col 1</td>
<td>Col 2</td>
<td>Col 3</td>
<td>Col 4</td>
<td>Col 5</td>
<td>Col 6</td>
</tr>
<tr>
<td data-label="Col 1">Col 1</td>
<td>Col 2</td>
<td>Col 3</td>
<td>Col 4</td>
<td>Col 5</td>
<td>Col 6</td>
</tr>
</tbody>
</table>
</div>
<style>
tr > th:first-child,
tr > td:first-child {
padding: 0;
}
tr > th:first-child::before,
tr > td:first-child::before {
content: attr(data-label);
display: inline-block;
position: fixed;
background: #fff;
border-right: 1px solid rgba(0,0,0,0.2);
letter-spacing: 1px;
padding: 0 0.75rem;
}
<style>
Here's a fiddle with what I've gotten so far: https://jsfiddle.net/wn5nonu3/
There's 2 issues I've run into:
The first is that because I've set the item to fixed, if the overflow of the table allows vertical scrolling then the fixed will obviously stay where they are fixed and appear out of line with the row.
The second issue is that I can't seem to style td::before (it seems to be showing 'inline' behavior regardless of what I change the display:; value to?).
Potential solution to the second problem is to remove the padding causing the row's to be larger, set the first column to a fixed width and add that width to td::before. I still can't fix the first problem though.
I thought I'd share in case anyone has any ideas about how this could possibly work, or whether or not the route I'm taking is even really doable?
jsFiddle: https://jsfiddle.net/wn5nonu3/ (same as one posted above, just for easy finding)
For the record: I know there's a number of great JS options, I just like to limit the amount of scripts I throw on my pages, and this just seems like something that would be useful.
One way you could make it is by using two tables with the same style, but it's a little hard to maintain. You have to make sure both tables are on the same line and that there's no space between them. When you just wrap the table with the actual content in a div that scrolls. Honestly, I wouldn't go there unless you really don't want to use JS, but it's your call.
.table-wrapper {
width: 100%;
white-space: nowrap;
}
.table-firstcolon {
display: inline-block;
vertical-align: top;
}
.table-firstcolon td,
.table-firstcolon th {
width: 60px;
}
.table-content-wrapper {
display: inline-block;
overflow-x: scroll;
vertical-align: top;
max-width: calc(100% - 60px);
}
.table-content-wrapper>table {
display: inline-block;
vertical-align: top;
}
/* Page Setup */
*,
*::after,
*::before {
box-sizing: inherit;
}
html {
box-sizing: border-box;
font-family: Arial, Helvetica, sans-serif;
font-size: 14px;
height: 100%;
line-height: 1.5;
width: 50%;
}
body {
min-height: 100%;
padding: 5px 10px;
/* this style is only for the fiddle, would be '0' */
width: 100%;
}
/* General Table Styling */
table {
background: #fdfdfd;
border-collapse: collapse;
border-spacing: 0;
}
th {
font-weight: bold;
}
thead,
tbody,
tfoot {
border: 1px solid #f1f1f1;
}
th, td {
padding: 6px;
text-align: left;
}
thead tr:first-child {
font-weight: bold;
border-bottom: 2px solid #eee;
}
tr:nth-child(even) {
background-color: rgba(0, 0, 0, 0.025);
}
tr:hover td {
background-color: rgba(0, 0, 0, 0.04);
color: #000;
}
<div class="table-wrapper">
<table class="table-firstcolon text-center hover stripes">
<thead>
<tr>
<th> </th>
</tr>
</thead>
<tbody>
<tr>
<th>Row 1</th>
</tr>
<tr>
<th>Row 2</th>
</tr>
<tr>
<th>Row 3</th>
</tr>
<tr>
<th>Row 4</th>
</tr>
<tr>
<th>Row 5</th>
</tr>
<tr>
<th>Row 6</th>
</tr>
</tbody>
</table><!--
--><div class="table-content-wrapper">
<table>
<thead>
<tr>
<th>Column A</th>
<th>Column B</th>
<th>Column C</th>
<th>Column D</th>
<th>Column E</th>
</tr>
</thead>
<tbody>
<tr>
<td>A1</td>
<td>B1</td>
<td>C1</td>
<td>D1</td>
<td>E1</td>
</tr>
<tr>
<td>A2</td>
<td>B2</td>
<td>C2</td>
<td>D2</td>
<td>E2</td>
</tr>
<tr>
<td>A3</td>
<td>B3</td>
<td>C3</td>
<td>D3</td>
<td>E3</td>
</tr>
<tr>
<td>A4</td>
<td>B4</td>
<td>C4</td>
<td>D4</td>
<td>E4</td>
</tr>
<tr>
<td>A5</td>
<td>B5</td>
<td>C5</td>
<td>D5</td>
<td>E5</td>
</tr>
<tr>
<td>A6</td>
<td>B6</td>
<td>C6</td>
<td>D6</td>
<td>E6</td>
</tr>
</tbody>
</table>
</div>
</div>
JsFiddle URL : http://jsfiddle.net/gfy4pwrr/1
<table cellspacing="0" cellpadding="0" border="0" width="325" >
<tr>
<td>
<table cellspacing="0" cellpadding="1" border="1" width="300" >
<tr>
<th>Full Name</th>
<th>Status</th>
<th>Last reported</th>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<div class ='cont' style="width:325px; height:48px; overflow:auto;">
<table class='data' cellspacing="0" cellpadding="1" border="1" width="300" >
<tr>
<td>col 1 data 1</td>
<td>col 2 data 1</td>
<td>col 3 data 1</td>
</tr>
<tr>
<td>col 1 data 2</td>
<td>col 2 data 2</td>
<td>col 3 data 2</td>
</tr>
<tr>
<td>col 1 data 3</td>
<td>col 2 data 3</td>
<td>col 3 data 3</td>
</tr>
</table>
</div>
</td>
</tr>
</table>
The columns are not aligned with the headers.
I want the table used for data to be aligned with the headers.
td width=100px for second table is not working.
I would get rid of the nested tables and use the semantics of the table element according to the w3c specs. The trick is to use the right elements but manipulate the way the browser displays them. <table>, <thead> and <tbody> can be displayed as block elements while every row can be a table (leaving <td> and <th> displayed as table-cell by default).
I've demonstrated it in a JSFiddle. But it basically comes down to a simple table structure:
<table>
<thead>
<tr>
<th>Full Name</th>
<th>Status</th>
<th>Last reported</th>
</tr>
</thead>
<tbody>
<tr>
<td>col 1 data 1</td>
<td>col 2 data 1</td>
<td>col 3 data 1</td>
</tr>
</tbody>
</table>
And setting the display properties in css with an overflow on <tbody>:
table, tbody, thead {
display: block;
}
tbody, thead {
overflow-y: scroll;
}
tbody {
height: 100px;
}
tr {
display: table;
...
}
To come back to the problem with the column width's. There is no other way solving that than setting the same width on each cell in each table (<tr>). In the fiddle I set it to 33.33%:
td , th {
width: 33.33%;
...
}
For Windows it is necessary to show the scrollbar in <thead> otherwise it doesn't size the same as <tbody>. To hide it there is a small trick:
thead {
margin-right: -300px;
padding-right: 300px;
}
It's not that the "columns are not aligned with the headers", the problem is that your second table does NOT have any header. You just have nested tables. One with headers th and second with no header, just td.
Basically your thare not in the same column as your td
So both tables, even if the width is the same, will adjust the width of the cells depending on the content inside. It's just happen all your tdhave same content (in number of charachters) so the effect was that they are slightly missaligned.
However if you set a fixed width to both thand tdand display them as ìnline-block`elements they will align: FIDDLE
However I don't recomend to change the display of the cells on a pure html table. You may have headaches incoming. (and also I don't recomend tthe use of nested tables... I had so many headaches back then when layouts were made that way... ty explorer)
Collapse the borders: border-collapse: collapse; and set box-sizing: border-box;
http://jsfiddle.net/gfy4pwrr/6/
* {
box-sizing: border-box;
}
table {
border-collapse: collapse;
}
td, th {
/* if it is 100px the overflow content in the first column "push" the border ?? */
width: 99px;
max-width: 99px;
overflow: hidden;
}
<table cellspacing="0" cellpadding="0" border="0" width="325">
<tr>
<td>
<table cellspacing="0" cellpadding="1" border="1" width="300">
<tr>
<th>Full Name</th>
<th>Status</th>
<th>Last reported</th>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<div class='cont' style="width:325px; height:48px; overflow:auto;">
<table class='data' cellspacing="0" cellpadding="1" border="1" width="300">
<tr>
<td>VeryOverflowContent long long long content</td>
<td>OverflowContent</td>
<td>col 3 data 1</td>
</tr>
<tr>
<td>col 1 data 2</td>
<td>col 2 data 2</td>
<td>col 3 data 2</td>
</tr>
<tr>
<td>col 1 data 3</td>
<td>col 2 data 3</td>
<td>col 3 data 3</td>
</tr>
</table>
</div>
</td>
</tr>
</table>
I guest you want a fixed header table.I recommend you change your html to easy build a fixed header table.
Here's my suggestion:
<div class="table-header">
<table>
<thead>
<tr>
<th>Full Name</th>
<th>Status</th>
<th>Last reported</th>
</tr>
</thead>
</table>
</div>
<div class="table-content">
<table>
<thead>
<tr>
<th>Full Name</th>
<th>Status</th>
<th>Last reported</th>
</tr>
</thead>
<tbody>
<tr>
<td>col 1 data 1</td>
<td>col 2 data 1</td>
<td>col 3 data 1</td>
</tr>
<tr>
<td>col 1 data 2</td>
<td>col 2 data 2</td>
<td>col 3 data 2</td>
</tr>
<tr>
<td>col 1 data 3</td>
<td>col 2 data 3</td>
<td>col 3 data 3</td>
</tr>
</tbody>
</table>
</div>
and css:
.table-header
{ padding-right:13.5px;
}
.table-header table
{
height:20px;
}
.table-header thead tr
{
background:#fff;
z-index:10000;
}
.table-content
{
max-height:250px;
overflow-y:auto;
overflow-x:hidden;
margin-top:-20px;
}
.table-content thead
{
visibility:collapse;
}
table
{
border-collapse: collapse;
}
table th, td
{
border: 1px solid black;
width:200px;
text-align:center;
padding:0;
}
look at:http://jsfiddle.net/chuongxl/gfy4pwrr/51/
or you can use this plugin http://www.fixedheadertable.com/