Line Clampin' is especially useful for cards (news, blogs and etc.) info text where you'd like to keep the cards equal height and thus all text that is bigger than your strict max number of lines to be cut off.
Please mind that I came across so many JS libraries that tend to do this technique and I'm really not a fan of bloating my projects with unneeded/overcomplicated solitions, not to mention the possible negative effect on load times and rendering speed 🐌.
I'm also one of those front-ends that still have to support legacy browsers like IE11 (poor me 😀) and so let me present you my approach that is lightweight, effective and modern + legacy browsers compatible.
TL;DR -- check my codepen demonstrating the approach in action https://codepen.io/porg/pen/VwLmOpV
Let's say we want to cut off the text on the 3-rd line (anything bigger is cut off and ellipsized). How big is a line though? Well it depends on the font-size of the text and it's line-height. We got everything we need to do a mixin that does our job:
@mixin limitTextToLineNumbersMixin( $font-size: $font-size-base, $line-height: 1.2, $lines-to-show: 3 ) {
max-width: 100%;
height: calc(#{$font-size} * #{$line-height} * #{$lines-to-show});
font-size: $font-size;
line-height: $line-height;
overflow: hidden;
}
And now for the ellipsis ... a bit of vanilla JS (we split the text to be clamped by words and remove those words that are out of visible text area boundaries. In the end the ellipsis got appended.
function ellipsizeTextElement(element) {
var nodeList = document.querySelectorAll(element);
var elements = Array.prototype.slice.call(nodeList, 0);
elements.forEach(function(element) {
var wordArray = element.innerHTML.split(' ');
while (element.scrollHeight > element.offsetHeight) {
wordArray.pop();
element.innerHTML = wordArray.join(' ') + '...';
}
});
}
BONUS 💡
Why limiting ourselves to 3 lines when we can tweak that from HTML (let's say we have different sections of cards and we want each to have different line clampin' rules)
We can easily add 'lines-X' class to our element that is to be clamped. Then we need some more SCSS (I restricted the number of lines from 1 to 6 and applied this to all the headings for my project' purposes):
$heading-font-sizes: (h1: $h1-font-size, h2: $h2-font-size, h3: $h3-font-size, h4: $h4-font-size, h5: $h5-font-size, h6: $h6-font-size );
@for $lines from 1 to 6 {
h#{$lines} {
$headingFontSize: map-get($heading-font-sizes, h#{$lines} );
@for $lines from 1 to 6 {
&.ellipsize-element.lines-#{$lines} {
@include limitTextToLineNumbersMixin( $headingFontSize, 1.5, #{$lines})
}
}
}
}
Have a better approach 🤓? I'm all ears 👂. Happy coding guys and gals 🙌
Top comments (4)
You would expect that CSS would have a solution for this by now. 😅
If you want pure CSS, I would use a linear gradient overlay as such:
The advantage here is that all the content is still there and you only need to apply a single CSS class.
You should totally add a live example of your code btw!
Good try (I like the effort you spent to make it CSS only) but has some cons to me.
P.S. Accepting your remark and will add a codepen demonstrating my approach. Thank you!
Love this article.
This will not work on japanese text, there is no spaces between words in japanese (and chinese, korean,...)