Reputation: 80
I was tasked with creating a table that would be used as the major portion of a layout. The header of the table should be static while body should scroll if necessary. The issue is that if the scrollbar is needed, the columns of the table becomes misaligned because the width of the tbody changes.
I used a bit of javascript to compensate by setting the right padding on the thead to be equal to the width of the scrollbar, and planned to use a listener to remove / add back the padding as the scrollbar disappeared / appeared.
While this approach worked to keep the columns aligned, I was asked to come up with an HTML/CSS only solution if possible. Does anyone know of a way to achieve this without any js? Thanks.
Some relevant CSS I currently have:
table {
width: 100%;
border-collapse: collapse;
}
table tbody {
position: absolute;
top: 24px;
left: 0;
right: 0;
bottom: 0;
overflow-y: auto;
}
table thead {
position: absolute;
top: 0;
left: 0;
right: 0;
}
Here is a fiddle to see the whole example: http://jsfiddle.net/kirky93/qqv73kjo/5/
Drag the viewport up/down to make the scrollbar dis/appear to see the issue.
Upvotes: 3
Views: 8985
Reputation: 24702
To eliminate the misalignment with pure CSS, we can get the scrollbar to push the header aside. We can do this by making it position: fixed
so that the scroll bar on the tbody extends to the top of the viewport.
Too much to read? Skip to the example at the bottom.
Use seven <col>
elements, one to represent each column. We can place the class on them with width and background color and these properties will be repeated for the entire column without having to put a class on each table cell. They look like this:
<table class="fixed">
<col class="one">
<col class="two">
<col class="three">
<col class="four">
<col class="five">
<col class="six">
<col class="seven">
In order to place a width
CSS property on the columns, we can set table-layout: fixed
on the table element. No matching min/max widths are needed now.
position: fixed
display: table
to make it behave like a table againtable-layout: fixed
so that the width behave properly<col>
elements, set the column classes on each th
position: static
Note the box-sizing: border-box
which makes elements include padding and borders into their widths and heights.
html {
box-sizing: border-box;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
body {
margin: 0;
}
table {
border-collapse: collapse;
background: #FFF;
table-layout: fixed;
width: 100%;
}
table thead {
position: fixed;
top: 0;
left: 0;
width: 100%;
background: #FFF;
display: table;
table-layout: fixed;
border: solid 1px #000;
}
table tbody {
margin-top: 24px;
}
table {
/*Make sure table has border that matches the cell border so it is included in the width*/
border: 1px solid black;
}
td,
th {
height: 20px;
border: 1px solid black;
}
.one {
width: 30px;
background-color: yellow;
}
.two {
width: 30px;
background-color: orange;
}
.three {
width: 30px;
background-color: red;
}
.four {
width: 100%;
}
.five {
width: 100px;
background-color: green;
}
.six {
width: 100px;
background-color: lightblue;
}
.seven {
width: 100px;
}
<table class="fixed">
<col class="one">
<col class="two">
<col class="three">
<col class="four">
<col class="five">
<col class="six">
<col class="seven">
<thead>
<tr>
<th class="one">1</th>
<th class="two">2</th>
<th class="three">3</th>
<th class="four">4</th>
<th class="five">5</th>
<th class="six">6</th>
<th class="seven">7</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
<td>6</td>
<td>7</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
<td>6</td>
<td>7</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
<td>6</td>
<td>7</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
<td>6</td>
<td>7</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
<td>6</td>
<td>7</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
<td>6</td>
<td>7</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
<td>6</td>
<td>7</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
<td>6</td>
<td>7</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
<td>6</td>
<td>7</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
<td>6</td>
<td>7</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
<td>6</td>
<td>7</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
<td>6</td>
<td>7</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
<td>6</td>
<td>7</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
<td>6</td>
<td>7</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
<td>6</td>
<td>7</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
<td>6</td>
<td>7</td>
</tr>
</tbody>
</table>
Upvotes: 3
Reputation: 51958
just set it to overflow:scroll on the tbody instead of auto
table tbody {
position: absolute;
top: 24px;
left: 0;
right: 0;
bottom: 0;
overflow-y: scroll;
}
Upvotes: 2