How can I truncate table cells, but fit as much as content possible?

120,469

Solution 1

<table border="1" style="width: 100%;">
    <colgroup>
        <col width="100%" />
        <col width="0%" />
    </colgroup>
    <tr>
        <td style="white-space: nowrap; text-overflow:ellipsis; overflow: hidden; max-width:1px;">This cell has more content.This cell has more content.This cell has more content.This cell has more content.This cell has more content.This cell has more content.</td>
        <td style="white-space: nowrap;">Less content here.</td>
    </tr>
</table>

http://jsfiddle.net/7CURQ/

Solution 2

I believe I have a non-JavaScript solution! I didn't want to settle for a JavaScript fix because I find the slight jitter of things moving around after the page is loaded to be unacceptable.

Features:

  • No JavaScript
  • No fixed-layout
  • No weighting or percentage-width tricks
  • Works with any number of columns
  • Simple server-side generation and client-side updating (no calculation necessary)
  • Cross-browser compatible

How it works: Inside the table cell place two copies of the content in two different elements within a relatively-positioned container element. The spacer element is statically-positioned and as such will affect the width of the table cells. By allowing the contents of the spacer cell to wrap we can get the "best-fit" width of the table cells that we are looking for. This also allows us to use the absolutely-positioned element to restrict the width of the visible content to that of the relatively-positioned parent.

Tested and working in: IE8, IE9, IE10, Chrome, Firefox, Safari, Opera

Result Images:

Nice proportional widths Nice proportional clipping

JSFiddle: http://jsfiddle.net/zAeA2/

Sample HTML/CSS:

<td>
    <!--Relative-positioned container-->
    <div class="container">
        <!--Visible-->
        <div class="content"><!--Content here--></div>
        <!--Hidden spacer-->
        <div class="spacer"><!--Content here--></div>
        <!--Keeps the container from collapsing without
            having to specify a height-->
        <span>&nbsp;</span>
     </div>
</td>

.container {
    position: relative;
}
.content {
    position: absolute;
    max-width: 100%;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.spacer {
    height: 0;
    overflow: hidden;
}

Solution 3

I've been faced the same challenge few days ago. It seems Lucifer Sam found the best solution.

But I noticed you should duplicate content at spacer element. Thought it's not so bad, but I'd like also to apply title popup for clipped text. And it means long text will appear third time in my code.

Here I propose to access title attribute from :after pseudo-element to generate spacer and keep HTML clean.

Works on IE8+, FF, Chrome, Safari, Opera

<table border="1">
  <tr>
    <td class="ellipsis_cell">
      <div title="This cells has more content">
        <span>This cells has more content</span>
      </div>
    </td>
    <td class="nowrap">Less content here</td>
  </tr>
</table>
.ellipsis_cell > div {
    position: relative;
    overflow: hidden;
    height: 1em;
}

/* visible content */
.ellipsis_cell > div > span {
    display: block;
    position: absolute; 
    max-width: 100%;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    line-height: 1em;
}

/* spacer content */
.ellipsis_cell > div:after {
    content: attr(title);
    overflow: hidden;
    height: 0;
    display: block;
}

http://jsfiddle.net/feesler/HQU5J/

Solution 4

Simply add the following rules to your td:

overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
// These ones do the trick
width: 100%;
max-width: 0;

Example:

table {
  width: 100%
}

td {
  white-space: nowrap;
}

.td-truncate {
  overflow: hidden;
  text-overflow: ellipsis;
  width: 100%;
  max-width: 0;
}
<table border="1">
  <tr>
    <td>content</td>
    <td class="td-truncate">long contenttttttt ttttttttt ttttttttttttttttttttttt tttttttttttttttttttttt ttt tttt ttttt ttttttt tttttttttttt ttttttttttttttttttttttttt</td>
    <td>other content</td>
  </tr>
</table>

PS: If you want to set a custom width to another td use property min-width.

Solution 5

There's a much easier and more elegant solution.

Within the table-cell that you want to apply truncation, simply include a container div with css table-layout: fixed. This container takes the full width of the parent table cell, so it even acts responsive.

Make sure to apply truncation to the elements in the table.

Works from IE8+

<table>
  <tr>
    <td>
     <div class="truncate">
       <h1 class="truncated">I'm getting truncated because I'm way too long to fit</h1>
     </div>
    </td>
    <td class="some-width">
       I'm just text
    </td>
  </tr>
</table>

and css:

    .truncate {
      display: table;
      table-layout: fixed;
      width: 100%;
    }

    h1.truncated {
      overflow-x: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }

here's a working Fiddle https://jsfiddle.net/d0xhz8tb/

Share:
120,469

Related videos on Youtube

s4y
Author by

s4y

Enthusiastic software engineer working on Chrome for Mac at Google. Original content is dedicated to the public domain (CC0). Do with it as you see fit.

Updated on October 08, 2021

Comments

  • s4y
    s4y over 2 years

    Meet Fred. He's a table:

    One cell has more content and is wider, the other has less content and is narrower

    <table border="1" style="width: 100%;">
        <tr>
            <td>This cells has more content</td>
            <td>Less content here</td>
        </tr>
    </table>
    

    Fred's apartment has a bizarre habit of changing size, so he's learned to hide some of his content so as not to push all the other units over and shove Mrs. Whitford's living room off into oblivion:

    The cells are now the same size, but only one has its content truncated, and it looks like if the other cell gave if some whitespace, they could both fit.

    <table border="1" style="width: 100%; white-space: nowrap; table-layout: fixed;">
        <tr>
            <td style="overflow: hidden; text-overflow: ellipsis">This cells has more content</td>
            <td style="overflow: hidden; text-overflow: ellipsis">Less content here</td>
        </tr>
    </table>
    

    This works, but Fred has a nagging feeling that if his right cell (which he's nicknamed Celldito) gave up a little space, his left cell wouldn't be truncated quite as much of the time. Can you save his sanity?


    In summary: How can a table's cells overflow evenly, and only when they've all given up all their whitespace?

    • thirtydot
      thirtydot about 13 years
      I suspect you'll have to resort to JavaScript to solve this.
    • War
      War about 13 years
      Lolz .. +1 for entertainment value :) ... does this need to be dynamic or can you not simply set a width on each column?
  • s4y
    s4y almost 13 years
    white-space: nowrap has the same effect as the nowrap attribute (and I’m using it in the example). Adding it here doesn’t change anything, as far as I can tell.
  • s4y
    s4y almost 12 years
    Sorry for the lack of response! I can’t see how this behaves any differently from a single table. When I view the fiddle in Chrome or Firefox, it looks exactly like the second screenshot from the question. Am I missing something?
  • s4y
    s4y almost 12 years
    Hey @Siubear. How’s that different from specifying a percent width on the tds?
  • I.G. Pascual
    I.G. Pascual almost 12 years
    Sorry, the link was not the one I posted. It's actually this one jsfiddle.net/VSZPV/2. Change the text of both cells and the width of the main table to test. Hope it's what you where looking for...
  • Percy
    Percy over 11 years
    Using colspan in such a way is a horrible idea. Why not use width instead?
  • Shaun Rowan
    Shaun Rowan about 10 years
    Ugh. Works so great, but i have no idea why, which makes me nervous :(
  • Riccardo Casatta
    Riccardo Casatta almost 10 years
    If your content is an very long word without spaces, this isn't working but you just need to add hyphenation to the conent in spacer with &shy; jsfiddle.net/zAeA2/160
  • Jayen
    Jayen over 9 years
    this is pretty awesome! i made my own variant using attr to avoid duplicating content: jsfiddle.net/coemL8rf/2
  • William George
    William George over 9 years
    @Jayen Nice - Perhaps use title instead of data-spacer to get a tooltip on mouse over :)
  • armin
    armin almost 9 years
    This solution requires 2 additional block-level elements to achieve a non-structural effect. It is possible to set one table cell to "display: table", which allows you get rid of one of the divs. jsfiddle.net/rza4hfcv Not sure, what I should think about this. But thanks for sharing your solution!
  • armin
    armin almost 9 years
    Did you experience any problems with that solution? I'm thinking about using it in a professional setting.
  • DanielM
    DanielM over 8 years
    @armin, try to duplicate the cell you want to truncate: you cannot put more than one side by side.
  • DanielM
    DanielM over 8 years
    I wouldn't say this is a final solution though. You loose one of the main benefits of a table: that the columns resize according with its content. If you set up every column like this, all of them will have the same width, no matter the length of its content.
  • armin
    armin over 8 years
    @DanielM You can extend the solution by further nesting the table - like in the old table-layout-days - but now just with css.
  • Sam
    Sam over 8 years
    @Jayen, I just tried yours and it doesn't seem to truncate the cell on the right side, so it doesn't meet the requirement of the cells overflowing evenly. I'm using Chrome 46.
  • Sam
    Sam over 8 years
    Looked pretty good until I added a static cell before a flexible cell: jsfiddle.net/7u59asyp/5
  • Sam
    Sam over 8 years
    Thanks! Doesn't do exactly what the question said (truncate all columns evenly), but the behaviour of this code is what I was looking for.
  • Sam
    Sam over 8 years
    Also, note that you can eliminate the <col>s by instead prepending the widths to the <td> styles: jsfiddle.net/7CURQ/64
  • Sam
    Sam over 8 years
    Actually, this seems to spoil the dynamic column sizing of the non-truncated columns. They seem to always be shrunk to minimum width.
  • Jayen
    Jayen over 8 years
    @Sam yes that's right. my example only shows that both types of cells can be made without duplicating content. i was not trying to answer the question, simply showing another way. if you change the HTML in my example, it works as you want.
  • downhand
    downhand over 7 years
    this is the only one that worked for me, albeit not perfectly, since I have 4 columns with varying expected content size
  • buggedcom
    buggedcom over 6 years
    much better than the other css solutions because it works in both orders, ie if the more content cell is after the less content cell.
  • bot19
    bot19 over 4 years
    The only issue with the non-duplicate content solutions is that you can't select the content. I and my clients do a lot of copy-pasting. Also doesn't work well if the content is more interactive than just text. Good effort though.
  • Malik Brahimi
    Malik Brahimi about 4 years
    The problem with this is that by default table columns consume space proportionally. If the content of one row is longer than that of another it will allocate more of the width. However, this technique evenly divides the space. Is there a work around?
  • renatodeleao
    renatodeleao almost 4 years
    Another good side-effect is that it works combined with -webkit-line-clamp to achieve multiline truncation if desired and if not required to support IE. jsfiddle.net/katdLfe5
  • Lajos Arpad
    Lajos Arpad over 2 years
    Source-code without explanation does not qualify as an answer. Please explain the reason why you suggest this source-code.
  • Alexandre Annic
    Alexandre Annic over 2 years
    As I know, no. Sadly, HTML table is really poorly designed ☹️.
  • Vilius Kazakauskas
    Vilius Kazakauskas over 2 years
    Why is the max-width:1px value needed? I can see it not working without it, but not sure why.