How can I construct a table header than spans multiple rows in HTML?

Solution 1:

This is how I would do it (working fiddle at http://jsfiddle.net/7pDqb/) Tested in Chrome.

th, td { border: 1px solid black }
<table>
  <thead>
    <tr>
      <th colspan="2">Major 1</th>
      <th colspan="2">Major 2</th>
    </tr>
    <tr>
      <th>col1</th>
      <th>col2</th>
      <th>col3</th>
      <th>col4</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>data1</td>
      <td>data2</td>
      <td>data3</td>
      <td>data4</td>
    </tr>
  </tbody>
</table>

Solution 2:

Were you accidentally using rowspan instead of colspan? Or did you accidentally forget a closing </tr> tag?

Extending off of tvanfosson's answer, I'd use the scope attribute on the th elements for semantic and accessibility purposes:

th, td { border: 1px solid black }
<table>
  <thead>
    <tr>
      <th colspan="2" scope='colgroup'>Major Heading 1</th>
      <th colspan="2" scope='colgroup'>Major Heading 2</th>
    </tr>
    <tr>
      <th scope='col'>Minor1</th>
      <th scope='col'>Minor2</th>
      <th scope='col'>Minor3</th>
      <th scope='col'>Minor4</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>col1</td>
      <td>col2</td>
      <td>col3</td>
      <td>col4</td>
    </tr>
  </tbody>
</table>