CSS: truncar células da tabela, mas caber o máximo possível

223

Conheça Fred. Ele é uma mesa:

Uma célula tem mais conteúdo e é mais larga, a outra tem menos conteúdo e é mais estreita

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

O apartamento de Fred tem o hábito bizarro de mudar de tamanho, então ele aprendeu a esconder parte de seu conteúdo para não empurrar todas as outras unidades e empurrar a sala da sra. Whitford para o esquecimento:

As células agora têm o mesmo tamanho, mas apenas uma tem seu conteúdo truncado, e parece que se a outra célula fornecer se houver algum espaço em branco, elas poderão se encaixar.

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

Isso funciona, mas Fred tem uma sensação incômoda de que se a célula direita (que ele é apelidada de Celldito) desistisse de um pouco de espaço, sua célula esquerda não seria truncada na maior parte do tempo. Você pode salvar sua sanidade?


Em resumo: como as células de uma tabela podem transbordar de maneira uniforme e somente quando todas elas abrem espaço em branco?

s4y
fonte
95
Para uma caracterização de um objecto virtual, bem um senhor :)
Myles cinzento
6
Eu suspeito que você precisará recorrer ao JavaScript para resolver isso.
thirtydot
6
Lolz .. +1 para o valor do entretenimento :) ... isso precisa ser dinâmico ou você não pode simplesmente definir uma largura em cada coluna?
War

Respostas:

82
<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
fonte
9
Ugh. Funciona tão bem, mas não tenho idéia do porquê, o que me deixa nervoso :(
Shaun Rowan
Obrigado! Não faz exatamente o que a pergunta dizia (truncar todas as colunas uniformemente), mas o comportamento desse código é o que eu estava procurando.
Sam
3
Além disso, observe que você pode eliminar os <col>s, acrescentando as larguras aos <td>estilos: jsfiddle.net/7CURQ/64
Sam
2
Na verdade, isso parece prejudicar o dimensionamento dinâmico da coluna das colunas não truncadas. Eles parecem estar sempre encolhidos na largura mínima.
Sam
38

Eu acredito que tenho uma solução não-javascript! Antes tarde do que nunca, certo? Afinal, essa é uma excelente pergunta e o Google está por toda parte. Não queria me contentar com uma correção de javascript, porque considero inaceitável o ligeiro tremor das coisas que se deslocam depois que a página é carregada.

Características :

  • Sem javascript
  • Sem layout fixo
  • Sem truques de ponderação ou largura percentual
  • Funciona com qualquer número de colunas
  • Geração simples do lado do servidor e atualização do lado do cliente (nenhum cálculo é necessário)
  • Compatível com vários navegadores

Como funciona : dentro da célula da tabela, coloque duas cópias do conteúdo em dois elementos diferentes dentro de um elemento de contêiner relativamente posicionado. O elemento espaçador é posicionado estaticamente e, como tal, afetará a largura das células da tabela. Ao permitir que o conteúdo da célula espaçadora seja encapsulado, podemos obter a largura "mais adequada" das células da tabela que estamos procurando. Isso também nos permite usar o elemento absolutamente posicionado para restringir a largura do conteúdo visível à do pai relativamente posicionado.

Testado e trabalhando em: IE8, IE9, IE10, Chrome, Firefox, Safari, Opera

Imagens dos resultados :

Larguras proporcionais agradáveis Recorte proporcional agradável

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

Exemplo de 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;
}
Lúcifer Sam
fonte
3
Se o seu conteúdo for uma palavra muito longa sem espaços, isso não está funcionando, mas você só precisa adicionar hifenização ao conteúdo no espaçador com o & shy; jsfiddle.net/zAeA2/160
Riccardo Casatta
2
isso é incrível! eu fiz a minha própria variante usando attr para evitar conteúdo duplicar: jsfiddle.net/coemL8rf/2
Jayen
@Jayen Nice - Talvez use titleem vez de data-spacerobter uma dica de ferramenta on mouse sobre :)
William George
@ Jayen, eu apenas tentei o seu e ele não parece truncar a célula no lado direito, para que não atenda aos requisitos de células que transbordam uniformemente. Estou usando o Chrome 46.
Sam
@ Sam sim, isso mesmo. meu exemplo mostra apenas que os dois tipos de células podem ser criados sem duplicar o conteúdo. eu não estava tentando responder à pergunta, simplesmente mostrando outra maneira. se você alterar o HTML no meu exemplo, ele funcionará como você deseja.
Jayen
24

Eu já enfrentei o mesmo desafio há alguns dias. Parece que Lúcifer Sam encontrou a melhor solução.

Mas notei que você deve duplicar o conteúdo no elemento espaçador. Achei que não era tão ruim, mas eu também gostaria de aplicar titlepop-up ao texto recortado. E isso significa que o texto longo aparecerá pela terceira vez no meu código.

Aqui proponho acessar o titleatributo do :afterpseudoelemento para gerar espaçador e manter o HTML limpo.

Funciona no 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/

Henry Feesler
fonte
Não poderia concordar mais, brilhante!
Mikhail
muito melhor do que as outras soluções css porque funciona em ambas as ordens, ou seja, se a célula com mais conteúdo estiver atrás da célula com menos conteúdo.
Buggedcom
19

Se o Javascript for aceitável, montei uma rotina rápida que você poderia usar como ponto de partida. Ele tenta adaptar dinamicamente as larguras das células usando a largura interna de um intervalo, em reação aos eventos de redimensionamento da janela.

Atualmente, assume-se que cada célula normalmente obtém 50% da largura da linha e recolhe a célula direita para manter a célula esquerda em sua largura máxima para evitar o transbordamento. Você pode implementar uma lógica de balanceamento de largura muito mais complexa, dependendo dos seus casos de uso. Espero que isto ajude:

Marcação para a linha que usei para testar:

<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 que conecta o evento de redimensionamento:

$(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
fonte
18

Existe uma solução muito mais fácil e elegante.

Dentro da célula da tabela que você deseja aplicar o truncamento, basta incluir uma div do contêiner com o layout da tabela css: fixed. Esse contêiner ocupa toda a largura da célula da tabela pai, portanto, até age como responsivo.

Certifique-se de aplicar truncamento aos elementos da tabela.

Trabalhos do 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>

e css:

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

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

aqui está um Fiddle em funcionamento https://jsfiddle.net/d0xhz8tb/

satyavh
fonte
Esta solução requer 2 elementos adicionais no nível do bloco para obter um efeito não estrutural. É possível definir uma célula da tabela para "display: table", o que permite que você se livre de uma das divs. jsfiddle.net/rza4hfcv Não tenho certeza, o que devo pensar sobre isso. Mas obrigado por compartilhar sua solução!
Armin
Você teve algum problema com essa solução? Estou pensando em usá-lo em um ambiente profissional.
Armin
@ armin, tente duplicar a célula que deseja truncar: você não pode colocar mais de um lado a lado.
21815 DanielM
Eu não diria que esta é uma solução final. Você perde um dos principais benefícios de uma tabela: que as colunas sejam redimensionadas de acordo com seu conteúdo. Se você configurar todas as colunas como essa, todas elas terão a mesma largura, independentemente do tamanho do seu conteúdo.
21815 DanielM
@DanielM Você pode estender a solução aninhando ainda mais a tabela - como nos antigos dias de layout da tabela - mas agora apenas com css.
Armin #
11

O problema é o 'layout da tabela: fixo', que cria colunas de largura fixa com espaçamento uniforme. Porém, desabilitar essa propriedade css eliminará o excesso de texto, pois a tabela se tornará o maior possível (e não há nada a notar).

Sinto muito, mas neste caso Fred não pode comer seu bolo e comê-lo para ... a menos que o proprietário dê a Celldito menos espaço para trabalhar, em primeiro lugar, Fred não pode usá-lo.

Andre Haverdings
fonte
9

Você pode tentar "ponderar" determinadas colunas, assim:

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

Você também pode tentar alguns ajustes mais interessantes, como usar colunas de 0% de largura e usar alguma combinação da white-spacepropriedade CSS.

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

Você entendeu a ideia.

Elliot Cameron
fonte
3

Sim, eu diria que trintadot tem, não há como fazê-lo, a menos que você use um método js. Você está falando de um conjunto complexo de condições de renderização que precisará definir. por exemplo, o que acontece quando as duas células estão ficando grandes demais para seus apartamentos, você terá que decidir quem tem prioridade ou simplesmente dar a eles uma porcentagem da área. você estica as pernas na outra célula, de qualquer forma, não há como fazê-lo com css. Embora existam algumas coisas bem descoladas que as pessoas fazem com o CSS, eu não pensei nisso. Eu realmente duvido que você possa fazer isso.

user648116
fonte
3

Use algum hack css, parece que display: table-column;pode vir resgatar:

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

.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;
}

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

blai
fonte
Ótima solução! Obrigado!
Valeriu92
Parecia muito bom até que eu adicionei uma célula estática antes de uma célula flexível: jsfiddle.net/7u59asyp/5
Sam
este é o único que trabalhou para mim, embora não perfeitamente, desde que eu tenho 4 colunas com diferentes tamanho do conteúdo esperado
downhand
3

Basta adicionar as seguintes regras ao seu td:

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

Exemplo:

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: Se você deseja definir uma largura personalizada para outra tdpropriedade de uso min-width.

Alexandre Annic
fonte
O problema é que, por padrão, as colunas da tabela consomem espaço proporcionalmente. Se o conteúdo de uma linha for maior que o de outra, ele alocará mais da largura. No entanto, essa técnica divide uniformemente o espaço. Existe uma solução alternativa?
Malik Brahimi
2

Esta questão aparece no topo do Google, então, no meu caso, usei o snippet css em https://css-tricks.com/snippets/css/truncate-string-with-ellipsis/, mas aplicá-lo ao td NÃO deu o resultado desejado.

Eu tive que adicionar uma tag div ao redor do texto no td e as reticências finalmente funcionaram.

Código HTML abreviado;

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

CSS abreviado;

.truncate { width: 300px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
MarcoZen
fonte
0

Verifique se "nowrap" resolve o problema até certo ponto. Nota: nowrap não é suportado em 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
fonte
white-space: nowraptem o mesmo efeito que o nowrapatributo (e estou usando no exemplo). Adicioná-lo aqui não muda nada, pelo que sei.
S4y 23/05
0

você pode definir a largura da célula direita para o mínimo da largura exigida e aplicar o excesso de texto oculto + excesso de texto no interior da célula esquerda, mas o Firefox é um bug aqui ...

embora, aparentemente, o flexbox possa ajudar

4esn0k
fonte
0

Eu estive trabalhando recentemente nisso. Confira este teste do jsFiddle , tente alterar a largura da tabela base para verificar o comportamento).

A solução é incorporar uma tabela em outra:

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

Fred agora está feliz com a expansão do Celldito?

IG Pascual
fonte
Desculpe pela falta de resposta! Não vejo como isso se comporta de maneira diferente de uma única tabela. Quando vejo o violino no Chrome ou Firefox, ele se parece exatamente com a segunda captura de tela da pergunta. Estou esquecendo de algo?
S4y
Desculpe, o link não foi o que eu postei. Na verdade, é este jsfiddle.net/VSZPV/2 . Altere o texto das duas células e a largura da tabela principal para testar. A esperança é o que você procura ...
IG Pascual
0

Não sei se isso vai ajudar alguém, mas resolvi um problema semelhante especificando tamanhos de largura específicos em porcentagem para cada coluna. Obviamente, isso funcionaria melhor se cada coluna tiver conteúdo com largura que não varie muito.

DKO
fonte
-1

Eu tive o mesmo problema, mas precisava exibir várias linhas (onde text-overflow: ellipsis;falha). Eu o resolvo usando um textareadentro de TDe depois o estilizo para se comportar como uma célula da tabela.

    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
fonte
-2

Dado que 'layout da tabela: fixo' é o requisito essencial do layout, que isso cria colunas não ajustáveis ​​com espaçamento uniforme, mas que você precisa criar células com larguras percentuais diferentes, talvez defina o 'colspan' de suas células como um múltiplo?

Por exemplo, usando uma largura total de 100 para facilitar os cálculos de porcentagem e dizendo que você precisa de uma célula de 80% e outra de 20%, considere:

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

Obviamente, para colunas de 80% e 20%, você pode definir a coluna de célula de 100% de largura para 5, 80% para 4 e 20% para 1.

Siubear
fonte
1
Hey @Siubear. Qual é a diferença de especificar uma largura percentual no tds?
S4y
Usar o colspan dessa maneira é uma ideia horrível. Por que não usar a largura?
Percy