Revealing text-overflow: ellipsis
One of the curses of building "enterprise applications" is the usual scenario of dealing with interfaces with too much data in them. "Must show all fields" and "needs more columns" are typical requests that make UX designers and front-end developers die a little on the inside. 😱
Uncritically adding more content is in general a bad approach: it increases the cognitive load of users, creates more intimidating interfaces for newcomers, makes performance worse, and many other negative effects. Adding a piece of information to your interface should be an exercise in weighing costs and benefits.
But what to do when you must display more data? If the design does not accommodate it, you can break the whole layout. Especially with smaller screens and user-generated data, a single long name or label can introduce awkward wrapping or the tragicomedy of horizontal scrolling. In despair, the "what if we just trim it with dot-dot-dot" suggestion comes up.
Enter text-overflow: ellipsis
. Set this on a container with a specific width and overflow: hidden
, and any text content will be trimmed with an elegant ellipsis character "…"
Let's look at a simple example; a flex container with three items:
<div class="parent">
<div class="container">This is some content</div>
<div class="container">This is some content, a bit longer</div>
<div class="container">This fits</div>
</div>
.parent {
border: 0.75rem solid rebeccapurple;
display: flex;
gap: 0.5rem;
width: fit-content;
}
.container {
border: 0.75rem solid lightsteelblue;
display: inline-block;
padding: 0.5rem;
}
When we provide a specific width
or max-width
to our containers (or otherwise limit their size), we can see the overflow problem (this is the defining behaviour of CSS).
.container {
white-space: nowrap;
width: 10rem;
}
The sensible solution here is to go back to the drawing board and consider our options: limit the size of the content, expand the available space by moving other elements, wrap content into multiple lines… We're not doing sensible things here. 🧨 Let's rush a fix through: the ellipsis to the rescue! (Seriously, if you call it "dot-dot-dot" we'll need to sit down and have a conversation.)
.container {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 10rem;
}
So, we had a problem before, we have a different problem now! It looks visually better, but it conveys even less information. I can't event select the whole text, copy, and paste it somewhere else to read it. This really doesn't solve much unless the whole content is not very interesting. For instance, a listing of emails can display the first few words of each message body and truncates the rest with ellipsis. But for other scenarios, especially those where it's not possible to navigate to the full data view, this is Not Good Enough.
We could re-evaluate and redesign; instead, let's dig deeper. One suggestion that usually comes up is "just place the full content in the title
attribute; it shows up on hover". Indeed, the browser will display a tooltip when hovering over such an element. This is worse than it sounds:
- The "hover" behaviour doesn't work without an appropriate pointing device. Touchscreen and keyboard users will remain sad/angry and without a tooltip
- Tooltips can be slow to appear
- The content will be truncated at different lengths in different browsers
- You can't style the tooltips. At all
- This is abusing the
title
attribute. It is meant to provide "advisory information related to the element" - It duplicates data
- In short, it's an accessibility no-no
Here's the same example, with mistreated title
attributes; try to read those on your phone. 😏
OK, fine. What else can we do? Redesign? Nah! Let's keep at this on-hover idea. We could pull in a big tooltip Javascript library to bypass most of the concerns above. Or… we could CSS our way out. Let's add one more wrapper element (in this case a <span>
but it's not important) to create our own on-hover behaviour.
<div class="parent">
<div class="container">
<span>This is some content</span>
</div>
<div class="container">
<span>This is some content, a bit long</span>
</div>
<div class="container">
<span>This fits</span>
</div>
</div>
.container {
width: 10rem;
}
.container > span {
display: block;
overflow: hidden;
padding: 0.5rem;
text-overflow: ellipsis;
white-space: nowrap;
}
.container:hover > span {
background-color: inherit;
contain: paint;
display: inline-flex;
outline: 1px solid;
min-width: 100%;
}
If you look carefully you'll notice that we moved the overflow
and text-overflow
properties to the inner wrapper, instead of keeping them on .container
. This allows .container
to use the default of overflow: visible
(i.e. the behaviour on the very first example).
The inner wrapper is now responsible for hiding the overflow… until it's hovered. When it is, we change its display
to inline-flex
, which forces its layout to expand and wrap the full contents. Since the parent is still locked at width: 10rem
it does not change dimensions, and the overflow simply spills out.
Here's how it looks (try hovering):
Why inline-flex
? We could use inline-block
, but that positions the element along the baseline, changing the parent's line-height, and we'd need to start playing with vertical-align
. The default behaviour of inline-flex
or inline-grid
does what we want.
A drawback here is that every element that has this behaviour applied will have the :hover
effect, even if it fits perfectly well within its container. Maybe Container Queries will allow addressing this problem. In the meantime, styling the hover state so that it looks good in both cases is advisable.
We still haven't addressed the issue with keyboard and touchscreen users. We need to make the elements focusable, but there is currently no way to make this happen with CSS (and probably there won't be for a while). The way to do this is to add the tabindex="0"
attribute to every relevant element.
<span tabindex="0">This is some content, a bit long</span>
We use the value of 0
to allow the browser to keep the tabbing order in accordance with source order. Now we just need to add a selector to the rule targeting the wrapper so it triggers also on focus.
.container:focus-within > span,
.container:hover > span {
/* … */
}
The final result is focusable both via keyboard navigation and touch interface. If you're using a mouse, try clicking this paragraph of text and then tabbing into the elements below.
There's a bonus for mouse users, too: since focus remains after clicking, you can click-to-focus and then move the cursor freely without losing the "tooltip".
So, should you use this "Reveal text-overflow: ellipsis
" technique? Probably not. In most cases the right solution is to reconsider the design and find a better way to surface the relevant content. Move what's not relevant into a different component or page. But if you're already using ellipsis in some minor places, this technique might offer some improvement.
The one scenario where it can make sense to use this technique is in a table with high variability of cell content size. The example below shows this — and if you look at it in a phone screen you'll also see why this is not a good overall solution to making your content responsive. It can help at certain breakpoints, though.
First name |
Last name |
Role |
Company |
City |
Country |
IP Address |
Department |
---|---|---|---|---|---|---|---|
Cristine |
Polding |
Supervisor |
Beer-Cruickshank |
Smolyaninovo |
Russia |
184.97.171.254 |
Services |
Tito |
O' Mara |
Engineer |
Ryan Inc |
Essang |
Indonesia |
185.88.223.177 |
Training |
Sheffie |
Hellwig |
Estimator |
Bergstrom-Donnelly |
Myshkin |
Russia |
84.148.213.10 |
Accounting |
Ree |
Whines |
Estimator |
Nader Group |
Solna |
Sweden |
40.171.71.148 |
Services |
Fionnula |
Fibbings |
Architect |
Parker-Ankunding |
Fukumitsu |
Japan |
236.94.63.183 |
Accounting |
Gaby |
Caldairou |
Architect |
Harber-Kessler |
Borne Sulinowo |
Poland |
137.119.243.204 |
Support |
Sawyer |
Ocheltree |
Construction Expeditor |
Powlowski-Littel |
Xinghua |
China |
10.24.67.242 |
Sales |
Aurore |
Crimin |
Surveyor |
Schulist-Stiedemann |
Sever do Vouga |
Portugal |
161.155.137.252 |
Business Development |
Gregoor |
Thonger |
Engineer |
McGlynn, Schulist and Gutkowski |
Lawrenceville |
United States |
207.154.165.2 |
Engineering |
Ronnie |
Dockwray |
Electrician |
Considine, Satterfield and Murray |
Seshcha |
Russia |
238.107.64.105 |
Services |
Mock data from Mockaroo