4

I tried to vertically centralize plain text inside a flex box element.

I decided to use property display:table-cell with vertical-align: middle. But it doesn't seem to work properly in flexbox elements.

How can I centralize it vertically, ideally without using a wrapper or positioning, and while still truncating long text with ellipses?

.container {
  width: 400px;
  height: 400px;
  font-weight: 700;
  border: 1px solid #d9d9d9;
  display: flex;
  flex-direction: column;
}

.item {
  display: table-cell;
  vertical-align: middle;
  flex: 1 1;
  background-color: cyan;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.item:nth-of-type(2n) {
  background-color: aliceblue;
}
<div class="container">
  <div class="item">Hello, I'm very very long string! Hello, I'm very very long string!</div>
  <div class="item">Hello</div>
  <div class="item">Hello</div>
  <div class="item">Hello</div>
</div>

View On CodePen

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
Mike Mameko
  • 199
  • 1
  • 2
  • 11

4 Answers4

6

One solution is to define each flex item as its own flex container in order to vertically center its contents with align-items:center. To keep text-overflow working, add a child element to each flex item, which can then be truncated with ellipses.

I can't offer a succinct explanation as to why text-overflow doesn't work with display:flex, and neither can David Wesst. In his words:

It turns out that there really isn't a clean way to do this. If you're wondering how I came to that conclusion you can stop because I didn't. Those responsible for the specification did, and you can read the full conversation that started with a Mozilla bug report and leads to a whole mail group discussion about why it should (or, in this case, should not) be implemented as part of the spec.

Here's a working example:

.container {
  width: 400px;
  height: 400px;
  font-weight: 700;
  border: 1px solid #d9d9d9;
  display: flex;
  flex-direction: column;
}

.item {
  display: flex;
  align-items: center;
  flex: 1;
  background-color: cyan;
}

.item span {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.item:nth-of-type(2n) {
  background-color: aliceblue;
}
<div class="container">
  <div class="item"><span>Hello, I'm very very long string! Hello, I'm very very long string!</span></div>
  <div class="item"><span>Hello</span></div>
  <div class="item"><span>Hello</span></div>
  <div class="item"><span>Hello</span></div>
</div>

Also see:
Setting ellipsis on text from a flex container

showdev
  • 28,454
  • 37
  • 55
  • 73
4

When you make an element a flex container (with display: flex or display: inline-flex), all in-flow children become flex items.

All flex items have their display value controlled by the container. It doesn't matter what you specify, the container overrides it.

So when you give a flex item display: table-cell, the browser ignores it. Here's what it looks like in Chrome Dev Tools:

Style Tab

enter image description here

Computed Tab

enter image description here

A flex container "blockifies" flex items, causing them to assume many qualities of block-level elements (source).

But the vertical-align property applies only to inline-level and table-cell elements (source).

That's why it doesn't work.

Regardless, vertical-align, even if it worked, is a totally unnecessary hack in this case. There are flex properties designed for aligning content in flex items.

.container {
  width: 500px;
  height: 500px;
  font-weight: 700;
  border: 1px solid #d9d9d9;
  display: flex;
  flex-direction: column;
}

.item {
  flex: 1 1;
  display: flex;
  justify-content: center; /* horizontal alignment, in this case */
  align-items: center;     /* vertical alignment, in this case */
  background-color: cyan;
}

.item:nth-of-type(2n) {
  background-color: aliceblue;
}
<div class="container">
  <div class="item">Hello</div>
  <div class="item">Hello</div>
  <div class="item">Hello</div>
  <div class="item">Hello</div>
</div>  

Related posts:

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • 2
    The question was changed. The long text wasn't in the original code. So this answer now covers the alignment part of the new question, but not the ellipsis part. – Michael Benjamin Oct 20 '17 at 17:11
0

Blockquote ...float, clear and vertical-align have no effect on a flex item. according to https://css-tricks.com/snippets/css/a-guide-to-flexbox/

See How to vertically align text inside a flexbox? for a possible solution.

beltouche
  • 731
  • 6
  • 15
0

You have to define those items also as flex containers, using the following CSS for them (no table-cell display...):

display: flex;
flex-direction: column;
justify-content: center;

.container {
  width: 400px;
  height: 400px;
  font-weight: 700;
  border: 1px solid #d9d9d9;
  display: flex;
  flex-direction: column;
}

.item {
  display: flex;
  flex-direction: column;
  justify-content: center;
  flex: 1 1;
  background-color: cyan;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.item:nth-of-type(2n) {
  background-color: aliceblue;
}
<div class="container">
  <div class="item">Hello, I'm very very long string! Hello, I'm very very long string!</div>
  <div class="item">Hello</div>
  <div class="item">Hello</div>
  <div class="item">Hello</div>
</div>
Johannes
  • 64,305
  • 18
  • 73
  • 130