Convert text-overflow: ellipsis text to "floating" view of full text - css

I have an Angular/Material side panel containing label/input control pairs. An example is below pairing a label with a mat-slide-toggle:
<div class="flex justify-between items-center">
<span class="mat-slide-toggle-content">
{{ 'StringReference' | translate }}
</span>
<mat-slide-toggle [ngModel]="booleanValue" (ngModelChange)="handleModelChange($event)" name="aToggle" color="primary">
</mat-slide-toggle>
</div>
Since some of the label text could be long, particularly in translated versions, I'd like to have a "backup plan" maintaining the layout but still making the label text accessible. The ellipsis works fine when the label is too wide and text-overflow: ellipsis is set.
Maintaining access to the whole string is my problem. I'd like to "tooltip-ize" the label text, floating it above the neighbor control on hover without relayout, showing the whole string. I can change the text-overflow setting, of course, and generally stretch the label to fit, but this causes a relayout of the control, which I don't like. Since I have hundreds of such labels, I don't want an HTML or JavaScript solution with tooltips or similar.
Any CSS-only thoughts that might work?

This might not be the perfect answer as your code snippet wouldn't render here, but I imagine it's just a side pullout kind of thing. Here's a potential, CSS-only solution that you could work with; I just used bootstrap columns to show cutoff and expansion:
Concept: Toggle styles on active state.
Example: https://stackblitz.com/edit/ellipsis-but-shown-on-active
The gruntwork would be in the two custom classes which I modeled for col-4 at a certain width:
.col-4-overflow {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
cursor: pointer;
}
.col-4-overflow:active {
overflow: visible;
text-overflow: inherit;
background: cornsilk;
position: relative;
min-width: 66.66666666666666%;
margin-right: -180px;
z-index: 1;
}
You might be able to figure out a more elegant replacement for the margin-right and z-index values of the active state, I dunno. :)

Related

Angular material - list with selection text truncate

I am trying to use the Angular Material list with checkboxes but with text which needs to be truncated rather than word wrapped (due to UI space limitation). I have forked the example within the Angular Material site to show the problem. The text kinda truncates but not with an ellipse or as I was hoping/expecting. Could some css ninja help?
https://stackblitz.com/edit/angular-xqk8h8
Looks like:
I'm expecting each line to end with "..." before the checkbox.
I have the CSS of text-truncate: ellipsis and white-space: nowrap
Changes required were a sub div as below
<div class="text">
Another example of quite long text which will need truncating on many screens
</div>
</div>
And adding the below css makes the overflow work
.content {
display:flex;
}
.text {
flex:1;
min-width: 0px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}

Collapse table-row's height in pure CSS (without affecting the table width)

I have the following piece of HTML with effectively a table for an aligned form:
<div id="one">
<p>
<label for="a">a</label> <input type="text" id="a">
</p>
<p class="h">
<label for="b">bbbbbb</label> <input type="text" id="b">
</p>
</div>
with the following CSS:
#one {
display: table;
width: auto;
}
p {
display: table-row;
}
p label, p input {
display: table-cell;
}
#one is something of automatically computed width, and labels and inputs are of unknown width. I want the functionality of an aligned form, but such that adding class h to their row removes then, making space for other elements vertically, but not changing width of #one, since it is supposed to sit next to other elements with automatically computed width.
What .h definition in CSS3 would give me my "table row" (p) height equal to 0 or otherwise visually remove it without changing the width of its parent? I can change HTML if needed, but I want to find a solution that does not use JS for that.
visibility: hidden does not remove it vertically, height: 0 does not work (probably because it is table-row), and display: none does not work, because it changes the effective width to 0. And I want my #one to stay the same width. Using display: block !important in combination with height: 0 partially works, but leaves a weird vertical space (and block should not really be a child of table).
What I'm searching for is similar to this SO question, but I'm searching for a pure CSS solution and without fixing the table width.
You can play with it here: JSFiddle.
Ok, this might work as your solution. Note that it doesn't have to be flex - it works with floats as well, but it doesn't work with display: table (and to be honest, I don't really see the point of using it in 2018).
Btw, I have added one more "row" after the .h so that we can control what happens. If everything is working correctly, we should see .h vertically "collapsing" so that the first and the third rows are in contact.
#one {
display: inline-block;
background-color: #F0FFFF;
}
p {
display: flex;
justify-content: space-between;
margin: 0; /* this is crucial because paragraphs have some margin set by default and I cannot know do you "reset" or "normalize" your css */
}
.h {
transform: scaleY(0); /* this is something that is used actually quite often for animating dropdown menus */
transform-origin: 50% 0; /* this line of code isn't contributing anythow NOW to your problem, but should you choose to animate "collapsing" the height of the row, it is setting its origin of transformation to the middle of the top border */
height: 0;
}
<div id="one">
<p>
<label for="a">a</label> <input type="text" id="a">
</p>
<p class="h">
<label for="b">bbbbbb</label> <input type="text" id="b">
</p>
<p>
<label for="a">a</label> <input type="text" id="a">
</p>
</div>
Additionally, you can add visibility: hidden if you want, but it doesn't change the solution. Hope it helped.
EDIT:
In searching for the solution, I have just stumbled upon this article (especially - this part). Although the article suggests that visibility: collapse should almost never been used, I felt it's worth mentioning it because it answers your original question. And, to be honest, I've learned about that "feature" of visibility just now while researching. Probably because nobody ever uses it :D.
CSS for your original code would have just this one more rule added (but you could also combine it with scaleY, height...):
#one {
display: table;
width: auto;
}
p {
display: table-row;
}
p label, p input {
display: table-cell;
}
.h {
visibility: collapse;
}
Further reading:
MDN: Visibility
(visibility: collapse) For rows, columns, column groups, and row groups, the row(s) or column(s) are hidden and the space they would have occupied is removed (as if display: none were applied to the column/row of the table). However, the size of other rows and columns is still calculated as though the cells in the collapsed row(s) or column(s) are present. This value allows for the fast removal of a row or column from a table without forcing the recalculation of widths and heights for the entire table.

CSS: Truncate left text but keep right one following after truncate

I have a case which I'm trying to solve with pure CSS, but I somehow feel like it is not possible (or at least not without using tables).
Imagine following layout
<div class="parent">
<span class="name">
Some name
</span>
<span class="number">
123
</span>
</div>
I want the parent to be of a fixed width and then have name followed inline by number. However, if the name is too long, I would like it to truncate (using ellipsis), but the number should remain and be moved to the right until it reaches the border of parent.
Here are few examples to illustrate.
Short text 1 |
Longer text 12 |
Very, very lon..123|
Notice that also the number text can have variable length (thus the width can't be fixed).
Any ideas?
CSS Flexbox layout does a good job of making this sort of thing a breeze. You can read about the details on using it on the MDN article "Using CSS Flexible Boxes", but here is a simple example of how it can solve your layout:
.parent {
display: flex;
width: 8em;
}
.name {
/* Make width shrinkable beyond width of content */
flex: 0 1 auto;
/* Make sure text doesn't wrap or push beyond element boundaries */
overflow: hidden;
white-space: nowrap;
/* Show an ellipsis when text cuts off */
text-overflow: ellipsis;
}
.number {
/* Make width inflexible */
flex: 0 0 auto;
}
You can see it in action in this example JSBin.

Dynamic width float-left with ellipsis

I have a single-line fixed-width container div with two variable-width span inside. Any overflow of the first span should be hidden with an ellipsis. The second span floats on the right and should be shown in full. Please see this Fiddle:
<div class='container'>
<span class='left'>Long long variable stuff</span>
<span class='right'>Changing stuff</span>
</div>
I want the first span's width to dynamically adjust according to the width of the second span so that both span stay on the same line. How can I do that?
You can use Flexbox, so with flex: 1 on .right, .left will adjust its size and overflow will be hidden.
.container {
width: 200px;
display: flex;
border: 1px solid black;
}
.left {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.right {
flex: 1;
white-space: nowrap;
}
<div class='container'>
<span class='left'>Long long variable stuff</span>
<span class='right'>Changing stuff</span>
</div>
I don't think there's any way for CSS to dynamically know the length of an element without javascript. If you're looking for a purely CSS solution you're going to need to give it some direction in order for it to know the widths you want. Visually, that might be a bit of a compromise for you, but it will allow you to ensure that everything is always on one line.
For the solution I'm about to propose to work you need to know one width of the two. In this case I'm going to say that you can make a best guess of the "changing stuff" on the right.
Your first problem is that spans are inline elements by default - not inline-block. In order to get the overflow text property to work, you need to use it with an inline-block or block element.
The next piece is to use calc. Calc excepts mixed measurements so you can subtract an exact pixel value off of a percent. This works really well for responsive layouts.
I've created an updated version of your plunker to illustrate:
https://jsfiddle.net/n19ddahb/5/

CSS Flexbox dynamic aspect-ratio code is influenced by content

For a webpage grid-layout I decided to use Flexbox. Now I wanted to implement some "auto-functionality", so that grid-boxes can later be inserted without the need to add classes or styles in the HTML. One of this features is to make a box allways be 75% as tall as it is wide - even if the box is resized by, for example, browserwindow resize. Off course, if the boxes content extends the 75%-height, it should (and only then should) increase its height to fit the content. I searched for hours to find a suitable solution, but I finally got it working. So I thought at least, until I added content to the box.
The auto aspect-ratio works fine, as long as the box is empty. If I add content, the 75% of the width is allways added to the height it has through extension by its content. I made a jsfiddle to clearly visualize the problem:
JSFiddle wd5s9vq0, visualizing the following Code:
HTML-Code:
<div class="container">
<div class="content-cell"></div>
<div class="content-cell"></div>
</div>
<div class="container">
<div class="content-cell">
This cell has an inreased height because of
it's content. The empty space below the
content is the 75% of the cells width.
</div>
<div class="content-cell"></div>
</div>
CSS:
.container {
display: flex;
width: 400px;
}
.content-cell {
flex: 1 1 0;
margin: 10px;
background-color: #ccc;
}
.content-cell::after {
content: "";
display: block;
padding-top: 75%;
}
If I didn't knew it better, it looks like a floating-problem - but I think the ::before / ::after selector should add the block-element before the element it is used on and not inside it.
Does anyone has an idea on how to fix this problem?
This seems to be a very widespread problem on the internet, and most solutions you find are either about wrapping the content, absolute-positioning the content or a mixture of both. This has numerous and case-dependent downsides. After hours of playing around with the code, I finally found a combination of CSS proporties that work without the need to add any DOM or make the content absolute-positioned. This looks quit basic, and I am wondering why it took me so long and why you can't find it out there on the web.
The HTML:
<div class="mybox aspect-full">
This is text, that would normally extend the box downwards.
It is long, but not so long that it extends the intended aspect-ratio.
</div>
The CSS:
.mybox {
width: 200px;
}
.aspect-full::before {
content: '';
display: block;
padding-top: 100%;
float: left;
}
The only downside I could find is that the content of your cell must float. If you use clear on one of your child objects, it is positioned below the expander-block and you are back to the original problem. If you need to clear the floating of divs inside of these aspect-ratio-cells, you might consider to wrap them and keep the wrapper floatable.

Resources