Reputation: 6770
I have a big filename that I'm cropping using css text-overflow: ellipsis.
<style>
#fileName {
width: 100px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
</style>
<div id="fileName"> This is the big name of my file.txt</div>
So I have this output
This is the bi...
But I want to preserve the file extension and have something like this
This is the... le.txt
Is it possible only using CSS?
Since my files are always txt, I've tried to use text-overflow: string
, but it looks like it only works on Firefox:
text-overflow: '*.txt';
Upvotes: 37
Views: 43261
Reputation: 1
My answer:
.outer-container {
border: 1px solid black;
width: 80vw;
margin: 8px;
}
.text-container {
display: flex;
flex-direction: row;
justify-content: flex-start;
}
.left-span {
white-space: pre;
overflow: hidden;
max-width: 50%;
text-overflow: ellipsis;
}
.right-span {
white-space: pre;
overflow: hidden;
max-width: 50%;
}
<div class="outer-container">
<div class="text-container"><span class="left-span">A long string that is long and bla bla bla b</span><span dir="rtl" class="right-span"><span dir="ltr">la bla bla bla bla bla and now it's the end.</span></span>
</div>
</div>
in react:
const TruncateMiddle = ({children: text}: {children: string}) => {
const halfwayIndex = Math.floor(text.length / 2);
const firstHalf = text.slice(0, halfwayIndex);
const secondHalf = text.slice(halfwayIndex);
return (
<div
style={{
display: 'flex',
flexDirection: 'row',
justifyContent: 'flex-start',
}}
title={text}
>
<span
style={{
whiteSpace: 'pre',
overflow: 'hidden',
textOverflow: 'ellipsis',
maxWidth: '50%',
}}
>
{firstHalf}
</span>
<span
dir="rtl"
style={{
whiteSpace: 'pre',
overflow: 'hidden',
maxWidth: '50%',
}}
>
<span dir="ltr">{secondHalf}</span>
</span>
</div>
);
};
export default function App() {
return (
<div
style={{
border: '1px solid black',
width: '80vw',
margin: '8px',
}}
>
<TruncateMiddle>
A long string that is long and bla bla bla bla bla bla bla bla bla and
now it's the end.
</TruncateMiddle>
</div>
);
}
Upvotes: 0
Reputation:
CSS is good, but I think you must do it by JavaScript for more accurate results. Why? Because, with JS You can control number of first and last texts of words. This is just 2 lines of JavaScript code to crop string as per you define:-
let fileName=document.getElementById('fileName')
fileName.innerHTML=fileName.innerHTML.substring(1, 10)+'...'+fileName.innerHTML.slice(-2)
<div id="fileName"> This is the big name of my file.txt</div>
also, you can choose first n
words, instead of first few letter/characters with JS, as per you want.
whose JS code is this:-
let fileName=document.getElementById('fileName')
let Words=fileName.innerHTML.split(" ")
let i=0;
fileName.innerHTML=''
Words.forEach(e => {
i++
if(i<5)
fileName.innerHTML+=e+' '
});
fileName.innerHTML+='...'
<div id="fileName"> This is the big name of my file.txt</div>
Upvotes: 0
Reputation: 380
I tried some of those CSS approach but the problem is if the text is short, you will get "short text short text" instead of "short text".
So I went with CSS + JS approach. JS (I edited Jeremy Friesen's to fix some cases):
const shrinkString = (originStr, maxChars, trailingCharCount) => {
let shrinkedStr = originStr;
const shrinkedLength = maxChars - trailingCharCount - 3;
if (originStr.length > shrinkedLength) {
const front = originStr.substr(0, shrinkedLength);
const mid = '...';
const end = originStr.substr(-trailingCharCount);
shrinkedStr = front + mid + end;
}
return shrinkedStr;
}
HTML:
<div>
<h5>{shrinkString("can be very long of short text", 50, 15)} </h5>
</div>
CSS:
div {
width: 200px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
I hope it helps. Sorry for the format. This is my first answer on SO.
Upvotes: 2
Reputation: 167
I found out the css solutions quite buggy and hard to maintain, since you need to add attributes or elements to separate text.
I built a quite straight forward Javascript that handles it. Send your text and max length of the text and you get the text truncated in the middle back.
const truncateMiddle = (text, maxCharacters) => {
const txtLength = text.length; // Length of the incoming text
const txtLengthHalf = maxCharacters ? Math.round(maxCharacters / 2) : Math.round(txtLength / 2); // set max txtHalfLength
return text.substring(0, (txtLengthHalf -1)).trim() + '...' + text.substring((txtLength - txtLengthHalf) + 2, txtLength).trim() //Return the string
}
truncateMiddle('Once opon a time there was a little bunny', 10);
Returns: Once...nny
Cons? Sure, it need more functionality to be responsive.
Upvotes: 0
Reputation: 4403
Here's a solution that uses flexbox
, and is dynamic, (e.g. works when the user resizes the browser window). Disadvantage is that the text after the ellipsis has a fixed size, so you can't put the ellipsis in the exact middle of the text.
.middleEllipsis {
margin: 10px;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: flex-start;
}
.start {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex-shrink: 1;
}
.end {
white-space: nowrap;
flex-basis: content;
flex-grow: 0;
flex-shrink: 0;
}
<div class="middleEllipsis">
<div class="start">This is a really long file name, really long really long really long</div><div class="end">file name.txt</div>
</div>
Resize the right-hand side boxes on jsfiddle to see the effect:
https://jsfiddle.net/L9sy4dwa/1/
If you're willing to abuse direction: rtl
, you can even get the ellipsis right in the middle of the text with some small changes to your CSS:
.middleEllipsis {
margin: 10px;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: flex-start;
}
.middleEllipsis > .start {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex-shrink: 1;
}
.middleEllipsis > .end {
white-space: nowrap;
flex-basis: content;
flex-grow: 0;
flex-shrink: 1;
align: right;
overflow: hidden;
direction: rtl;
}
You can see an animated gif of what this looks like on https://i.sstatic.net/CgW24.gif.
Here's a jsfiddle showing this approach:
https://jsfiddle.net/b8seyre3/
Upvotes: 9
Reputation: 614
The accept answer is good. Although for Browser Compatibility, you could do the detection for truncate or not. Make the whole CSS conditional.
const wrap = document.getElementById('filenameText');
if (wrap.offsetWidth >= wrap.scrollWidth) {
this.truncation = false;
}
<div
:data-filetype="data-filetype"
:class="[truncation && 'truncateFilenamClass']"
>
Upvotes: 0
Reputation: 24692
Here is a clean CSS solution using the data-*
attribute and two ::after
pseudo-elements. I also added an optional hover and show all text (the #fileName::after
pseudo element needs to be removed when the full text is shown).
#fileName {
position: relative;
width: 100px;
}
#fileName p {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
#fileName:after {
content: attr(data-filetype);
position: absolute;
left: 100%;
top: 0;
}
/*Show on hover*/
#fileName:hover {
width: auto
}
#fileName:hover:after {
display: none;
}
<div id="fileName" data-filetype="txt">
<p>This is the big name of my file.txt</p>
</div>
The #fileName p::after
is given a background color that matches the background of the text. This covers the ".txt" when the filenames are short and therefore not cut off with overflow: hidden
.
Note the padding-right: 22px
, this pushes the ".txt" beyond the ellipsis.
Refer to examples 2 and 3 below for different methods with different browser support for each. It doesn't seem to be possible to hide the ".txt" happily in all browsers.
Browser Compatibility: Chrome and Firefox.
The #fileName p::after
is given a background color that matches the background of the text. This covers the ".txt" when the filenames are short and therefore not cut off with overflow: hidden
.
Note the padding-right
on each of the ::after
pseudo-elements. padding-right: 22px
pushes the ".txt" beyond the ellipsis and padding-right: 100%
gives the covering pseudo-element its width. The padding-right: 100%
doesn't work with Edge or IE 11.
#fileName {
position: relative;
width: 122px;
}
#fileName::after {
content: attr(data-filetype);
position: absolute;
right: 0;
top: 0;
}
#fileName p {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
padding-right: 22px;
}
#fileName p::after {
content: '';
background: #FFF;
position: relative;
padding-right: 100%;
z-index: 1;
}
/*Show on hover*/
#fileName:hover {
width: auto;
}
/*Hide .txt on hover*/
#fileName:hover::after {
display: none;
}
<div id="fileName" data-filetype=".txt">
<p>This is the big name of my file.txt</p>
</div>
<div id="fileName" data-filetype=".txt">
<p>Short.txt</p>
</div>
Browser Compatibility: IE 11, Edge and Chrome.
The content: ... unholy amount of ...
on #fileName p::after
gives it width. This, along with display: inline-block
, is currently the only method that works on the Edge browser / IE 11 as well as Chrome. The display: inline-block
breaks this method on Firefox and the .txt
is not covered on short filenames.
#fileName {
position: relative;
width: 122px;
}
#fileName::after {
content: attr(data-filetype);
position: absolute;
right: 0;
top: 0;
padding-right: 10px; /*Fixes Edge Browser*/
}
#fileName p {
white-space: nowrap;
overflow: hidden;
padding-right: 22px;
text-overflow: ellipsis;
}
#fileName p::after {
content: '.........................................................................................................................';/*Fixes Edge Browser*/
background: #FFF;
position: relative;
display: inline-block;/*Fixes Edge Browser*/
z-index: 1;
color: #FFF;
}
/*Show on hover*/
#fileName:hover {
width: auto
}
#fileName:hover::after {
display: none;
}
<div id="fileName" data-filetype=".txt">
<p>This is the big name of my file.txt</p>
</div>
<div id="fileName" data-filetype=".txt">
<p>Short.txt</p>
</div>
Upvotes: 53
Reputation: 21
Input ---This is a very very very very very big file.txt
To truncate the above file name use the below javascript
Output ---This is a very...big file.txt
var selectedFileName = getItemSelected();//Input
$scope.referenceFileName =getItemSelected();
var len = selectedFileName.length;
if(len > 30){
selectedFileName = selectedFileName.substr(0,15)+'... '+selectedFileName.substr(len-15,15);
}
$scope.fileName = selectedFileName;
**
Note:
**Pass the $scope.referenceFileName in the json---back end
$scope.fileName
this would be---front end
Upvotes: 0
Reputation: 2466
Here is another suggestion that worked well for me:
<div style="width:100%;border:1px solid green;display:inline-flex;flex-wrap:nowrap;">
<div style="flex: 0 1 content;text-overflow: ellipsis;overflow:hidden;white-space:nowrap;"> Her comes very very very very very very very very very very very very very very very very very very very long </div>
<div style="flex: 1 0 content;white-space:nowrap;"> but flexible line</div>
</div>
Upvotes: 12
Reputation: 1
For a solution that works with liquid layouts I came up with something that uses flexbox. Obvious drawback is that three elements are needed. Obvious advantage: If there is enough room everything will be shown. Depending on circumstances an additional white-space rule for the paragraph might be needed as well as some min-width for the first span.
<p><span>Long text goes in here except for the</span><span>very end</span></p>
p {display:flex}
p span:first-child {flex-shrink:1; text-overflow: ellipsis; overflow: hidden}
ADDENDUM: Strictly speaking, the flex-shrink is not even necessary because it is the default behaviour of the flex-items anyway. This is not so in IE10, however. Prefixing is necessary, too in this case.
Upvotes: -1
Reputation: 383
JavaScript option:
var cropWithExtension = function(value, maxChars, trailingCharCount) {
var result = value;
if(value.length > maxChars){
var front = value.substr(0, value.length - (maxChars - trailingCharCount - 3));
var mid = "...";
var end = value.substr(-trailingCharCount);
result = front + mid + end;
}
return result;
}
var trimmedValue = cropWithExtension("This is the big file.txt", 21, 6);
Upvotes: 1
Reputation: 5510
This is the best I can come up with... It might be worthwhile trying to clean up the leading edge of the second span...
CSS
#fileName span {
white-space: nowrap;
overflow: hidden;
display:inline-block;
}
#fileName span:first-child {
width: 100px;
text-overflow: ellipsis;
}
#fileName span + span {
width: 30px;
direction:rtl;
text-align:right;
}
HTML
<div id="fileName">
<span>This is the big name of my file.txt</span>
<span>This is the big name of my file.txt</span>
</div>
http://jsfiddle.net/c8everqm/1/
Upvotes: 15