261

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?

TylerH
  • 20,799
  • 66
  • 75
  • 101
s4y
  • 50,525
  • 12
  • 70
  • 98
  • 7
    I suspect you'll have to resort to JavaScript to solve this. – thirtydot Mar 09 '11 at 07:59
  • 9
    Lolz .. +1 for entertainment value :) ... does this need to be dynamic or can you not simply set a width on each column? – War Mar 10 '11 at 11:04

19 Answers19

121
<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/

ladislav
  • 1,323
  • 1
  • 9
  • 4
  • 23
    Ugh. Works so great, but i have no idea why, which makes me nervous :( – Shaun Rowan Mar 28 '14 at 15:32
  • 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 Nov 12 '15 at 05:55
  • 4
    Also, note that you can eliminate the ``s by instead prepending the widths to the `` styles: http://jsfiddle.net/7CURQ/64/ – Sam Nov 12 '15 at 05:55
  • 3
    Actually, this seems to spoil the dynamic column sizing of the non-truncated columns. They seem to always be shrunk to minimum width. – Sam Nov 12 '15 at 06:15
  • 2
    Why is the max-width:1px value needed? I can see it not working without it, but not sure why. – Vilius Kazakauskas Feb 15 '22 at 12:58
  • It works also with multiple columns, just leave the 100% for the one that needs truncation. – Beto López Nov 14 '22 at 07:40
42

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;
}
TylerH
  • 20,799
  • 66
  • 75
  • 101
Jeff Camera
  • 5,324
  • 5
  • 44
  • 59
  • 3
    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 ­ http://jsfiddle.net/zAeA2/160/ – Riccardo Casatta Jun 18 '14 at 09:23
  • 2
    this is pretty awesome! i made my own variant using attr to avoid duplicating content: http://jsfiddle.net/coemL8rf/2/ – Jayen Jan 07 '15 at 01:53
  • @Jayen Nice - Perhaps use `title` instead of `data-spacer` to get a tooltip on mouse over :) – William George Jan 09 '15 at 17:53
  • @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 Nov 12 '15 at 05:13
  • @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. – Jayen Nov 12 '15 at 08:11
  • 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. – bot19 Sep 18 '19 at 02:26
35

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.

Alexandre Annic
  • 9,942
  • 5
  • 36
  • 50
  • 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? – Malik Brahimi Apr 22 '20 at 15:30
  • As I know, no. Sadly, HTML table is really poorly designed ☹️. – Alexandre Annic Nov 10 '21 at 17:51
  • how to limit cell height without setting nowrap? – xeruf Mar 10 '23 at 12:46
27

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/

Community
  • 1
  • 1
Henry Feesler
  • 371
  • 5
  • 6
  • 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. – buggedcom Oct 06 '17 at 08:50
  • 1
    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. http://jsfiddle.net/katdLfe5/ – renatodeleao Jul 20 '20 at 18:42
24

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/

satyavh
  • 341
  • 2
  • 3
  • 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. https://jsfiddle.net/rza4hfcv/ Not sure, what I should think about this. But thanks for sharing your solution! – armin Jul 30 '15 at 14:42
  • Did you experience any problems with that solution? I'm thinking about using it in a professional setting. – armin Jul 30 '15 at 15:55
  • @armin, try to duplicate the cell you want to truncate: you cannot put more than one side by side. – DanielM Oct 06 '15 at 07:29
  • 1
    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. – DanielM Oct 06 '15 at 07:37
  • @DanielM You can extend the solution by further nesting the table - like in the old table-layout-days - but now just with css. – armin Oct 18 '15 at 20:50
18

If Javascript is acceptable, I put together a quick routine which you could use as a starting point. It dynamically tries to adapt the cell widths using the inner width of a span, in reaction to window resize events.

Currently it assumes that each cell normally gets 50% of the row width, and it will collapse the right cell to keep the left cell at its maximum width to avoid overflowing. You could implement much more complex width balancing logic, depending on your use cases. Hope this helps:

Markup for the row I used for testing:

<tr class="row">
    <td style="overflow: hidden; text-overflow: ellipsis">
    <span>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</span>
    </td>
    <td style="overflow: hidden; text-overflow: ellipsis">
    <span>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</span>
    </td>
</tr>

JQuery which hooks up the resize event:

$(window).resize(function() {
    $('.row').each(function() {
        var row_width = $(this).width();
        var cols = $(this).find('td');
        var left = cols[0];
        var lcell_width = $(left).width();
        var lspan_width = $(left).find('span').width();
        var right = cols[1];
        var rcell_width = $(right).width();
        var rspan_width = $(right).find('span').width();

        if (lcell_width < lspan_width) {
            $(left).width(row_width - rcell_width);
        } else if (rcell_width > rspan_width) {
            $(left).width(row_width / 2);
        }
    });
});
samplebias
  • 37,113
  • 6
  • 107
  • 103
12

The problem is the 'table-layout:fixed' which create evenly-spaced-fixed-width columns. But disabling this css-property will kill the text-overflow because the table will become as large as possible (and than there is noting to overflow).

I'm sorry but in this case Fred can't have his cake and eat it to.. unless the landlord gives Celldito less space to work with in the first place, Fred cannot use his..

Andre Haverdings
  • 847
  • 8
  • 10
9

You could try to "weight" certain columns, like this:

<table border="1" style="width: 100%;">
    <colgroup>
        <col width="80%" />
        <col width="20%" />
    </colgroup>
    <tr>
        <td>This cell has more content.</td>
        <td>Less content here.</td>
    </tr>
</table>

You can also try some more interesting tweaks, like using 0%-width columns and using some combination of the white-space CSS property.

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

You get the idea.

Elliot Cameron
  • 5,235
  • 2
  • 27
  • 34
4

This question pops up top in Google, so in my case, I used the css snippet from https://css-tricks.com/snippets/css/truncate-string-with-ellipsis/ but applying it to the td did NOT give the desired result.

I had to add a div tag around the text in the td and the ellipsis finally worked.

Abbreviated HTML Code;

<table style="width:100%">
 <tr>
    <td><div class='truncate'>Some Long Text Here</div></td>
 </tr>
</table>

Abbreviated CSS;

.truncate { width: 300px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
MarcoZen
  • 1,556
  • 22
  • 27
3

Like samplebias answer, again if Javascript is an acceptable answer, I made a jQuery plugin specifically for this purpose: https://github.com/marcogrcr/jquery-tableoverflow

To use the plugin just type

$('selector').tableoverflow();

Full example: http://jsfiddle.net/Cw7TD/3/embedded/result/

Edits:

  • Fix in jsfiddle for IE compatibility.
  • Fix in jsfiddle for better browser compatibility (Chrome, Firefox, IE8+).
Marco
  • 5,555
  • 2
  • 17
  • 23
3

Use some css hack, it seems the display: table-column; can come to rescue:

.myTable {
  display: table;
  width: 100%;
}

.myTable:before {
  display: table-column;
  width: 100%;
  content: '';
}

.flexibleCell {
  display: table-cell;
  max-width: 1px;
  white-space: nowrap;
  text-overflow: ellipsis;
  overflow: hidden;
}

.staticCell {
  white-space: nowrap;
}
<div class="myTable">
  <div class="flexibleCell">A very long piece of content in first cell, long enough that it would normally wrap into multiple lines.</div>
  <div class="staticCell">Less content</div>
</div>

JSFiddle: http://jsfiddle.net/blai/7u59asyp/

Nickofthyme
  • 3,032
  • 23
  • 40
blai
  • 39
  • 1
  • Looked pretty good until I added a static cell before a flexible cell: https://jsfiddle.net/7u59asyp/5/ – Sam Nov 12 '15 at 05:50
  • this is the only one that worked for me, albeit not perfectly, since I have 4 columns with varying expected content size – downhand Jan 02 '17 at 11:48
3

Yep I would say thirtydot has it, there is no way to do it unless you use a js method. You are talking about a complex set of rendering conditions that you will have to define. e.g. what happens when both cells are getting too big for their apartments you will have to decide who has priority or simply just give them a percentage of the area and if they are overfull they will both take up that area and only if one has whitespace will you stretch your legs in the other cell, either way there is no way to do it with css. Although there are some pretty funky things people do with css that I have not thought of. I really doubt you can do this though.

user648116
  • 41
  • 1
1

Check if "nowrap" solve the issue to an extent. Note: nowrap is not supported in HTML5

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

amlan
  • 11
  • 1
  • 4
  • `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 May 23 '11 at 22:46
1
<table style="table-layout: fixed; max-width: 100%;">
    <tr>
        <td>
             <div style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap">This cells has more content</div>
        </td>
        <td>Less content here</td>
    </tr>
</table>
flm
  • 107
  • 8
  • Source-code without explanation does not qualify as an answer. Please explain the reason why you suggest this source-code. – Lajos Arpad Oct 07 '21 at 14:29
0

you can set the width of right cell to minimum of required width, then apply overflow-hidden+text-overflow to the inside of left cell, but Firefox is buggy here...

although, seems, flexbox can help

4esn0k
  • 9,789
  • 7
  • 33
  • 40
0

Don't know if this will help anyone, but I solved a similar problem by specifying specific width sizes in percentage for each column. Obviously, this would work best if each column has content with width that doesn't vary too widely.

DKO
  • 53
  • 7
0

I've been recently working on it. Check out this jsFiddle test, try it yourself changing the width of the base table to check the behavior).

The solution is to embedded a table into another:

<table style="width: 200px;border:0;border-collapse:collapse">
    <tbody>
        <tr>
            <td style="width: 100%;">
                <table style="width: 100%;border:0;border-collapse:collapse">
                    <tbody>
                        <tr>
                            <td>
                                <div style="position: relative;overflow:hidden">
                                    <p>&nbsp;</p>
                                    <p style="overflow:hidden;text-overflow: ellipsis;position: absolute; top: 0pt; left: 0pt;width:100%">This cells has more content</p>
                                </div>
                            </td>
                        </tr>
                    </tbody>
                </table>
            </td>
            <td style="white-space:nowrap">Less content here</td>
        </tr>
    </tbody>
</table>

Is Fred now happy with Celldito's expansion?

I.G. Pascual
  • 5,818
  • 5
  • 42
  • 58
  • 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 Jun 18 '12 at 00:58
  • Sorry, the link was not the one I posted. It's actually this one http://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... – I.G. Pascual Jun 18 '12 at 12:27
-1

I had the same issue, but I needed to display multiple lines (where text-overflow: ellipsis; fails). I solve it using a textarea inside a TD and then style it to behave like a table cell.

    textarea {
        margin: 0;
        padding: 0;
        width: 100%;
        border: none;
        resize: none;

        /* Remove blinking cursor (text caret) */
        color: transparent;
        display: inline-block;
        text-shadow: 0 0 0 black; /* text color is set to transparent so use text shadow to draw the text */
        &:focus {
            outline: none;
        }
    }
Nicero
  • 4,181
  • 6
  • 30
  • 52
-2

Given that 'table-layout:fixed' is the essential layout requirement, that this creates evenly spaced non-adjustable columns, but that you need to make cells of different percentage widths, perhaps set the 'colspan' of your cells to a multiple?

For example, using a total width of 100 for easy percentage calculations, and saying that you need one cell of 80% and another of 20%, consider:

<TABLE width=100% style="table-layout:fixed;white-space:nowrap;overflow:hidden;">
     <tr>
          <td colspan=100>
               text across entire width of table
          </td>
     <tr>
          <td colspan=80>
               text in lefthand bigger cell
          </td>
          <td colspan=20>
               text in righthand smaller cell
          </td>
</TABLE>

Of course, for columns of 80% and 20%, you could just set the 100% width cell colspan to 5, the 80% to 4, and the 20% to 1.

Siubear
  • 177
  • 2
  • 3