Problem:
I have a <table> element that I want to dynamically fill 100% of a container's height, without exceeding.
Background:
When the <table> exceeds the container height, I want to be able to scroll through the table-rows. I do not want information above the table to be scrolled off the page.
When my <table> height exceeds the container, the container gets the scroll-bar, and not the <table> itself. This scrolls information above the table off of the page.
Limitations:
I am using <table> elements and do not want to use the <div> display: table approach.
I would also like this to be dynamic, and not set the height to a hard pixel count.
HTML:
<div class="demo-container">
<div class="demo-header">Don't scroll me off the page please</div>
<div class="demo-container>
<div class="table-container">
<table>
<thead>
<tr>
<th>Table Header</th>
</tr>
</thead>
<tbody>
<tr>
<td>Rows are populated via API and will expand the table height</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
CSS:
.demo-container {
height: 100%
display: grid;
grid-area: body;
grid-template-areas:
'demo-header'
'demo-container';
grid-template-rows: 60px 1fr;
}
.demo-header {grid-area: demo-header;}
.demo-container {grid-area: demo-container;}
.table-container {
height: 100%
overflow-y: auto;
}
I know that if I set the .table-container's height to pixels, and set overflow-y: auto, I can achieve the desired look.
However, I do not want to do this with pixel heights, and would like a more responsive solution in case things change on the page. Is there any way to do this without exact pixel heights?
Thanks
Here's how you might go about it. How you set up the outer element depends on your overall page structure.
html,
body {
height: 100vh;
margin: 0;
padding: 0;
}
.demo-container {
display: flex;
flex-direction: column;
max-height: 100%;
}
.demo-header {
flex: none;
}
.table-container {
overflow: auto;
}
table {
background: pink;
}
td {
padding: 15px;
border: 1px solid #fff;
}
<div class="demo-container">
<div class="demo-header">Don't scroll me off the page please</div>
<div class="table-container">
<table>
<thead>
<tr>
<th>Table Header</th>
</tr>
</thead>
<tbody>
<tr>
<td>Pretend that this expands the table height past the container</td>
</tr>
<tr>
<td>Pretend that this expands the table height past the container</td>
</tr>
<tr>
<td>Pretend that this expands the table height past the container</td>
</tr>
<tr>
<td>Pretend that this expands the table height past the container</td>
</tr>
<tr>
<td>Pretend that this expands the table height past the container</td>
</tr>
<tr>
<td>Pretend that this expands the table height past the container</td>
</tr>
<tr>
<td>Pretend that this expands the table height past the container</td>
</tr>
<tr>
<td>Pretend that this expands the table height past the container</td>
</tr>
<tr>
<td>Pretend that this expands the table height past the container</td>
</tr>
<tr>
<td>Pretend that this expands the table height past the container</td>
</tr>
<tr>
<td>Pretend that this expands the table height past the container</td>
</tr>
<tr>
<td>Pretend that this expands the table height past the container</td>
</tr>
<tr>
<td>Pretend that this expands the table height past the container</td>
</tr>
<tr>
<td>Pretend that this expands the table height past the container</td>
</tr>
</tbody>
</table>
</div>
</div>
#container {
width: 960px;
height: 960px;
background-color: #ccc;
}
.box {
width: 300px;
height: 300px;
background-color: blue;
display: table-caption;
border: 0;
}
<div id='container'>
<span class='box'>Content</span>
<span class='box'>Content</span>
<span class='box'>Content</span>
<span class='box'>Content</span>
</div>
Table Caption Fiddle Demo
Now when I change table-caption to table-cell it renders horizontally. Below is the demo of it.
Table Cell Fiddle Demo
Any reason for the different renderings?
Here is what the spec says about display: table-caption:
table-caption (In HTML: CAPTION)
Specifies a caption for the table. All elements with 'display: table-caption' must be rendered, as described in section 17.4.
And here is what the section 17.4 says about rendering of caption boxes:
The caption boxes are block-level boxes that retain their own content, padding, margin, and border areas, and are rendered as normal block boxes inside the table wrapper box.
The key part is that they are rendered as normal block boxes and hence each of them is displayed one below the other (as in, in their own row).
Other points to note: (A summary of my discussion with GCyrillus in comments)
Parent container with display: table is not required for a child to have display: table-cell or display: table-caption. You can find more details and reference to the relevant part of the spec in this SO thread
There should ideally be only one caption per table. User Agents probably don't expect multiple captions to be provided under the same parent/table and it probably explains why Firefox renders it differently from Chrome. But details on that are beyond the scope of this answer (in my opinion) as the question only asks why display: table-caption causes vertical layout.
I concur with GCyrillus, it is definitely bad practice to use display: table-caption on multiple elements under the same parent. I believe you were doing trial and error in an attempt to learn.
.header{
writing-mode: vertical-rl;
padding-top: 30%;
font-weight: bold;
padding-right: 5px
}
table,tr,td{
border:1px solid black;
border-collapse: collapse;
padding: 5px;
}
<h1>Right Caption </h1>
<table>
<tr>
<td>
<table>
<tr> <th>SrNo.</th> <th>Name</th> <th>Department</th> </tr>
<tr>
<td>1</td>
<td>Natasha</td>
<td>IT</td>
</tr>
<tr>
<td>1</td>
<td>Umar</td>
<td>IT</td>
</tr>
<tr>
<td>1</td>
<td>Usman</td>
<td>BBA</td>
</tr>
<tr>
<td>1</td>
<td>Warda</td>
<td>BBA</td>
</tr>
</table>
</td>
<td rowspan="5" ><span class="header">Student Data</span> </td>
</tr>
</table>
<h1>Left Caption </h1>
<table>
<tr>
<td rowspan="5" ><span class="header">Student Data</span> </td>
<td>
<table>
<tr> <th>SrNo.</th> <th>Name</th> <th>Department</th> </tr>
<tr>
<td>1</td>
<td>Natasha</td>
<td>IT</td>
</tr>
<tr>
<td>1</td>
<td>Umar</td>
<td>IT</td>
</tr>
<tr>
<td>1</td>
<td>Usman</td>
<td>BBA</td>
</tr>
<tr>
<td>1</td>
<td>Warda</td>
<td>BBA</td>
</tr>
</table>
</td>
</tr>
</table>
I can't understand why the table sizing is working the way it is. Here is my example HTML:
<!DOCTYPE html>
<html>
<head>
<title>Table sizing test</title>
</head>
<body>
<style>
.tab-strip {
overflow: hidden;
white-space: nowrap;
}
.tab-strip .tab-button {
display: inline-block;
}
.tab-strip .tab-button td {
background-color: yellow;
}
.tab-strip .tab-button td:first-child {
background-color: green !important;
width: 100px;
}
</style>
<div>
<table align="center" border="1">
<tr>
<td valign="top">
<div class="tab-strip">
<table class="tab-button">
<tr>
<td></td>
<td>TEST1</td>
</tr>
</table>
<table class="tab-button">
<tr>
<td></td>
<td>TEST2</td>
</tr>
</table>
<table class="tab-button">
<tr>
<td></td>
<td>TEST3</td>
</tr>
</table>
<table class="tab-button">
<tr>
<td></td>
<td>TEST4</td>
</tr>
</table>
<table class="tab-button">
<tr>
<td></td>
<td>TEST5</td>
</tr>
</table>
<table class="tab-button">
<tr>
<td></td>
<td>TEST6</td>
</tr>
</table>
</div>
</td>
</tr>
</table>
</div>
</body>
</html>
I've put it in a jsFiddle here: http://jsfiddle.net/90674xsg/
When the window is made narrower, the table keeps shrinking (smaller than its content) until a certain point, and then stops (causing a horizontal scrollbar to appear in the result window). What determines this minimum width, though?
UPDATE:
It's been pointed out to me that the table width is determined by adding up the content-derived width of cells that actually contain content. So the "TESTx" cells' widths are counted, but the empty cell widths are ignored even though they have a fixed width of 100px. How can i make the minimum table width include their widths?
Tables are kind of weird, there's good reason that modern web development has steered away from them.
Adding the css min-width property seems to do the trick for me, but I only tested in chrome.
.tab-strip .tab-button td:first-child {
background-color: green !important;
width: 100px;
min-width: 100px;
}
See updated fiddle here. If that doesn't work, you can try forcing it to stay open with padding instead of width - or add an empty div to the td that has a width of 100px.
I'm trying to create a "fixed-width" table, but it somehow changes the column width whenever the data in column is bigger than rest of them.
For example, following table changes the width on the last number, which is 10.
<table>
<tr>
<td rowspan="3">1</td>
<td>2</td>
<td>3</td>
<td>4</td>
</tr>
<tr>
<td>5</td>
<td rowspan="2" colspan="2">7</td>
</tr>
<tr>
<td>6</td>
</tr>
<tr>
<td>8</td>
<td colspan="2">9</td>
<td>10</td>
</tr>
</table>
Here's my CSS:
table {
border: 1px solid;
width: 400px;
height: 300px;
}
There are 2 algorithms for tables in CSS, triggered by the property table-layout:
table-layout:fixed will adapt cell widths to what the author (you) want, as far as possible
table-layout:auto (default value) will adapt cell widths to their content.
CSS
table {
table-layout: fixed;
width: 400px;
height: 300px;
border: 1px solid;
}
Here's a fiddle: http://jsfiddle.net/tk4J8/
Don't use column-width to specify width of table columns - it's a suggested optimal guideline for browsers that isn't really meant for fixed width layouts. Use colgroups instead.
Remove the column-width style in your stylesheet, and add this to your table tag before any tr or td tags:
<colgroup>
<col span="1"></col>
<col span="1"></col>
<col span="1"></col>
<col span="1"></col>
</colgroup>
And add this to your stylesheet:
colgroup col {
width: 100px;
}
jsFiddle.
Here's the Mozilla documentation for it.
I am trying to design a page where there are some tables. It seems that styling tables is much more painful than it ought to be.
The problem is the following: The tables should have a fixed height and display either white space at the bottom (when there is too little content) or a vertical scrollbar (when there is too much). Add to this that the tables have a header which should not scroll.
As far as I know, the thead not scrolling is the default behaviour for tables. And a stretching tfoot could serve well for the purpose of filling with white space. Sadly, it seems that every constraint I can put on the table height is cheerfully ignored. I have tried
table {
height: 600px;
overflow: scroll;
}
I have tried with max-height. I have tried to position the table absolutely and give both the top and bottom coordinates. I have tried to manually edit the height in Firebug to see if it was a problem with CSS specificity. I have tried to set the height on the tbody too. Fact is, the table always stays exactly the same height as its content, regardless of my efforts.
Of course I could fake a table with a div structure, but it actually is a table, and I fear using divs I may run into an issue where some columns may not be properly aligned.
How am I supposed to give a table a height?
NOTE this answer is now incorrect. I may get back to it at a later time.
As others have pointed out, you can't set the height of a table unless you set its display to block, but then you get a scrolling header. So what you're looking for is to set the height and display:block on the tbody alone:
<table style="border: 1px solid red">
<thead>
<tr>
<td>Header stays put, no scrolling</td>
</tr>
</thead>
<tbody style="display: block; border: 1px solid green; height: 30px; overflow-y: scroll">
<tr>
<td>cell 1/1</td>
<td>cell 1/2</td>
</tr>
<tr>
<td>cell 2/1</td>
<td>cell 2/2</td>
</tr>
<tr>
<td>cell 3/1</td>
<td>cell 3/2</td>
</tr>
</tbody>
</table>
Here's the fiddle.
Set display: block; for the table
Set position: sticky; top: 0; for the header row
<table style="display: block; height: 100px; overflow: auto;">
<thead>
<tr>
<td style="position: sticky; top: 0;">Header stays put</td>
<td style="position: sticky; top: 0;">Layout aligned</td>
</tr>
</thead>
<tbody>
<tr>
<td>foo1</td>
<td>Header stays put</td>
</tr>
<tr>
<td>foo2</td>
<td>Header stays put</td>
</tr>
</tbody>
</table>
https://jsfiddle.net/0zxk18fp/
Tested on Chrome, Firefox, Safari, Edge
Add display:block; to the table's css. (in other words.. tell the table to act like a block element rather than a table.)
fiddle here
You can do this by using the following css.
.scroll-thead{
width: 100%;
display: inline-table;
}
.scroll-tbody-y
{
display: block;
overflow-y: scroll;
}
.table-body{
height: /*fix height here*/;
}
Following is the HTML.
<table>
<thead class="scroll-thead">
<tr>
<th>Key</th>
<th>Value</th>
</tr>
</thead>
<tbody class="scroll-tbody-y table-body">
<tr>
<td>Blah</td>
<td>Blah</td>
</tr>
</tbody>
</table>
JSFiddle
I had a coworker ask how to do this today, and this is what I came up with. I don't love it but it is a way to do it without js and have headers respected. The main drawback however is you lose some semantics due to not having a true table header anymore.
Basically I wrap a table within a table, and use a div as the scroll container by giving it a max-height. Since I wrap the table in a parent table "colspanning" the fake header rows it appears as if the table respects them, but in reality the child table just has the same number of rows.
One small issue due to the scroll bar taking up space the child table column widths wont match up exactly.
Live Demo
Markup
<table class="table-container">
<tbody>
<tr>
<td>header col 1</td>
<td>header col 2</td>
</tr>
<tr>
<td colspan="2">
<div class="scroll-container">
<table>
<tr>
<td>entry1</td>
<td>entry1</td>
</tr>
........ all your entries
</table>
</div>
</td>
</tr>
</tbody>
</table>
CSS
.table-container {
border:1px solid #ccc;
border-radius: 3px;
width:50%;
}
.table-container table {
width: 100%;
}
.scroll-container{
max-height: 150px;
overflow-y: scroll;
}
Seems very similar to this question. From there it seems that this should do the trick:
table {
display: block; /* important */
height: 600px;
overflow-y: scroll;
}
A simple workaround that is available in most of the cases it to wrap the table in a div and then give a max-height to that div:
.scrollable-wrapper {
max-height: 400px;
overflow: auto;
}
/* Add also the following code if sticky header is wanted */
.scrollable-wrapper table thead th {
background: #afa;
position: sticky;
top: 0;
box-shadow: 0 2px 2px -1px rgba(0, 0, 0, 0.4);
}
<div class="scrollable-wrapper">
<table>
<thead>
<tr>
<th>Id</th>
<th>Text</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
Codepen: https://codepen.io/Conejoo/pen/NWpjmYw
In Tables, For minimum table cells height or rows height use css height: in place of min-height:
AND
For Limiting max-height of all cells or rows in table with Javascript:
This script is good for horizontal overflow tables.
This script increase the table width 300px each time (maximum 4000px) until rows shrinks to max-height(160px) , and you can also edit numbers as your need.
var i = 0, row, table = document.getElementsByTagName('table')[0], j = table.offsetWidth;
while (row = table.rows[i++]) {
while (row.offsetHeight > 160 && j < 4000) {
j += 300;
table.style.width = j + 'px';
}
}
Source: HTML Table Solution Max Height Limit For Rows Or Cells By Increasing Table Width, Javascript
Use divs with max height and min height around the content that needs to scroll.
<tr>
<td>
<div>content</div>
</td>
</tr>
td div{
max-height:20px;
}
https://jsfiddle.net/ethanabrace/4w0ksczr/
Just try this.
<div style="max-height: 400px; overflow: scroll">
<!--This is your table-->
<table style="border: 1px solid red">
<thead>
<tr>
<td>Header stays put, no scrolling</td>
</tr>
</thead>
<tbody style="display: block; border: 1px solid green; height: 30px; overflow-y: scroll">
<tr>
<td>cell 1/1</td>
<td>cell 1/2</td>
</tr>
<tr>
<td>cell 2/1</td>
<td>cell 2/2</td>
</tr>
<tr>
<td>cell 3/1</td>
<td>cell 3/2</td>
</tr>
</tbody>
</table>
</div>
<table style="border: 1px solid red">
<thead>
<tr>
<td>Header stays put, no scrolling</td>
</tr>
</thead>
<tbody id="tbodyMain" style="display: block; border: 1px solid green; height: 30px; overflow-y: scroll">
<tr>
<td>cell 1/1</td>
<td>cell 1/2</td>
</tr>
<tr>
<td>cell 2/1</td>
<td>cell 2/2</td>
</tr>
<tr>
<td>cell 3/1</td>
<td>cell 3/2</td>
</tr>
</tbody>
</table>
Javascript Section
<script>
$(document).ready(function(){
var maxHeight = Math.max.apply(null, $("body").map(function () { return $(this).height(); }).get());
// alert(maxHeight);
var borderheight =3 ;
// Added some pixed into maxheight
// If you set border then need to add this "borderheight" to maxheight varialbe
$("#tbodyMain").css("min-height", parseInt(maxHeight + borderheight) + "px");
});
</script>
please, refer How to set maximum possible height to your Table Body Fiddle Here