1

The problem I'm facing is the following. I've written a JavaScript function to make a scrollable table. The reason I use JavaScript is to spare me of the cross browser compatibility issues I'd have with CSS. Since the number of table-rows are quite limited, a maximum of 40 rows, the overhead of using JavaScript seems to be no issue. The code is shown here:

function correctTableHeaderSize(){
    var count = 0;
    var sizes = [];
    $("#table").find("th").each(function(){
        sizes[count] = $(this)[0].clientWidth;
        count++;
    });
    $("#table").find("tbody").children("tr").each(function(){   
        counter=0;
        $(this).children("td").each(function(){
            if($(this).next().is("td")){            
                $(this).css('width',sizes[counter]);
                counter++;
            }
        });
    });
    $("#table").prop("hidden",false);
}

What it does:

  1. Get the width of all table headers (of table with id "table") and store these in an array
  2. for all rows in the table body, get the child cells and set there width to match the width of their corresponding table header.

This worked fine until I noticed an annoying fact, that is starting to turn in to a serious problem. The table headers and the corresponding cells underneath are not the same size. They differ a few pixels. The wider the header gets, the greater this difference is.

Using Firebug I noticed for example that a th element with a width of 30%, defined with inline css was translated to a scroll-width of 406px, this was also the value I've found in the array containing these widths, but after the JavaScript function finished the scroll-width of the corresponding table cells were 419px, while the css applied to this element shows a width of 406px. Somewhere, somehow 13px were added, although margin and padding for th and td are set to 0. The reason I checked the scroll-width is based on this topic explaining all sorts of width properties, this way I'm sure I take the total sizes into account. See the snippet for an example of the code.

function correctTableColumns() {
    var count = 0;
    var sizes = [];
    $("#table").find("th").each(function() {
      sizes[count] = $(this)[0].clientWidth;
      count++;
    });
    $("#table").find("tbody").children("tr").each(function() {
      counter = 0;
      $(this).children("td").each(function() {
        if ($(this).next().is("td")) { //this to let the last cell take al available space, this way the scrollbar width is not an issue
          $(this).css('width', sizes[counter]);
          counter++;
        }
      });
    });
    $("#table").prop("hidden", false);
 }
table.scrollTable {
  width: 100%;
}
table.scrollTable thead,
table.scrollTable tbody {
  float: left;
  width: 100%;
}
table.scrollTable tbody {
  overflow-y: scroll;
  height: 50px;
  width: 100%;
}
table.scrollTable th {
  white-space: normal;
  margin: 0px;
  padding: 0px;
}
table.scrollTable td {
  margin: 0px;
  padding: 0px;
}
table.scrollTable tr {
  width: 100%;
  display: table;
}
table.scrollTable thead {
  overflow: false;
  position: relative;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>

<body>
  <table id="table" class="scrollTable" bgcolor="#94BAE7">
    <THEAD>
      <TR width=\ "100%\">
        <TH bgcolor="#CCFF99" width="8%">Col1</TH>
        <TH bgcolor="#FFA347" width="8%">Col2</TH>
        <TH bgcolor="#CCFF99" width="30%">Col3</TH>
        <TH bgcolor="#FFA347" width="2%">Col4</TH>
        <TH bgcolor="#CCFF99" width="8%">Col5</TH>
        <TH bgcolor="#FFA347" width="8%">Col6</TH>
        <TH bgcolor="#CCFF99" width="2%">Col7</TH>
        <TH bgcolor="#FFA347" width="30%">Col8</TH>
        <TH bgcolor="#CCFF99" width="3%">Col9</TH>
        <TH></TH>
      </TR>
    </THEAD>
    <TBODY>
      <tr>
        <td bgcolor="#CCFF99">10</td>
        <td bgcolor="#FFA347">10</td>
        <td bgcolor="#CCFF99">I am short</td>
        <td bgcolor="#FFA347">100</td>
        <td bgcolor="#CCFF99">100</td>
        <td bgcolor="#FFA347">100</td>
        <td bgcolor="#CCFF99">100</td>
        <td bgcolor="#FFA347">10</td>
        <td bgcolor="#CCFF99">foo</td>
      </tr>
      <tr>
        <td bgcolor="#CCFF99">10</td>
        <td bgcolor="#FFA347">10</td>
        <td bgcolor="#CCFF99">I am a longer sentence</td>
        <td bgcolor="#FFA347">100</td>
        <td bgcolor="#CCFF99">100</td>
        <td bgcolor="#FFA347">100</td>
        <td bgcolor="#CCFF99">100</td>
        <td bgcolor="#FFA347">10</td>
        <td bgcolor="#CCFF99">foo</td>
      </tr>
    </TBODY>
  </table>
  <input type="button" value="Repair this table" onclick="correctTableColumns();"> 
 </body>
</html>

Does anyone have an idea how this small difference in widths is possible?

Solution

The problem was indeed the width of one the columns but the source of this issue was not the text that was too long but rather a hidden td at the end of each tr. this contained an image that is shown if a certain condition is met.

This hidden td should've taken up the remaining space in the tr, but since it was hidden, it took no space at all. The remaining space was then filled up by the other td's which all got a piece of the remaining space. Therefore the small size-difference on each td. By making the image and not the parent td hidden this issue was solved.

Since the comment of Raidri fixed the issue in the snippet and put me on the right track I've upvoted his answer (but I do not have sufficient rights to do this, I'm sorry). Thank you

Community
  • 1
  • 1
DemanB
  • 47
  • 6
  • 1
    Sorry if I seem dumb to ask this, but cells automatically match the largest width in their column without tweaking their width, but why do you do so?... – qtgye Apr 08 '15 at 10:34
  • to fixe table td widths , you need to use the table-layout properties : http://www.w3.org/wiki/CSS/Properties/table-layout – G-Cyrillus Apr 08 '15 at 11:11
  • To answer qtgye: When using css "overflow-y: auto" on the tbody, but not on the the thead, the columnwidth of columns in tbody are not equal to these in the thead element. Which is why I need to correct them. When you run the snippet this behaviour is shown. Although there might be better ways to fix this, my solution gives me no issues when used on different browsers. – DemanB Apr 08 '15 at 15:17

2 Answers2

1

You are trying to set the width of the cells with foo so small that it cannot contain the text. Because of this it is automatically made bigger by the browser and other columns / cells are getting smaller in the process. If you give that column more width to begin with, it all works:

function correctTableColumns() {
    var count = 0;
    var sizes = [];
    $("#table").find("th").each(function() {
      sizes[count] = $(this).css('width');
      count++;
    });
    $("#table").find("tbody").children("tr").each(function() {
      counter = 0;
      $(this).children("td").each(function() {
        if ($(this).next().is("td")) { //this to let the last cell take al available space, this way the scrollbar width is not an issue
          $(this).css('width', sizes[counter]);
          counter++;
        }
      });
    });
    $("#table").prop("hidden", false);
 }
table.scrollTable {
  width: 100%;
}
table.scrollTable thead,
table.scrollTable tbody {
  float: left;
  width: 100%;
}
table.scrollTable tbody {
  overflow-y: scroll;
  height: 50px;
  width: 100%;
}
table.scrollTable th {
  white-space: normal;
  margin: 0px;
  padding: 0px;
}
table.scrollTable td {
  margin: 0px;
  padding: 0px;
}
table.scrollTable tr {
  width: 100%;
  display: table;
}
table.scrollTable thead {
  overflow: false;
  position: relative;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>

<body>
  <table id="table" class="scrollTable" bgcolor="#94BAE7">
    <THEAD>
      <TR width=\ "100%\">
        <TH bgcolor="#CCFF99" width="8%">Col1</TH>
        <TH bgcolor="#FFA347" width="8%">Col2</TH>
        <TH bgcolor="#CCFF99" width="30%">Col3</TH>
        <TH bgcolor="#FFA347" width="2%">Col4</TH>
        <TH bgcolor="#CCFF99" width="8%">Col5</TH>
        <TH bgcolor="#FFA347" width="8%">Col6</TH>
        <TH bgcolor="#CCFF99" width="2%">Col7</TH>
        <TH bgcolor="#FFA347" width="25%">Col8</TH>
        <TH bgcolor="#CCFF99" width="10%">Col9</TH>
        <TH></TH>
      </TR>
    </THEAD>
    <TBODY>
      <tr>
        <td bgcolor="#CCFF99">10</td>
        <td bgcolor="#FFA347">10</td>
        <td bgcolor="#CCFF99">I am short</td>
        <td bgcolor="#FFA347">100</td>
        <td bgcolor="#CCFF99">100</td>
        <td bgcolor="#FFA347">100</td>
        <td bgcolor="#CCFF99">100</td>
        <td bgcolor="#FFA347">10</td>
        <td bgcolor="#CCFF99">foo</td>
      </tr>
      <tr>
        <td bgcolor="#CCFF99">10</td>
        <td bgcolor="#FFA347">10</td>
        <td bgcolor="#CCFF99">I am a longer sentence</td>
        <td bgcolor="#FFA347">100</td>
        <td bgcolor="#CCFF99">100</td>
        <td bgcolor="#FFA347">100</td>
        <td bgcolor="#CCFF99">100</td>
        <td bgcolor="#FFA347">10</td>
        <td bgcolor="#CCFF99">foo</td>
      </tr>
    </TBODY>
  </table>
  <input type="button" value="Repair this table" onclick="correctTableColumns();"> 
 </body>
</html>
Raidri
  • 17,258
  • 9
  • 62
  • 65
  • This put me on the right way. I've explained the problem in an edit of my original question. Thank you for your help – DemanB Apr 08 '15 at 14:50
0

You need to use the table-layout propertie to control widths of your cells


CodePen javascript is avalaible in codepen, just click your repair button to see your script efficient.


function correctTableColumns() {
    var count = 0;
    var sizes = [];
    $("#table").find("th").each(function() {
      sizes[count] = $(this)[0].clientWidth;
      count++;
    });
    $("#table").find("tbody").children("tr").each(function() {
      counter = 0;
      $(this).children("td").each(function() {
        if ($(this).next().is("td")) { //this to let the last cell take al available space, this way the scrollbar width is not an issue
          $(this).css('width', sizes[counter]);
          counter++;
        }
      });
    });
    $("#table").prop("hidden", false);
 }
table.scrollTable {
  width: 100%;
  table-layout:fixed;/* here set widths even for cells or as set in CSS*/
}
table.scrollTable thead,
table.scrollTable tbody {
  float: left;
  width: 100%;
}
table.scrollTable tbody {
  overflow-y: scroll;
  height: 50px;
  width: 100%;
}
table.scrollTable th {
  white-space: normal;
  margin: 0px;
  padding: 0px;
}
table.scrollTable td {
  margin: 0px;
  padding: 0px;
}
table.scrollTable tr {
  width: 100%;
  display: table;
  table-layout:fixed;/* here set widths even for cells or as set in CSS*/
}
table.scrollTable thead {
  overflow: false;
  position: relative;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>

<body>
  <table id="table" class="scrollTable" bgcolor="#94BAE7">
    <THEAD>
      <TR width= "100%">
        <TH bgcolor="#CCFF99" width="8%">Col1</TH>
        <TH bgcolor="#FFA347" width="8%">Col2</TH>
        <TH bgcolor="#CCFF99" width="30%">Col3</TH>
        <TH bgcolor="#FFA347" width="2%">Col4</TH>
        <TH bgcolor="#CCFF99" width="8%">Col5</TH>
        <TH bgcolor="#FFA347" width="8%">Col6</TH>
        <TH bgcolor="#CCFF99" width="2%">Col7</TH>
        <TH bgcolor="#FFA347" width="30%">Col8</TH>
        <TH bgcolor="#CCFF99" width="3%">Col9</TH>
        <TH></TH>
      </TR>
    </THEAD>
    <TBODY>
      <tr>
        <td bgcolor="#CCFF99">10</td>
        <td bgcolor="#FFA347">10</td>
        <td bgcolor="#CCFF99">I am short</td>
        <td bgcolor="#FFA347">100</td>
        <td bgcolor="#CCFF99">100</td>
        <td bgcolor="#FFA347">100</td>
        <td bgcolor="#CCFF99">100</td>
        <td bgcolor="#FFA347">10</td>
        <td bgcolor="#CCFF99">foo</td>
      </tr>
      <tr>
        <td bgcolor="#CCFF99">10</td>
        <td bgcolor="#FFA347">10</td>
        <td bgcolor="#CCFF99">I am a longer sentence</td>
        <td bgcolor="#FFA347">100</td>
        <td bgcolor="#CCFF99">100</td>
        <td bgcolor="#FFA347">100</td>
        <td bgcolor="#CCFF99">100</td>
        <td bgcolor="#FFA347">10</td>
        <td bgcolor="#CCFF99">foo</td>
      </tr>
    </TBODY>
  </table>
  <input type="button" value="Repair this table" onclick="correctTableColumns();"> 
  <p onclick="alert('clicked !');"> see <strong>http://codepen.io/anon/pen/ZYNPjd</strong> . javascript doesn't run in codesnippet :) </p>
 </body>
</html>
RevanthKrishnaKumar V.
  • 1,855
  • 1
  • 21
  • 34
G-Cyrillus
  • 101,410
  • 14
  • 105
  • 129
  • Javascript does run in code snippets. That is what they are for. But your code does give a rather strange layout to the table in comparison to the original. – Raidri Apr 08 '15 at 11:00
  • @Raidri it never does with my firefox, it only loads CSS file for me. – G-Cyrillus Apr 08 '15 at 11:04
  • @Raidri can you confirm that clicking repair button or the las p in my codesnippet triggers something ?. For me it is just like javascript is not there. – G-Cyrillus Apr 08 '15 at 11:09
  • @Raidri thanks for your feed back.So it's on my side :) – G-Cyrillus Apr 08 '15 at 11:13