How to create HTML tables with fixed header using CSS

In one of my recent project I had to display data in HTML table with header row remains fixed and body can be scrolled vertically.

Since the html was generated on server and rendered directly on browser, I thought of using only css do this. Check the code bellow.


# Skill Name Experience Expertise
1. .Net Framework 15 Years Expert
2. ASP.Net Web Forms 15 Years Expert
3. ASP.Net MVC 10 Years Expert
4. C# 15 Years Expert
5. VB.Net 15 Years Expert
6. JavaScript 15 Years Expert
7. jQuery 10 Years Expert
8. SQL Server 15 Years Expert
9. Entity Framework 6 Years Expert
10. HTML5 4 Years Expert
11. Twitter Bootstrap 8 Years Expert
12. Angular JS 3 Years Professional
13. ReactJS 3 Years Professional


    <table class="fixedHeader">
                <th style="width:30px;">#</th>
                <th style="width:200px;">Skill Name</th>
                <th style="width:150px;">Experience</th>
                <th style="width:150px;">Expertise</th>
                <td style="width:30px;">1.</td>
                <td style="width:200px;">.Net Framework</td>
                <td style="width:150px;">15 Years</td>
                <td style="width:150px;">Expert</td>
                <td style="width:30px;">2.</td>
                <td style="width:200px;">ASP.Net Web Forms</td>
                <td style="width:150px;">15 Years</td>
                <td style="width:150px;">Expert</td>
            ...add more rows here

        //this is decorative only
        .fixedHeader td, .fixedHeader th {
        border: 1px solid;
        border-color: cadetblue;
        text-align: left;
        padding: 5px;

        //This is important
        .fixedHeader > thead, .fixedHeader > tbody {
        display: block;

        //set max height and overflow properties
        .fixedHeader > tbody {
        max-height: 300px;
        overflow: auto;


There are two important aspects this solution.

  1. Each td and th has a specific width.

    Setting width of each cell will enable browser to enforce it rather than calculate the best fit.

  2. tbody and thead are set to display-block

    This is required so that body and head can be independent of the table tag.