How to Specify Table's Height Such That a Vertical Scroll Bar Appears

How to specify table's height such that a vertical scroll bar appears?

Try using the overflow CSS property. There are also separate properties to define the behaviour of just horizontal overflow (overflow-x) and vertical overflow (overflow-y).

Since you only want the vertical scroll, try this:

table {
height: 500px;
overflow-y: scroll;
}

EDIT:

Apparently <table> elements don't respect the overflow property. This appears to be because <table> elements are not rendered as display: block by default (they actually have their own display type). You can force the overflow property to work by setting the <table> element to be a block type:

table {
display: block;
height: 500px;
overflow-y: scroll;
}

Note that this will cause the element to have 100% width, so if you don't want it to take up the entire horizontal width of the containing element, you need to specify an explicit width for the element as well.

How to set tbody height with overflow scroll

If you want tbody to show a scrollbar, set its display: block;.

Set display: table; for the tr so that it keeps the behavior of a table.

To evenly spread the cells, use table-layout: fixed;.

DEMO tbody scroll


CSS:

table, tr td {
border: 1px solid red
}
tbody {
display: block;
height: 50px;
overflow: auto;
}
thead, tbody tr {
display: table;
width: 100%;
table-layout: fixed;/* even columns width , fix width of table too*/
}
thead {
width: calc( 100% - 1em )/* scrollbar is average 1em/16px width, remove it from thead width */
}
table {
width: 400px;
}

If tbody doesn't show a scroll, because content is less than height or max-height, set the scroll any time with: overflow-y: scroll;. DEMO 2


<editS/updateS> 2019 - 04/2021



  • Important note: this approach to making a table scrollable has drawbacks in some cases. (See comments below.) some of the duplicate answers in this thread deserves the same warning by the way

WARNING: this solution disconnects the thead and tbody cell grids; which means that in most practical cases, you will not have the cell alignment you expect from tables. Notice this solution uses a hack to keep them sort-of aligned: thead { width: calc( 100% - 1em ) }

  • Anyhow, to set a scrollbar, a display reset is needed to get rid of the table-layout (which will never show scrollbar).

  • Turning the <table> into a grid via display:grid/contents will also leave a gap in between header and scrollable part, to mind about. (idem if built from divs)

  • overflow:overlay; has not yet shown up in Firefox ( keep watching it)

  • position:sticky will require a parent container which can be the scrolling one. make sure your thead can be sticky if you have a few rows and rowspan/colspan headers in it (it does not with chrome).

So far, there is no perfect solution yet via CSS only. there is a few average ways to choose along so it fits your own table (table-layout:fixed; is .. fixing table and column's width, but javascript could probably be used to reset those values => exit pure CSS)

How do I make a table show a vertical scroll bar without explicitly setting the height?

I managed to do this in the end so putting the code here in case anyone else needs it.

*,*:before,*:after {  -moz-box-sizing: border-box;  -webkit-box-sizing: border-box;  box-sizing: border-box;}html,body {  width: 100%;  height: 100%;  margin: 0;  padding: 0;}#main-content {  height: 100%;  display: flex;  flex-direction: row;}#field-table-area {  /*width: 100%;*/  height: 100%;  display: flex;  flex-direction: column;}.field-area {  border-bottom: 1px darkgrey solid;  padding: 4px;  background-color: aliceblue;}.flexbox-item-grow {  flex: 1;  /* same as flex: 1 1 auto; */}#field-selection-area {  /*height: 100%;*/  overflow: auto;  border-right: 1px darkgrey solid;}#field-selection-area ul {  list-style: none;  padding: 4px;  margin: 0;}#field-selection-area ul li {  padding: 2px;  white-space: nowrap;}#field-selection-area ul li:hover {  border: 1px darkgrey solid;  border-radius: 3px;  padding: 1px;  background-color: rgb(220, 230, 241);}#table-area {  display: flex;  flex-direction: row;}#table-holder {  overflow: auto;}#table-holder table td {  border: 1px darkgrey solid;}
<!DOCTYPE html><html>
<head lang="en"> <meta charset="UTF-8"> <title>Pivot Web</title> <link rel="stylesheet" href="style4.css"></head>
<body>
<div id="main-content"> <div id="field-selection-area"> <ul class="no-text-selection"> <li draggable="true">Period</li> <li draggable="true">Market</li> <li draggable="true">Trade ID</li> <li draggable="true">Something</li> <li draggable="true">Something Space</li> </ul> </div>
<div id="field-table-area" class="flexbox-item-grow"> <div id="field-config-area"> <div id="filter-field-area" class="no-text-selection field-area"> Drop Filter Fields Here </div>
<div id="row-field-area" class="no-text-selection field-area"> Drop Row Fields Here </div>
<div id="column-field-area" class="no-text-selection field-area"> Drop Column Fields Here </div> </div>
<div id="table-area" class="flexbox-item-grow"> <div id="table-holder" class="flexbox-item-grow"> <table> <tr> <td>18.0</td> <td>18.0</td> <td>18.0</td> <td>18.0</td> <td>18.0</td> <td>18.0</td> <td>18.0</td> <td>18.0</td> <td>18.0</td> <td>18.0</td> <td>18.0</td> <td>18.0</td> <td>18.0</td> <td>18.0</td> <td>18.0</td> </tr> <tr> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> </tr> <tr> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> </tr> <tr> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> </tr> <tr> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> <td>5.3</td> </tr> </table> </div> </div> </div> </div>
</body>
</html>

HTML table with 100% width, with vertical scroll inside tbody

In order to make <tbody> element scrollable, we need to change the way it's displayed on the page i.e. using display: block; to display that as a block level element.

Since we change the display property of tbody, we should change that property for thead element as well to prevent from breaking the table layout.

So we have:

thead, tbody { display: block; }

tbody {
height: 100px; /* Just for the demo */
overflow-y: auto; /* Trigger vertical scroll */
overflow-x: hidden; /* Hide the horizontal scroll */
}

Web browsers display the thead and tbody elements as row-group (table-header-group and table-row-group) by default.

Once we change that, the inside tr elements doesn't fill the entire space of their container.

In order to fix that, we have to calculate the width of tbody columns and apply the corresponding value to the thead columns via JavaScript.

Auto Width Columns

Here is the jQuery version of above logic:

// Change the selector if needed
var $table = $('table'),
$bodyCells = $table.find('tbody tr:first').children(),
colWidth;

// Get the tbody columns width array
colWidth = $bodyCells.map(function() {
return $(this).width();
}).get();

// Set the width of thead columns
$table.find('thead tr').children().each(function(i, v) {
$(v).width(colWidth[i]);
});

And here is the output (on Windows 7 Chrome 32):

vertical scroll inside tbody

WORKING DEMO.

Full Width Table, Relative Width Columns

As the Original Poster needed, we could expand the table to 100% of width of its container, and then using a relative (Percentage) width for each columns of the table.

table {
width: 100%; /* Optional */
}

tbody td, thead th {
width: 20%; /* Optional */
}

Since the table has a (sort of) fluid layout, we should adjust the width of thead columns when the container resizes.

Hence we should set the columns' widths once the window is resized:

// Adjust the width of thead cells when *window* resizes
$(window).resize(function() {
/* Same as before */
}).resize(); // Trigger the resize handler once the script runs

The output would be:

Fluid Table with vertical scroll inside tbody

WORKING DEMO.


Browser Support and Alternatives

I've tested the two above methods on Windows 7 via the new versions of major Web Browsers (including IE10+) and it worked.

However, it doesn't work properly on IE9 and below.

That's because in a table layout, all elements should follow the same structural properties.

By using display: block; for the <thead> and <tbody> elements, we've broken the table structure.

Redesign layout via JavaScript

One approach is to redesign the (entire) table layout. Using JavaScript to create a new layout on the fly and handle and/or adjust the widths/heights of the cells dynamically.

For instance, take a look at the following examples:

  • jQuery .floatThead() plugin (a floating/locked/sticky table header plugin)
  • jQuery Scrollable Table plugin. (source code on github)
  • jQuery .FixedHeaderTable() plugin (source code on github)
  • DataTables vertical scrolling example.

Nesting tables

This approach uses two nested tables with a containing div. The first table has only one cell which has a div, and the second table is placed inside that div element.

Check the Vertical scrolling tables at CSS Play.

This works on most of web browsers. We can also do the above logic dynamically via JavaScript.

Table with fixed header on scroll

Since the purpose of adding vertical scroll bar to the <tbody> is displaying the table header at the top of each row, we could position the thead element to stay fixed at the top of the screen instead.

Here is a Working Demo of this approach performed by Julien.

It has a promising web browser support.

And here a pure CSS implementation by Willem Van Bockstal.


The Pure CSS Solution

Here is the old answer. Of course I've added a new method and refined the CSS declarations.

Table with Fixed Width

In this case, the table should have a fixed width (including the sum of columns' widths and the width of vertical scroll-bar).

Each column should have a specific width and the last column of thead element needs a greater width which equals to the others' width + the width of vertical scroll-bar.

Therefore, the CSS would be:

table {
width: 716px; /* 140px * 5 column + 16px scrollbar width */
border-spacing: 0;
}

tbody, thead tr { display: block; }

tbody {
height: 100px;
overflow-y: auto;
overflow-x: hidden;
}

tbody td, thead th {
width: 140px;
}

thead th:last-child {
width: 156px; /* 140px + 16px scrollbar width */
}

Here is the output:

Table with Fixed Width

WORKING DEMO.

Table with 100% Width

In this approach, the table has a width of 100% and for each th and td, the value of width property should be less than 100% / number of cols.

Also, we need to reduce the width of thead as value of the width of vertical scroll-bar.

In order to do that, we need to use CSS3 calc() function, as follows:

table {
width: 100%;
border-spacing: 0;
}

thead, tbody, tr, th, td { display: block; }

thead tr {
/* fallback */
width: 97%;
/* minus scroll bar width */
width: -webkit-calc(100% - 16px);
width: -moz-calc(100% - 16px);
width: calc(100% - 16px);
}

tr:after { /* clearing float */
content: ' ';
display: block;
visibility: hidden;
clear: both;
}

tbody {
height: 100px;
overflow-y: auto;
overflow-x: hidden;
}

tbody td, thead th {
width: 19%; /* 19% is less than (100% / 5 cols) = 20% */
float: left;
}

Here is the Online Demo.

Note: This approach will fail if the content of each column breaks the line, i.e. the content of each cell should be short enough.


In the following, there are two simple example of pure CSS solution which I created at the time I answered this question.

Here is the jsFiddle Demo v2.

Old version: jsFiddle Demo v1

vertical scrollbar appears when width is larger than 100vw

The viewport unit are relative to the viewport so if a horizontal scroll bar appear it means that this scroll bar will take space thus we need the vertical scroll in order to see the part hidden by the horizontal one.

To avoid this keep using only the vw unit and use % instead of vh so the height will be relative to the parent instead of the viewport. I have also removed the margin and adjusted the top and left values to make the block centred

* {  padding: 0;  margin: 0;}
body,html { height: 100%;}
.outer { position: relative; top: 0; left: 0; height: 100%; width: 105vw; /* This won't create a vertical scroll*/ overflow: hidden; background-color: lightyellow;}
.bg { height: 80%; width: 80vw; top: 50%; transform: translateY(-50%); position: absolute;}
.bg1 { background-color: #80c9be; left: 10vw;}
.bg2 { background-color: #e99790; left: 110vw;}
.bg3 { background-color: #f2e2cd; left: 210vw;}
.bg4 { background-color: #48697f; left: 310vw;}
<div class="outer">  <div class="bg bg1">  </div>  <div class="bg bg2">  </div>  <div class="bg bg3">  </div>  <div class="bg bg4">  </div></div>

Vertical scroll bar appearing even when height is not set

You have a parent container div.tabData whose height is determined by the total heights of the child elements, of which there are two, the inner <div> and the anonymous block that contains the word "Hello".

The inner div has a height of 390px and the "Hello" line takes up about 1.5em. Therefore, the parent element with the yellow background is just big enough to enclose the 390px inner div and the one line of text.

If you add enough content to the inner div, the text will eventually flow outside of the inner div that has the green background. This is how browsers work by default, they try to make the text visible no matter what.

However, as far as the parent element is concerned, it has the right height based on 390px + height-of-1-line-of-text. Browsers will not recalculate a block element's height when text overflows out of a fixed height child element.

If you continue to add more text to the inner div, it starts to flow over any text in the parent element, and eventually, it will overflow the parent container and cause a vertical scroll bar to appear since you set overflow: auto on the parent element.

On the other hand, is you had not fixed the height of the inner div, you would get the expected behavior, the inner div expands to contain all its content, and the parent div expands to enclose both the inner div and the one line of text.

Example

If you try the following fiddle, http://jsfiddle.net/audetwebdesign/s3bnJ/, and adjust the horizontal width, you can see the text from the inner div flow out of the inner div and into the parent div, and eventually, you will see the scroll bar appear.

Why vertical scroll bar appearing when height is 100%?

For two reasons

  1. The body has a default margin that you'd need to eliminate with body {margin:0}
  2. The the other issue is that your borders factor into the size of your elements and increase the height. You can fix this by adding div {box-sizing:border-box}

jsFiddle example



Related Topics



Leave a reply



Submit