Reputation: 161
My target is:
The problem begins when I add text-align: right;
to the style: 3 dots behave differently than without the text-align
style property: in general, 3 dots are outside the text container (grey color).
Compare "good" vs "bad" styles; The only difference: "good" doesn't contain text-align: right;
style property. Try to play with font-size in those styles and you will see that for the "good" style 3 dots are always inside the text container (grey background) while for the "bad" style 3 dots' position is unexpected (could be inside the container, or partly inside, or fully outside)
So, is there any chance to have a 3 dots behavior like for the "good" style, but at the same time have text aligned right? Take into account the line number limit.
* {
box-sizing: border-box;
}
body {
height: 100vh;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
background: #78b9f3;
margin:0;
font-family: "Arial";
}
.wrapper {
display: flex;
justify-content: center;
}
.card {
background: #fff;
box-shadow: 0 4px 24px 3px rgb(0 0 0 / 10%);
padding: 20px;
margin: 20px;
width: 200px;
height: auto;
border-radius: 6px;
}
p {
font-size: 1em;
line-height: 1.3em;
margin:0;
}
h2 {
font-size: 1.5em;
margin: 0 0 0.5em 0;
}
.good {
font-size: 20px;
background-color: grey;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical;
}
.bad {
font-size: 20px;
text-align: right;
background-color: grey;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical;
}
<section class="wrapper">
<div class="card">
<h2>Good</h2>
<p class="good">Hello, I'm a very long text for at least three lines!</p>
</div>
<div class="card">
<h2>Bad</h2>
<p class="bad">Hello, I'm a very long text for at least three lines!</p>
</div>
</section>
Upvotes: 16
Views: 5200
Reputation: 697
Now seems like the issue is only reproducible in Chrome...
Firefox and Safari properly render the ...
after the multiline clamped text, even with text-align: right
.
Only Chrome renders the ellipsis outside of the containing element in some weird "absolutely positioned" way.
padding-right: 1em
on clamped text element:p {
width: 300px;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;
text-align: right;
padding-right: 1em;
}
<p>
In this example the <code>-webkit-line-clamp</code> property is set to
<code>3</code>, which means the text is clamped after three lines. An ellipsis
will be shown at the point where the text is clamped.
</p>
Upvotes: 0
Reputation: 3965
As mentioned chromium based browsers do not implement text-overflow: ellipsis;
in conjunction with text-align: right;
as intended, so a JavaScript solution is unavoidable.
This answer works, if the paragraphs do not contain HTML, but text only – as given in your example – and possible occurring space characters are known (see getLinebreakPosis
below). Yet in this example, it seems only the average space character occurs.
Also things become tricky, if you're dealing with very long words, then you need to add a hyphenation library, too.
function exceedsHeight(element, height) {
return parseFloat(getComputedStyle(element).height) > height
}
function refillParagraph(paragraph, maxHeight=42, endingString=' ...') {
// If text overflows maxHeight, cut it off and add an endingString.
// If paragraph is not overflowing, do nothing and abort:
if( ! exceedsHeight(paragraph, maxHeight) ) return
// Otherwise store text and remove it of paragraph:
const text = paragraph.textContent.trim()
paragraph.textContent = ''
// Refill paragraph character by character, plus the endingString:
for(let i=0; i < text.length; i++) {
paragraph.textContent = text.slice(0, i) + endingString
// Paragraph overflows:
if(exceedsHeight(paragraph, maxHeight)) {
// Remove last character and get breaking points:
let posis = getLinebreakPosis( text.slice(0, i-1) )
// Fill paragraph with text until last found breaking point,
// plus the endingString:
for(let j=0; j < posis.length; j++) {
paragraph.textContent = text.slice(0, posis[j]) + endingString
// No overflow, found breaking point, break posis-loop:
if( ! exceedsHeight(paragraph, maxHeight) ) break
}
// We're done, break the for-each-character-of-text-loop:
break
}
}
}
function getLinebreakPosis(text) {
// Return array with all positions where a space occurs in the text.
// Sort by last found first.
const posis = []
const spaceChars = [' ', '\n', '\t'] // and probably some more
let i = text.length
while(i > 0) {
i--
if(spaceChars.includes(text[i])) {
posis.push(i)
}
}
return posis
}
// For every found paragraph, execute refillParagraph:
document.addEventListener('DOMContentLoaded', eve => {
document.querySelectorAll('p').forEach(p => refillParagraph(p) )
});
p {
width: 200px;
text-align: right;
}
<article>
<h2>Ellipse all the browsers</h2>
<p>
This is a paragraph with a decent amount of text in it, for illustration purposes.
</p>
<p>
This is another paragraph which could be filled with ancient latin texts, just to exclude the most of us.
</p>
</article>
Upvotes: 1
Reputation: 43
I have added direction rtl to bad class and the dots have flipped which is what you require.
Also added overflow hidden to hide rest of the text. Hope this will help you.
Upvotes: -2
Reputation: 21
I just found a trick way to fix the above issue:
Hope this way help you temporarily fix the issue.
See example below:
* {
box-sizing: border-box;
}
body {
height: 100vh;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
background: #78b9f3;
margin:0;
font-family: "Arial";
}
.wrapper {
display: flex;
justify-content: center;
}
.card {
background: #fff;
box-shadow: 0 4px 24px 3px rgb(0 0 0 / 10%);
padding: 20px;
margin: 20px;
width: 200px;
height: auto;
border-radius: 6px;
}
p {
font-size: 1em;
line-height: 1.3em;
margin:0;
}
h2 {
font-size: 1.5em;
margin: 0 0 0.5em 0;
}
.good {
font-size: 20px;
background-color: grey;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical;
text-align: right;
padding-right: 20px; //added code
}
.bad {
font-size: 20px;
text-align: right;
background-color: grey;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical;
}
<section class="wrapper">
<div class="card">
<h2>Good</h2>
<p class="good">Hello, I'm a very long text for at least three lines!</p>
</div>
<div class="card">
<h2>Bad</h2>
<p class="bad">Hello, I'm a very long text for at least three lines!</p>
</div>
</section>
Upvotes: 2
Reputation: 5281
Demo: Last June I created a small tutorial comparing horizontal ellipsis and vertical line clamping on Codepen, including responsive sizing and spacing and some sliders you can toy with. The inline JS in the demo is only used to control the custom variables and is irrelevant to your issue. I added text-align
radios for your purpose.
Solution: Comparing my code against yours I think you simply need to change your text-overflow: ellipsis;
(used in both 'good' or 'bad') into overflow: hidden
, set your text-align
as required and you're good to go.
The value of the direction
property is only relevant for the value of text-align
. Something like:
body[dir="ltr"] p { text-align: right }
body[dir="rtl"] p { text-align: left }
But that is fairly common practice for html documents and doesn't seem to be the issue here.
The below snippet shows the bare CSS needed to get you up and running using custom attribute line-clamp
you can use for any element that needs line clamping.
Let me know in the comments if your need a more elaborate explanation.
[line-clamp] {
/* Alternative character not supported
by Edge/Chrome and line-clamp */
/* All [MANDATORY] for vertical line clamp */
width: 100%;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
.test {
text-align: right
}
<p class="test" line-clamp>Lorem Ipsum is simply some dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not
only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software
like Aldus PageMaker including versions of Lorem Ipsum.
</p>
Upvotes: 2
Reputation: 17115
Just take a look at the compatibility table on mdn – apart from firefox, browser support is rather spotty (to put it mildly).
However, you could fix this rendering issue with some javaScript.
... or you could also mimic text-overflow
an line-clamp
properties with some old school overflow and line height properties.
This hack is based on defining some line-height
related classes.
Css variables help to facilitate the calculations:
:root {
--overflowLineHeight: 1.25em;
--overflowColor1: rgba(255, 255, 255, 1);
--overflowColor2: rgba(255, 255, 255, 0);
}
.maxLines2 {
max-height: calc(var(--overflowLineHeight) * 2);
}
The actual overflow indicator (ellipsis) element is just an absolutely positioned pseudo element with a background gradient (placed in a relatively positioned parent element).
* {
box-sizing: border-box;
}
body {
height: 100vh;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
background: #78b9f3;
margin: 0;
font-family: "Arial";
}
.wrapper {
display: flex;
justify-content: center;
padding:1em;
}
.card {
background: #fff;
box-shadow: 0 4px 24px 3px rgb(0 0 0 / 10%);
padding: 1em;
margin: 1em;
width: 33%;
height: auto;
border-radius: 6px;
resize: both;
overflow: hidden;
}
p {
font-size: 1em;
line-height: 1.3em;
margin: 0;
}
h2 {
font-size: 1.5em;
margin: 0 0 0.5em 0;
}
:root {
--overflowLineHeight: 1.25em;
--overflowColor1: rgba(255, 255, 255, 1);
--overflowColor2: rgba(255, 255, 255, 0);
}
.overflow {
font-size: 20px;
line-height: var(--overflowLineHeight);
text-align: right;
overflow: hidden;
position: relative;
}
.overflow:after {
content: " …";
position: absolute;
bottom: 0;
right: 0;
display: block;
z-index: 1;
background-image: linear-gradient( 90deg, var(--overflowColor2), var(--overflowColor1) 50%);
width: 2.5em;
}
.maxLines2 {
max-height: calc(var(--overflowLineHeight) * 2);
}
.maxLines3 {
max-height: calc(var(--overflowLineHeight) * 3);
}
.maxLines4 {
max-height: calc(var(--overflowLineHeight) * 4);
}
<section class="wrapper">
<div class="card">
<h2>Fix: 2 lines</h2>
<p class=" maxLines2 overflow">Hello, I'm a very long text1 for at least three lines! Hello, I'm a very long text2 for at least three lines!</p>
</div>
<div class="card">
<h2>Fix: 3 lines</h2>
<p class=" maxLines3 overflow">Hello, I'm a very long text1 for at least three lines! Hello, I'm a very long text2 for at least three lines!</p>
</div>
<div class="card">
<h2>Fix: 4 lines</h2>
<p class=" maxLines4 overflow">Hello, I'm a very long text1 for at least three lines! Hello, I'm a very long text2 for at least three lines!</p>
</div>
</section>
line-clamp
This hack is based on the fact word-break: break-all
will render the ellipsis within the block boundaries.
Unfortunately, this will result in ugly word breaks.
To fix this issue,
<span>
elements.word-break: break-word
propertylet overflows = document.querySelectorAll(".overflow");
fixOverflow(overflows);
function fixOverflow(overflows) {
overflows.forEach(function(text, i) {
//split textContent into array
let words = text.innerHTML
.split(" ")
.map((w) => {
return w.trim();
})
.filter(Boolean);
//delete current textContent
let wrapped = "";
text.textContent = "";
text.style.setProperty("word-break", "break-all");
let bbText = text.getBoundingClientRect();
let bottomText = bbText.y + bbText.height;
//get line height by checking the first word's height
let span0 = document.createElement("span");
span0.textContent = words[0] + " ";
span0.classList.add("wordWrp");
text.appendChild(span0);
let height0 = span0.getBoundingClientRect().height;
//check max lines and init counter
let style = window.getComputedStyle(text);
let maxLines = parseFloat(style.webkitLineClamp);
let breaks = 0;
//wrap words in spans
for (let i = 1; i < words.length; i++) {
let word = words[i];
let span = document.createElement("span");
span.textContent = word + " ";
span.classList.add("wordWrp");
text.appendChild(span);
let bbSpan = span.getBoundingClientRect();
let heightSpan = bbSpan.height;
let bottomSpan = bbSpan.y + bbSpan.height;
if (heightSpan > height0 && breaks < maxLines - 1 && bottomSpan < bottomText) {
span.classList.add("wordWrpLine");
breaks++;
}
}
});
}
//update on resize
const resizeObserver = new ResizeObserver(() => {
upDateOverflows();
});
overflows.forEach(function(text, i) {
resizeObserver.observe(text);
});
function upDateOverflows() {
overflows.forEach(function(text, i) {
let wordWraps = text.querySelectorAll(".wordWrp");
let bbText = text.getBoundingClientRect();
let bottom = bbText.y + bbText.height;
let height0 = wordWraps[0].getBoundingClientRect().height;
//check max lines and init counter
let style = window.getComputedStyle(text);
let maxLines = parseFloat(style.webkitLineClamp);
let breaks = 0;
for (let i = 1; i < wordWraps.length; i++) {
let wordWrap = wordWraps[i];
wordWrap.classList.remove("wordWrpLine");
let bb = wordWrap.getBoundingClientRect();
let height = bb.height;
let bottomSpan = bb.y + bb.height;
if (height > height0 && breaks < maxLines - 1 && bottomSpan < bottom) {
wordWrap.classList.add("wordWrpLine");
breaks++;
}
}
});
}
* {
box-sizing: border-box;
}
body {
height: 100vh;
width: 100%;
background: #78b9f3;
margin: 0;
font-family: "Arial";
}
.wrapper {
display: flex;
justify-content: center;
align-items: center;
}
.card {
background: #fff;
box-shadow: 0 4px 24px 3px rgb(0 0 0 / 10%);
padding: 20px;
margin: 20px;
width: 250px;
height: auto;
border-radius: 6px;
resize: both;
overflow: hidden;
}
p {
font-size: 1em;
line-height: 1.3em;
margin: 0;
}
h2 {
font-size: 1.5em;
margin: 0 0 0.5em 0;
}
.overflow {
font-size: 20px;
text-align: right;
background-color: grey;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical;
}
.overflow:hover .wordWrp {
outline: 1px solid red;
}
.maxLines2 {
-webkit-line-clamp: 2;
line-clamp: 2;
}
.maxLines3 {
-webkit-line-clamp: 3;
line-clamp: 3;
}
.maxLines4 {
-webkit-line-clamp: 4;
line-clamp: 4;
}
.wordWrpLine {
word-break: break-word;
}
.wordWrpLine2 {
background: red;
}
<h2>Resize cards</h2>
<section class="wrapper">
<div class="card">
<h2>Fix: 2 lines</h2>
<p class=" maxLines2 overflow">Hello, I'm a very long text1 for at least three lines! Hello, I'm a very long text2 for at least three lines!</p>
</div>
<div class="card">
<h2>Fix: 3 lines</h2>
<p class=" maxLines3 overflow">Hello, I'm a very long text1 for at least three lines! Hello, I'm a very long text2 for at least three lines!</p>
</div>
<div class="card">
<h2>Fix: 4 lines</h2>
<p class=" maxLines4 overflow">Hello, I'm a very long text1 for at least three lines! Hello, I'm a very long text2 for at least three lines!</p>
</div>
</section>
Pretty similar to the previous js approach – by means of splitting the element's text into span elements.
This time we're completely replacing the css elllipsis placeholder by appending a custom <span>
element.
The overflow "ellipsis" placeholder is placed according to some boundig box checks: the first span element leaving the overflow defined boundaries will be the position/index for prepending the ellipsis span.
let overflows = document.querySelectorAll(".overflow");
fixOverflow(overflows);
function fixOverflow(overflows) {
overflows.forEach(function(text) {
let spanWrps = text.querySelectorAll(".wordWrp");
let words = '';
let hasSpans = spanWrps.length ? true : false;
let spanEllipse = text.querySelector(".spanEllipse");
//create ellpse san if not already present
if (!spanEllipse) {
spanEllipse = document.createElement("span");
spanEllipse.classList.add('spanEllipse');
spanEllipse.textContent = ' …';
}
// get word/string array - unless it's aleady generated
if (hasSpans) {
words = [...spanWrps].map((word) => {
return word.textContent
});
} else {
//split textContent into array
words = text.innerHTML
.split(" ")
.map((w) => {
return w.trim();
})
.filter(Boolean);
}
let bbText = text.getBoundingClientRect();
let bottomText = bbText.y + bbText.height;
//delete current textContent
if (!hasSpans) {
text.textContent = "";
}
for (let i = 0; i < words.length; i++) {
let word = words[i];
//wrap words in spans if not already done
let span = '';
if (hasSpans) {
span = spanWrps[i];
span.classList.remove('wordWrpOverflow');
} else {
span = document.createElement("span");
span.textContent = word + " ";
text.appendChild(span);
span.classList.add("wordWrp");
}
let bbSpan = span.getBoundingClientRect();
let bottomSpan = bbSpan.y + bbSpan.height;
if (bottomSpan > bottomText) {
span.classList.add("wordWrpOverflow");
} else {
span.classList.remove("wordWrpOverflow");
}
}
let firstOverFlow = text.querySelector('.wordWrpOverflow');
if (firstOverFlow) {
let bbE = spanEllipse.getBoundingClientRect();
let bottomE = bbE.y + bbE.height;
let bbPrev = firstOverFlow.previousElementSibling.getBoundingClientRect();
let bottomPrev = bbPrev.y + bbPrev.height;
//add ellipsis before first overflow element
if (bottomE > bottomText && bottomPrev < bottomText) {
firstOverFlow.parentNode.insertBefore(spanEllipse, firstOverFlow.previousElementSibling);
} else {
// ellipsis might be in overflow area - traverse backwards
if (bottomPrev > bottomText) {
firstOverFlow.parentNode.insertBefore(spanEllipse, firstOverFlow.previousElementSibling.previousElementSibling);
} else {
firstOverFlow.parentNode.insertBefore(spanEllipse, firstOverFlow);
}
}
}
// no ellipsis neede - remove it!
else {
spanEllipse.remove();
}
});
}
//update on resize
const resizeObserver = new ResizeObserver(() => {
fixOverflow(overflows)
});
overflows.forEach(function(text, i) {
resizeObserver.observe(text);
});
* {
box-sizing: border-box;
}
body {
height: 100vh;
width: 100%;
background: #78b9f3;
margin: 0;
font-family: "Arial";
}
.card {
background: #fff;
padding: 20px;
margin: 20px;
height: auto;
border-radius: 6px;
resize: both;
overflow: auto;
}
p {
font-size: 1em;
line-height: 1.3em;
margin: 0;
}
h2 {
font-size: 1.5em;
margin: 0 0 0.5em 0;
}
:root {
--lineHeight: 1.2em;
}
.overflow {
font-size: 20px;
line-height: var(--lineHeight);
text-align: right;
overflow: hidden;
}
.maxLines2 {
max-height: calc(2 * var(--lineHeight));
}
.maxLines3 {
max-height: calc(3 * var(--lineHeight));
}
.maxLines4 {
max-height: calc(4 * var(--lineHeight));
}
.wordWrpOverflow {
visibility: hidden;
}
/* force line break */
.spanEllipse+span {
display: block
}
.txt-cnt * {
text-align: center;
}
@media (min-width:720px) {
.card {
width: 33%;
}
.wrapper {
display: flex;
justify-content: center;
}
}
@media (min-width:1024px) {
.card {
width: 250px;
}
}
<section class="wrapper">
<div class="card">
<h2>Fix: 2 lines</h2>
<p class=" maxLines2 overflow">Hello, I'm a very long text1 for at least three lines! Hello, I'm a very long text2 for at least three lines!</p>
</div>
<div class="card">
<h2>Fix: 3 lines</h2>
<p class=" maxLines3 overflow">Hello, I'm a very long text1 for at least three lines! Hello, I'm a very long text2 for at least three lines!</p>
</div>
<div class="card txt-cnt">
<h2>Fix: 4 lines: <br />text-align:center</h2>
<p class=" maxLines4 overflow">Hello, I'm a very long text1 for at least three lines! Hello, I'm a very long text2 for at least three lines!</p>
</div>
</section>
Currently only firefox and some iOS safari versions seem to render ellipsis correctly.
To avoid unnecessary js processing for these browser you could include a feature detection:
let firefoxOverflow = CSS.supports("text-overflow", "ellipsis ellipsis");
let safariWebkit = CSS.supports("-webkit-hyphens", "none");
let needsWorkaround = false;
if(!firefoxOverflow && !safariWebkit) {
needsWorkaround = true;
document.body.classList.add("needs-overflow-fix");
}
This will certainly not work for all firefox an safari versions.
At least it doesn't use any browser sniffing.
/**
* check proper overflow support
**/
let supportText = "";
let firefoxOverflow = CSS.supports("text-overflow", "ellipsis ellipsis");
let safariWebkit = CSS.supports("-webkit-hyphens", "none");
let needsWorkaround = false;
if (!firefoxOverflow && !safariWebkit) {
needsWorkaround = true;
document.body.classList.add("needs-overflow-fix");
}
// just for display
if (needsWorkaround) {
supportText = "needs workaround - use js";
} else {
supportText = "proper support – use css";
}
support.textContent = supportText;
/**
* apply workaround if necessary
**/
if (needsWorkaround) {
let overflows = document.querySelectorAll(".overflow");
fixOverflow(overflows);
function fixOverflow(overflows) {
overflows.forEach(function (text) {
/*
let style = window.getComputedStyle(text);
let styleClamp = parseFloat(style.getPropertyValue("-webkit-line-clamp"));
styleClamp = !styleClamp
? parseFloat(style.getPropertyValue("line-clamp"))
: styleClamp;
//console.log(style)
console.log("clamp", styleClamp);
if (styleClamp > 0) {
//text.classList.add('maxLines'+styleClamp);
}
*/
let spanWrps = text.querySelectorAll(".wordWrp");
let words = "";
let hasSpans = spanWrps.length ? true : false;
let spanEllipse = text.querySelector(".spanEllipse");
//create ellpse san if not already present
if (!spanEllipse) {
spanEllipse = document.createElement("span");
spanEllipse.classList.add("spanEllipse");
spanEllipse.textContent = " …";
}
// get word/string array - unless it's aleady generated
if (hasSpans) {
words = [...spanWrps].map((word) => {
return word.textContent;
});
} else {
//split textContent into array
words = text.innerHTML
.split(" ")
.map((w) => {
return w.trim();
})
.filter(Boolean);
}
let bbText = text.getBoundingClientRect();
let bottomText = bbText.y + bbText.height;
//delete current textContent
if (!hasSpans) {
text.textContent = "";
}
for (let i = 0; i < words.length; i++) {
let word = words[i];
//wrap words in spans if not already done
let span = "";
if (hasSpans) {
span = spanWrps[i];
span.classList.remove("wordWrpOverflow");
} else {
span = document.createElement("span");
span.textContent = word + " ";
text.appendChild(span);
span.classList.add("wordWrp");
}
let bbSpan = span.getBoundingClientRect();
let bottomSpan = bbSpan.y + bbSpan.height;
if (bottomSpan > bottomText) {
span.classList.add("wordWrpOverflow");
} else {
span.classList.remove("wordWrpOverflow");
}
}
let firstOverFlow = text.querySelector(".wordWrpOverflow");
if (firstOverFlow) {
let bbE = spanEllipse.getBoundingClientRect();
let bottomE = bbE.y + bbE.height;
let bbPrev = firstOverFlow.previousElementSibling.getBoundingClientRect();
let bottomPrev = bbPrev.y + bbPrev.height;
//add ellipsis before first overflow element
if (bottomE > bottomText && bottomPrev < bottomText) {
firstOverFlow.parentNode.insertBefore(
spanEllipse,
firstOverFlow.previousElementSibling
);
} else {
// ellipsis might be in overflow area - traverse backwards
if (bottomPrev > bottomText) {
firstOverFlow.parentNode.insertBefore(
spanEllipse,
firstOverFlow.previousElementSibling.previousElementSibling
);
} else {
firstOverFlow.parentNode.insertBefore(spanEllipse, firstOverFlow);
}
}
}
// no ellipsis neede - remove it!
else {
spanEllipse.remove();
}
});
}
//update on resize
const resizeObserver = new ResizeObserver(() => {
fixOverflow(overflows);
});
overflows.forEach(function (text, i) {
resizeObserver.observe(text);
});
}
* {
box-sizing: border-box;
}
body {
height: 100vh;
width: 100%;
background: #78b9f3;
margin: 0;
font-family: "Arial";
}
.needs-overflow-fix {
background: orange;
}
.card {
background: #fff;
padding: 20px;
margin: 20px;
height: auto;
border-radius: 6px;
resize: both;
overflow: auto;
}
p {
font-size: 1em;
line-height: 1.3em;
margin: 0;
}
h2 {
font-size: 1.5em;
margin: 0 0 0.5em 0;
}
:root {
--lineHeight: 1.2em;
}
.overflow {
font-size: 20px;
line-height: var(--lineHeight);
text-align: right;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical;
}
.needs-overflow-fix .overflow {
text-overflow: unset;
overflow: hidden;
display: block;
-webkit-line-clamp: unset !important;
line-clamp: unset !important;
-webkit-box-orient: unset !important;
}
.maxLines2 {
-webkit-line-clamp: 2;
line-clamp: 2;
}
.maxLines3 {
-webkit-line-clamp: 3;
line-clamp: 3;
}
.maxLines4 {
-webkit-line-clamp: 4;
line-clamp: 4;
}
.needs-overflow-fix .maxLines2 {
max-height: calc(2 * var(--lineHeight));
}
.needs-overflow-fix .maxLines3 {
max-height: calc(3 * var(--lineHeight));
}
.needs-overflow-fix .maxLines4 {
max-height: calc(4 * var(--lineHeight));
}
.wordWrpOverflow {
visibility: hidden;
}
/* force line break */
.spanEllipse + span {
display: block;
}
.txt-cnt * {
text-align: center;
}
@media (min-width: 720px) {
.card {
width: 33%;
}
.wrapper {
display: flex;
justify-content: center;
}
}
@media (min-width: 1024px) {
.card {
width: 250px;
}
}
<p style="text-align:center"><strong id="support" > </strong></p>
<section class="wrapper">
<div class="card">
<h2>Fix: 2 lines</h2>
<p class=" maxLines2 overflow">Hello, I'm a very long text1 for at least three lines! Hello, I'm a very long text2 for at least three lines!</p>
</div>
<div class="card">
<h2>Fix: 3 lines</h2>
<p class=" maxLines3 overflow">Hello, I'm a very long text1 for at least three lines! Hello, I'm a very long text2 for at least three lines!</p>
</div>
<div class="card txt-cnt">
<h2>Fix: 4 lines: <br />text-align:center</h2>
<p class="maxLines4 overflow">Hello, I'm a very long text1 for at least three lines! Hello, I'm a very long text2 for at least three lines! Hello, I'm a very long text2 for at least three lines!</p>
</div>
</section>
If the background color changes from blue to orange – js fix is applied.
Upvotes: 2
Reputation: 2321
direction: rtl;
.text-align:right
so dots will also appear on right as per expected behavior.* {
box-sizing: border-box;
}
body {
height: 100vh;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
background: #78b9f3;
margin: 0;
font-family: "Arial";
}
.wrapper {
display: flex;
justify-content: center;
}
.card {
background: #fff;
box-shadow: 0 4px 24px 3px rgb(0 0 0 / 10%);
padding: 20px;
margin: 20px;
width: 200px;
height: auto;
border-radius: 6px;
}
p {
font-size: 1em;
line-height: 1.3em;
margin: 0;
}
h2 {
font-size: 1.5em;
margin: 0 0 0.5em 0;
}
.good {
font-size: 20px;
background-color: grey;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical;
}
.bad {
font-size: 20px;
text-align: right;
background-color: grey;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical;
direction: rtl;
}
<h1> IN that case to bring ... to right you have to set <em>direction: rtl;</em></h1>
<section class="wrapper">
<div class="card">
<h2>Good</h2>
<p class="good">Hello, I'm a very long text for at least three lines!</p>
</div>
<div class="card">
<h2>Bad</h2>
<p class="bad">Hello, I'm a very long text for at least three lines!</p>
</div>
</section>
Upvotes: -2