11

I know how to make a single div to put ellipsis after n number of lines using (where n is 2 lines in this case):

overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;

It works one one div but I have a different problem. I have a title and a description of some content, and I want to limit both fields to 3 lines at max by themselves, but also a total of 5 lines (instead of the maximum possible, 6 in that case) in total. In other words, I'd like to cut description after two lines (with an ellipsis) if the title is 3 lines.

How do I achieve this (preferably with no or smallest amount of Javascript)? I only need to support (mobile) Safari for now.

Can Poyrazoğlu
  • 33,241
  • 48
  • 191
  • 389

3 Answers3

2

How about comparing the clientHeight of each text area and use a simple. conditional statement like this..

var title = document.querySelector(".box h3"),
des = document.querySelector(".box p");
console.log("titleHeight = " + title.clientHeight + "px");
console.log("descriptionHeight = " + des.clientHeight + "px");
if (title.clientHeight > 90 && des.clientHeight > 90){
  title.style.webkitLineClamp = 3;
  des.style.webkitLineClamp = 2;
}else{
  title.style.webkitLineClamp = 3;
  des.style.webkitLineClamp = 3;
}
.box h3 {
  display: -webkit-box;
  -webkit-line-clamp: inherit;
  -webkit-box-orient: vertical;  
  overflow: hidden;
}

.box p {
  display: -webkit-box;
  -webkit-line-clamp: inherit;
  -webkit-box-orient: vertical;  
  overflow: hidden;
}

.box h3 {
   line-height: 30px;
 }
 .box p {
   line-height: 30px;
 }
<div class="box">
  <h3>Hey, don't cut me off like that. I want to speak my mind and don't appreciate being put into a box. Hey, don't cut me off like that. I want to speak my mind and don't appreciate being put into a box.</h3>
  <p>Hey, don't cut me off like that. I want to speak my mind and don't appreciate being put into a box. Hey, don't cut me off like that. I want to speak my mind and don't appreciate being put into a box.</p>
</div>
norcal johnny
  • 2,050
  • 2
  • 13
  • 17
  • That's the _last_ way that I want to go. There will be many factors that will affect the actual height of the bounding boxes so that I can't hardcode a height in advance. But I like the approach and might go this way if I can't find any other. – Can Poyrazoğlu Jun 13 '21 at 14:22
  • the only thing it is basing it on is the font size(line-height) which shouldn't be a problem. Ultimately you could even use 3 * line-height. – norcal johnny Jun 13 '21 at 18:38
2

getClientRects can return the line length for an inline element.

const { length } = document.querySelector("h1 span").getClientRects();
length >= 3 && document.querySelector("p").style.setProperty("--line-clamp", 2);
div > * {
  --line-clamp: 3;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: var(--line-clamp);
  -webkit-box-orient: vertical;
}
<div>
  <h1><span>Lorem ipsum dolor sit amet consectetur adipisicing elit. Natus repellendus ducimus minus met consectetur</span></h1>
  <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Animi consectetur quo, perspiciatis, pariatur, deleniti enim molestiae sunt debitis aut nam iure cumque sint aperiam est! Vel temporibus atque excepturi sed!</p>
</div>
sol
  • 22,311
  • 6
  • 42
  • 59
  • 1
    okay, this works. my element wasn't inline (it was a div) and it was always returning 1 (makes sense, as there is only one "box"). changed it to span and it now works perfectly. even though this answer involves JS i think this is the cleanest solution that achieves what i want. – Can Poyrazoğlu Jun 18 '21 at 14:00
2

With some flexbox, max-height, and a trick to place ellipsis, you could achieve this with pure CSS.

Screenshot:

Screenshot from code

See it at Codepen.

:root {
  --field-max-lines: 3;
  --desc-max-lines: 2; /* if title reached maximum number of lines */
  --title-lh: 30px;
  --desc-lh: 20px;
  font-size: 16px;
}

* {
  margin: 0;
  padding: 0;
}

body {
  display: flex;
  gap: 20px;
  padding: 20px;
}

div {
  display: flex;
  flex-direction: column;
  max-height: calc(var(--field-max-lines) * var(--title-lh) + var(--desc-max-lines) * var(--desc-lh));
  width: 200px;
}

div>* {
  overflow: hidden;
  position: relative;
  padding-right: 1rem;
}

div>*::before {
  position: absolute;
  content: "...";
  bottom: 0;
  right: 0;
}

div>*::after {
  position: absolute;
  content: "";
  right: 0;
  width: 1rem;
  height: 1.5rem;
}

strong {
  flex: none;
  line-height: var(--title-lh);
  max-height: calc(var(--field-max-lines) * var(--title-lh));
  font-size: 20px;
}

strong,
strong::after {
  background: red;
}

p {
  line-height: var(--desc-lh);
  max-height: calc(var(--field-max-lines) * var(--desc-lh));
}

p,
p::after {
  background: yellow;
}
<div>
  <strong>This title has 2 lines. This title has 2 lines.</strong>
  <p>This description has 4 lines. This description has 4 lines. This description has 4 lines. This description has 4 lines.</p>
</div>

<div>
  <strong>This title has 3 lines. This title has 3 lines. This title has 3 lines.</strong>
  <p>This description has 2 lines. This description has 2 lines.</p>
</div>

<div>
  <strong>This title has 3 lines. This title has 3 lines. This title has 3 lines.</strong>
  <p>This description has 3 lines. This description has 3 lines. This description has 3 lines.</p>
</div>

<div>
  <strong>This title has 4 lines. This title has 4 lines. This title has 4 lines. This title has 4 lines. This title has 4 lines.</strong>
  <p>This description has 3 lines. This description has 3 lines. This description has 3 lines.</p>
</div>
Felipe Saldanha
  • 1,087
  • 8
  • 17
  • 1
    This looks nice, but a minor annoyance: the ellipsis is always at the rightmost end of the div that is truncated, not necessarily where the text actually ends. so if I had a line that has some word, and after that another word which is a single long word therefore the text is truncated, that line abruptly ends, say in the middle, whereas the ellipsis is at the edge of the div regardless, creating some weird gap. – Can Poyrazoğlu Jun 18 '21 at 10:40