Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Table] Columns get misaligned in dense tables #6058

Closed
jpett opened this issue Jul 26, 2017 · 14 comments · Fixed by #10594
Closed

[Table] Columns get misaligned in dense tables #6058

jpett opened this issue Jul 26, 2017 · 14 comments · Fixed by #10594
Assignees
Labels
P4 A relatively minor issue that is not relevant to core functions
Projects

Comments

@jpett
Copy link

jpett commented Jul 26, 2017

Bug, feature request, or proposal:

Bug. We are currently using md-table in an application that displays complex tables with a lot of columns containing financial data. The tables oftentimes become rather dense and there is not a lot of room left for each column. If a cell's content is too long and cannot be wrapped, the cell grows in size shifting the row's remaining cells to the right. In our case the problem gets even worse because we need to indent the content of the first cell (using padding-left) in order to visualize hierarchical information.

What is the expected behavior?

md-table should behave like an HTML table and ensure all cells in the same column have the same width.

What are the steps to reproduce?

I have created a plunker that shows the problem:
https://plnkr.co/edit/kJF4NNCrFLRu4g4pFwRc?p=preview

Which versions of Angular, Material, OS, TypeScript, browsers are affected?

material@2.0.0-beta.8, angular 4.3.1

Sorry if I should have overlooked any issue already describing this problem and thanks for all your work on this great library! :)

@jpett
Copy link
Author

jpett commented Jul 27, 2017

I think I found a workaround for this problem. By changing the css to use display: table instead of flexbox, the browser takes care of all layout problems quite nicely. Not sure what the rationale behind using flexbox instead of table was, however. Maybe I have overlooked something?

.mat-table {
  display: table;

  > .mat-header-row, > .mat-row {
    display: table-row;

    > .mat-header-cell, > .mat-cell {
      display: table-cell;
      height: 48px;
      vertical-align: middle;
    }
  }
}

@andrewseguin andrewseguin self-assigned this Jul 27, 2017
@EvAlex
Copy link

EvAlex commented Jul 28, 2017

Thanks, @jpett! I modified your styles a bit (restored border, fixed width and paddings):

.mat-table {
    display: table;
    width: 100%;

    > .mat-header-row, > .mat-row {
        display: table-row;
        padding: 0;
        border: none;

        > .mat-header-cell, > .mat-cell {
            display: table-cell;
            height: 48px;
            vertical-align: middle;

            border-bottom: 1px solid rgba(0, 0, 0, 0.12);
        }
    }
}

These really saved me from recalculating all the things in js... This was going to be a nightmare. Now my table looks perfect, and extends it's parent md-card. Saved my day :)

@pueaau
Copy link

pueaau commented Aug 8, 2017

Thanks guys, this is wonderful.
I've had the same problem due to long strings in some columns. Slim columns also take up way too much space by default. I wouldn't know how to solve this using flex-layout.

@irowbin
Copy link

irowbin commented Aug 8, 2017

Any plnkr links guys?

@jpett
Copy link
Author

jpett commented Aug 8, 2017

Here you go: https://plnkr.co/edit/tzb09J?p=preview (just converted the scss code to css for the example)

@pueaau
Copy link

pueaau commented Aug 8, 2017

I ran into problems problems when I tried to combine this with expandable table rows. The expanded part is now only one column wide. Guess that happens when you combine two hacks.

Does someone know how to solve this issue using flexbox instead of native tables?

@makdeniss
Copy link

makdeniss commented Oct 5, 2017

there is a problem with the proposed solution (display: table): the max-height attribute doesn't work anymore. So table scrolling is gone.

@andrewseguin
Copy link
Contributor

tl;dr: just add overflow: hidden; word-wrap: break-word to your cells

The issue here stems from the cell's content stretching the width. Since each cell has different content, they become misaligned and the table looks wonky.

image

To resolve this, tell each cell that it cannot overflow and that it should wrap its content rather than stretch the container.

Here's some CSS that fixes this case:

.mat-cell, .mat-header-cell {
  overflow: hidden;
  word-wrap: break-word;
}

For a plunker with this applied, see https://plnkr.co/edit/3ctqAiPsFe60Mnc3T0Eh?p=preview

image

The reason this is not included as part of the table is because the mat-table knows that cells can have a wide array of content and is not trying to be too prescriptive about how to overflow and wrap its contents. Though, an argument could be made that this should always be applied to the cells.

Note that in this particular example, I'd go one step further and say that progress and color probably can be more restricted in their width and let the name column stretch as much as it wants. This can be done by applying this CSS:

.mat-column-progress {
  max-width: 60px;
}

.mat-column-color {
  max-width: 100px;
}

Plunker of this applied: https://plnkr.co/edit/anDyDjxmECOWHlTrIwzD?p=preview

image

@jpett
Copy link
Author

jpett commented Oct 9, 2017

Thanks for your elaborated response @andrewseguin! The solution you proposed still behaves a little different from classic html tables:

  • By default a classic html table won't break any words but grow in width in order to fit it's content. Especially in responsive designs on limited screen sizes this is in my opinion a more productive solution, since you can wrap the table in an overflow: auto container (as it is e.g. common in Bootstrap, using the class . table-responsive)
  • In your solution there is no way to let the table decide how to size the columns based on its content. Your example only allows for one column with dynamic width

I understand your argument that you don't want to be too prescriptive about how to overflow and wrap the table content. Still, I would recommend using default styles that work robustly and to clearly explain this matter in the documentation. In my opinion people will stumble upon this problem rather quickly if they don't only have a sample table with a limited amount of columns.

@andrewseguin
Copy link
Contributor

@jpett Thanks for your feedback on the issue. I'm now leaning towards adding a PR that includes the overflow styles I included in my previous comment, since I'm not sure there's a good case for not wanting those styles. Hopefully this should solve most problems that people will run into, at least with regards to columns where you know what their widths should be set to.

I agree that we have a feature gap with regards to resizing based on content. It's possible to use min and max widths to adjust the table, which works well for columns that are filled with static content or fixed width buttons. But this doesn't help for dynamic content or text that shrinks/grows when internationalized (looking at you, German).

While display: table works with our current feature-set and HTML rendering, I believe that we're going to see that it doesn't play nice with features such as sticky columns, which will likely break up the templating in a significant way. I love the simplicity in using a set of styles that auto-sizes for us, but I don't think it'll work for us with our long-term plans for the table.

I'm currently trying to design/prototype what it would look like to have some inputs or directives that can be applied to a column definition that can help provide some kind of auto-sizing. E.g.

<ng-container cdkColumnDef="userName" width="shrink-to-fit">
  ...
</ng-container>

With this, a strategy can be applied each time the table renders that can resize the column based on the rendered output. If we incorporate some kind of smart-width feature, it should be easy to adapt it to also allow for simple inputs that automatically restrict the width to min/max bounds, and even provide some hooks so that you can easily resize the columns based using drag-support.

I'll soon be writing up a new set of tables for the md-table (once MdTableDataSource gets in). When I do, I'll set aside a section that talks a bit about using width styles. I agree it's non-trivial to properly set up a good responsive md-table right now, and I'm hopeful that we can design some clean solutions that helps users out.

@jpett
Copy link
Author

jpett commented Oct 10, 2017

@andrewseguin Thanks again for your extensive reply! In my opinion the word-wrap: break-word style is not a good solution for real applications. While having a dummy string like "AAAAAA" break in between is not a big deal, breaking any real data like dates, numbers, names or similar is a rather big one. I think I could not offer such a solution to our customers. Therefore I see having a break-word style just as a tiny improvement.

In the end it might just be a matter of priorities. I personally would prefer the mat-table to work more like a normal HTML table, providing autosize for columns by default without me having to set any width properties or styles. Of course, fixed headers and/or columns are also an important feature, but I think these could also be implemented without major problems in a display: table solution. In my experience it might even be a lot easier than implementing a smart-width feature, which could be kind of tricky ;)

@andrewseguin andrewseguin added this to Bugs in Table Oct 19, 2017
@andrewseguin andrewseguin changed the title md-table: column misalignment in dense tables [Table] Columns get misaligned in dense tables Oct 19, 2017
@andrewseguin andrewseguin added the P4 A relatively minor issue that is not relevant to core functions label Oct 19, 2017
@makdeniss
Copy link

@andrewseguin is there another fix for this? Unfortunately, as I stated before, I cannot use word-wrap: break-word, since this is splitting up vital information. The solution provided earlier by @jpett also doesn't work, because it breaks the view of the tables making them left-aligned and not fully sized.

@QuentinFchx
Copy link

While display: table works with our current feature-set and HTML rendering, I believe that we're going to see that it doesn't play nice with features such as sticky columns

@andrewseguin If I may, this Vue.js-based UI library achieves sticky-column (and other features) while still taking advantage of the display: table. I must admit that there is a slight animation delay (that might be due to the underlying animation implem). I might not be aware of some limitations but it sounds like a decent implementation.

I'll probably port their library because I don't think flexbox is the solution to fix the longstanding issues with tables.

On a side-note (since Google is an insider), is there any plans at the W3C level to improve the table element (especially around sticky stuff)?

@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 8, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
P4 A relatively minor issue that is not relevant to core functions
Projects
No open projects
Table
  
Closed
Development

Successfully merging a pull request may close this issue.

7 participants