skip to Main Content

Specifically, what I’m trying to achieve is this (try to imagine it without the table borders):

enter image description here

where:

  • the first column is fixed width and has a <hr> element the full column width.
  • the second column has the text of the title, and the column width expands to suit.
  • the third column has a width that uses all remaining table width and has a <hr> element the full column width.

I got this far:

<table border="1" cellpadding="1" cellspacing="1" style="table-layout: fixed; width:100%;">
  <tr>
    <td style="width:40px;"><hr></td>
    <td style="white-space: nowrap;overflow: hidden;"><strong>Some Title</strong></td>
    <td style="width:90%"><hr></td>
  </tr>
</table>

but this plainly is only "correct" for one table width, and incorrect for all others:
enter image description here
How can I prevent column 2 from being overwritten by column 3, or force column 3 to only use as much width as it needs?

4

Answers


  1. Changing table-layout: fixed to table-layout: auto and then adding a min-width: 40px to your first columns and width: 100% to your 3rd columns should do the trick.
    Doing so, the last column will fill the available space.

    One thing should be noted: Tables are "stiff", so as far as I know it’s not possible to give the 3rd column a different width for each row.

    See the below example, where the 2nd column "pulls" away the 3rd column to fit the longest row:

    <table border="1" cellpadding="1" cellspacing="1" style="table-layout: auto; width:100%;">
      <tr>
        <td style="width:40px;min-width: 40px;"><hr></td>
        <td style="white-space: nowrap;overflow: hidden;"><strong>Some Title</strong></td>
        <td style="width:100%"><hr></td>
      </tr>
        <tr>
        <td style="width:40px;min-width: 40px;"><hr></td>
        <td style="white-space: nowrap;overflow: hidden;"><strong>Someas longer title</strong></td>
        <td style="width:100%"><hr></td>
      </tr>
        <tr>
        <td style="width:40px;min-width: 40px"><hr></td>
        <td style="white-space: nowrap;overflow: hidden;"><strong>Some very long title to show off</strong></td>
        <td style="width:100%"><hr></td>
      </tr>
    </table>
    Login or Signup to reply.
  2. Just add width: max-content; to the second column:

    <table border="1" cellpadding="1" cellspacing="1" style="table-layout: auto; width:100%;">
      <tr>
        <td style="width:40px;min-width:40px;"><hr></td>
        <td style="white-space: nowrap;overflow: hidden; width: max-content;"><strong>Some Title</strong></td>
        <td style="width: 100%;"><hr></td>
      </tr>
    </table>

    If you just want to create this effekt "header with line in background" variants like this one might be an alternative for responsive designs:

    .MyH1 {
      position: relative;
     }
    .MyH1 h1 {
      position: absolute;
      top: 0;
      left: 6rem;
      background-color: white;
    }
    .MyH1 hr {
      position: absolute;
      top: 2.2em;    /* has to fit to the padding + font-size of <h1> */
      width: 100%;
    }
    <div class="MyH1">
        <hr>
        <h1>Some Title</h1>
    </div>
    Login or Signup to reply.
  3. Using a table for this purpose is really inadequate semantically. Instead, you can use a flex container with three children and the following settings which will also solve your width problems:

    .header1 {
      display: flex;
      align-items: center;
    }
    
    .header1>span {
      height: 2px;
      border-bottom: 2px solid #000;
    }
    
    .header1>span:first-child {
      flex: 0 0 40px;
    }
    
    .header1>h1 {
      padding: 0 10px;
    }
    
    .header1>span:last-child {
      flex-grow: 1;
    }
    <div class="header1">
      <span></span>
      <h1>Some Title</h1>
      <span></span>
    </div>

    If you want the horizontal lines higher, add position: relative and a bottom value to the spans:

    .header1 {
      display: flex;
      align-items: center;
    }
    
    .header1>span {
      height: 2px;
      border-bottom: 2px solid #000;
      position: relative;
      bottom: 3px;
    }
    
    .header1>span:first-child {
      flex: 0 0 40px;
    }
    
    .header1>h1 {
      padding: 0 10px;
    }
    
    .header1>span:last-child {
      flex-grow: 1;
    }
    <div class="header1">
      <span></span>
      <h1>Some Title</h1>
      <span></span>
    </div>
    Login or Signup to reply.
  4. I recommend not using a <table> element for data that is not tabular (if you are showing tabular data in the <table>, and this is a heading for that <table>, then use the <caption> element to contain that heading).

    So, instead of that table approach, I’d suggest the following, using a semantic <header> element along with CSS flex layout:

    /* using the <header> element to contain the
       custom CSS properties for the 'line': */
    header {
      --line-color: #aab;
      --line-size: 0.1rem;
      /* specifying flex-layout on the children: */
      display: flex;
      /* aligning those children to the start of
         the inline-axis (the horizontal axis in
         English, and the axis upon which inline
         elements are laid out): */
      justify-content: start;
    }
    
    /* using the pseudo-elements, ::before and
       ::after, to contain the horizontal line: */
    header::before,
    header::after {
      background-image:
      /* a linear gradient on a vertical axis, going
         downwards (180deg): */
        linear-gradient(
          180deg,
          /* the first color is transparent, and continues
             until the 50% point, minus half of the line-size,
             so the line is centered at 50% on the vertical
             axis: */
          transparent calc(50% - var(--line-size)/2),
          /* we then switch to the --line-color custom property,
             which starts 50% - minus half the line-size and
             continues until a point at 50% plus half the line-size: */
          var(--line-color) calc(50% - var(--line-size)/2) calc(50% + var(--line-size)/2),
          /* and then switching back to transparent: */
          transparent calc(50% + var(--line-size)/2));
      content: '';
    }
    
    header::before {
      /* this gives the 'inset' size of the <h1> element,
         adjust to your preference: */
      flex-basis: 4rem;
    }
    
    header::after {
      /* this causes the ::after element to expand to take
         up all available space on the line: */
      flex-grow: 1;
    }
    
    h1 {
      padding-inline: 1rem;
    }
    <header>
      <h1>Title content</h1>
    </header>

    JS Fiddle demo.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search