piisexactly3
piisexactly3

Reputation: 779

How to use JavaScript and offsetWidth to line up tables?

I've inherited this project that goes about things in an old-fashioned way. For instance, it uses tables for layout, which is bad enough, but then it breaks apart headers and content into two separate tables (see my code snippet).

It's not really practical to go about re-writing the markup, so the solution will have to be a JavaScript one, combined with CSS probably. Keep in mind that I've vastly simplified the issue for the purposes here to make things less confusing; in reality, the problem stretches over many different files.

Using JavaScript (see the snippet), I'm able to mostly line up the headers with the body. The idea is to wait until the page loads, find the widths of the body elements, and then apply them to the headers to make it look like one table. As you can see, it doesn't exactly match up. This is in part because of the CSS borders, but life is messy and borders happen. It's not realistic to remove all additional CSS just to make things line up.

Can you help me get these tables to line up and look like one table?

Edit:

To be a bit clearer on the requirements, the table needs to be sized dynamically, based on the widths of the content in the body table. The content might change, so it won't be sufficient to hard-code widths.

window.onload = function() {
  var bodyCols = document.getElementsByClassName('bodyCol');
  var headCols = document.getElementsByClassName('headCol');

  for (var i=0; i<bodyCols.length; i++) {
    headCols[i].style.minWidth = bodyCols[i].offsetWidth + 'px';
  }
}
#headTable {
  width: 100%;
}

.headCol { 
  border: 5px solid red;
}

#bodyTable {
  width: 100%;
}

.bodyCol { 
  border: 5px solid blue;
}
<table id="headTable">
  <tbody>
    <tr>
      <td class="headCol">
        Hey!
      </td>
      <td class="headCol">
        Wait!
      </td>
      <td class="headCol">
        I've got a new complaint
      </td>
    </tr>
  </tbody>
</table>
<table id="bodyTable">
  <tbody>
    <tr>
      <td class="bodyCol">
        Forever in debt
      </td>
      <td class="bodyCol">
        to your priceless
      </td>
      <td class="bodyCol">
        advice
      </td>
    </tr>
  </tbody>
</table>

Upvotes: 1

Views: 546

Answers (2)

spencer.sm
spencer.sm

Reputation: 20614

The following is a solution using pure JavaScript.

var bodyCols = document.querySelectorAll('.bodyCol');
var headCols = document.querySelectorAll('.headCol');

for(var i = 0; i < bodyCols.length; i++){
    console.log(headCols[i]);
  headCols[i].style.width = window.getComputedStyle(bodyCols[i]).width;
}

See working example: https://jsfiddle.net/pbjzmanc/

Upvotes: 2

piisexactly3
piisexactly3

Reputation: 779

I spent some time on this and came up with a jQuery solution. Now, I didn't mention jQuery in the question and ideally I wouldn't have to include it in my project just for this one problem. However, it does solve the problem nicely and I don't know of a way to do it otherwise. I will leave off marking this as the correct answer for now in the hopes someone can show me how to do this with plain JavaScript.

$(function() {  
  $('.bodyCol').each(function(index) {
    $('.headCol:eq(' + index + ')').innerWidth($(this).innerWidth());
  });
});
#headTable {
  width: 100%;
}

.headCol { 
  border: 5px solid red;
}

#bodyTable {
  width: 100%;
}

.bodyCol { 
  border: 5px solid blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="headTable">
  <tbody>
    <tr>
      <td class="headCol">
        Hey!
      </td>
      <td class="headCol">
        Wait!
      </td>
      <td class="headCol">
        I've got a new complaint
      </td>
    </tr>
  </tbody>
</table>
<table id="bodyTable">
  <tbody>
    <tr>
      <td class="bodyCol">
        Forever in debt
      </td>
      <td class="bodyCol">
        to your priceless
      </td>
      <td class="bodyCol">
        advice
      </td>
    </tr>
  </tbody>
</table>

Upvotes: 0

Related Questions