</header>
<main>
- <p>Here's the CSS required to make a paragraph truncate with an ellipsis after a specific number of lines
- (the vendor prefixes are required):</p>
- <pre>
+ <section>
+ <h2>Fixed number of lines</h2>
+ <p>Here's the CSS required to make a paragraph truncate with an ellipsis after a specific number of lines
+ (the vendor prefixes are required):</p>
+ <pre>
.line-clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 5;
overflow: hidden;
}</pre>
- <p>Here is the above CSS in action. Try adjusting the paragraph's width:</p>
- <p class="line-clamp width-resizable">
- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore
- magna aliqua. Dolor sit amet consectetur adipiscing elit duis tristique sollicitudin. Suscipit adipiscing bibendum
- est ultricies integer quis auctor. Odio facilisis mauris sit amet massa vitae tortor condimentum lacinia. Nam
- libero justo laoreet sit amet cursus sit amet. Nisl vel pretium lectus quam id. Proin nibh nisl condimentum id.
- Sagittis vitae et leo duis ut diam quam nulla. Sed cras ornare arcu dui vivamus arcu felis. Vulputate ut pharetra
- sit amet aliquam id diam. Id neque aliquam vestibulum morbi. Tellus at urna condimentum mattis. Non enim praesent
- elementum facilisis leo vel. Turpis massa tincidunt dui ut. Risus quis varius quam quisque id. Amet purus gravida
- quis blandit. Felis eget velit aliquet sagittis id consectetur purus ut. Quis commodo odio aenean sed adipiscing.
- Pellentesque elit eget gravida cum sociis natoque penatibus et magnis. Facilisis leo vel fringilla est ullamcorper
- eget nulla. Montes nascetur ridiculus mus mauris. Nunc sed augue lacus viverra vitae congue. Morbi non arcu risus
- quis varius quam quisque id. Adipiscing tristique risus nec feugiat in fermentum posuere urna nec. Elit
- ullamcorper dignissim cras tincidunt lobortis feugiat vivamus.
- </p>
- <p>You can also use a CSS variable and some JavaScript to dynamically set the <code>-webkit-line-clamp</code>
- property based on the container's height. Using this CSS:
- </p>
- <pre>
+ <p>Here is the above CSS in action. Try adjusting the paragraph's width:</p>
+ <p class="line-clamp width-resizable">
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore
+ magna aliqua. Dolor sit amet consectetur adipiscing elit duis tristique sollicitudin. Suscipit adipiscing bibendum
+ est ultricies integer quis auctor. Odio facilisis mauris sit amet massa vitae tortor condimentum lacinia. Nam
+ libero justo laoreet sit amet cursus sit amet. Nisl vel pretium lectus quam id. Proin nibh nisl condimentum id.
+ Sagittis vitae et leo duis ut diam quam nulla. Sed cras ornare arcu dui vivamus arcu felis. Vulputate ut pharetra
+ sit amet aliquam id diam. Id neque aliquam vestibulum morbi. Tellus at urna condimentum mattis. Non enim praesent
+ elementum facilisis leo vel. Turpis massa tincidunt dui ut. Risus quis varius quam quisque id. Amet purus gravida
+ quis blandit. Felis eget velit aliquet sagittis id consectetur purus ut. Quis commodo odio aenean sed adipiscing.
+ Pellentesque elit eget gravida cum sociis natoque penatibus et magnis. Facilisis leo vel fringilla est ullamcorper
+ eget nulla. Montes nascetur ridiculus mus mauris. Nunc sed augue lacus viverra vitae congue. Morbi non arcu risus
+ quis varius quam quisque id. Adipiscing tristique risus nec feugiat in fermentum posuere urna nec. Elit
+ ullamcorper dignissim cras tincidunt lobortis feugiat vivamus.
+ </p>
+ </section>
+
+ <section>
+ <h2>Dynamic number of lines</h2>
+ <p>You can also use a CSS variable and some JavaScript to dynamically set the <code>-webkit-line-clamp</code>
+ property based on the container's height. Using this CSS:
+ </p>
+ <pre>
.dynamic-line-clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: var(--lines);
overflow: hidden;
}</pre>
- <p>And this JavaScript:</p>
- <pre>
+ <p>And this JavaScript:</p>
+ <pre>
function getLineHeightInPx(elem) {
const temp = document.createElement('div');
temp.textContent = '0';
const elem = document.querySelector('.dynamic-line-clamp');
new ResizeObserver(_ => elem.style.setProperty('--lines', Math.floor(elem.clientHeight / getLineHeightInPx(elem)))).observe(elem);</pre>
- <p>Try adjusting the height:</p>
- <div class="aside-container height-resizable-container">
- <p id="basic-observer" class="dynamic-line-clamp height-resizable">
- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore
- magna aliqua. Dolor sit amet consectetur adipiscing elit duis tristique sollicitudin. Suscipit adipiscing bibendum
- est ultricies integer quis auctor. Odio facilisis mauris sit amet massa vitae tortor condimentum lacinia. Nam
- libero justo laoreet sit amet cursus sit amet. Nisl vel pretium lectus quam id. Proin nibh nisl condimentum id.
- Sagittis vitae et leo duis ut diam quam nulla. Sed cras ornare arcu dui vivamus arcu felis. Vulputate ut pharetra
- sit amet aliquam id diam. Id neque aliquam vestibulum morbi. Tellus at urna condimentum mattis. Non enim praesent
- elementum facilisis leo vel. Turpis massa tincidunt dui ut. Risus quis varius quam quisque id. Amet purus gravida
- quis blandit. Felis eget velit aliquet sagittis id consectetur purus ut. Quis commodo odio aenean sed adipiscing.
- Pellentesque elit eget gravida cum sociis natoque penatibus et magnis. Facilisis leo vel fringilla est ullamcorper
- eget nulla. Montes nascetur ridiculus mus mauris. Nunc sed augue lacus viverra vitae congue. Morbi non arcu risus
- quis varius quam quisque id. Adipiscing tristique risus nec feugiat in fermentum posuere urna nec. Elit
- ullamcorper dignissim cras tincidunt lobortis feugiat vivamus.
+ <p>Try adjusting the height:</p>
+ <div class="aside-container height-resizable-container">
+ <p id="basic-observer" class="dynamic-line-clamp height-resizable">
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore
+ magna aliqua. Dolor sit amet consectetur adipiscing elit duis tristique sollicitudin. Suscipit adipiscing bibendum
+ est ultricies integer quis auctor. Odio facilisis mauris sit amet massa vitae tortor condimentum lacinia. Nam
+ libero justo laoreet sit amet cursus sit amet. Nisl vel pretium lectus quam id. Proin nibh nisl condimentum id.
+ Sagittis vitae et leo duis ut diam quam nulla. Sed cras ornare arcu dui vivamus arcu felis. Vulputate ut pharetra
+ sit amet aliquam id diam. Id neque aliquam vestibulum morbi. Tellus at urna condimentum mattis. Non enim praesent
+ elementum facilisis leo vel. Turpis massa tincidunt dui ut. Risus quis varius quam quisque id. Amet purus gravida
+ quis blandit. Felis eget velit aliquet sagittis id consectetur purus ut. Quis commodo odio aenean sed adipiscing.
+ Pellentesque elit eget gravida cum sociis natoque penatibus et magnis. Facilisis leo vel fringilla est ullamcorper
+ eget nulla. Montes nascetur ridiculus mus mauris. Nunc sed augue lacus viverra vitae congue. Morbi non arcu risus
+ quis varius quam quisque id. Adipiscing tristique risus nec feugiat in fermentum posuere urna nec. Elit
+ ullamcorper dignissim cras tincidunt lobortis feugiat vivamus.
+ </p>
+ <p class="aside">Note that <code>overflow: hidden</code> <strong>will only hide text that is outside</strong> the
+ container element. So if you resize the paragraph to cut through the middle of a line, the ellipsis will appear in
+ the line above it but the cut-off text will still be visible.
+ </p>
+ </div>
+ </section>
+
+ <section>
+ <h2>Dynamic number of lines: quality of life improvements</h2>
+ <p>
+ If your paragraph's height is dynamic, it's useful to add some JavaScript to snap the paragraph's <code>height</code> to
+ a multiple of its <code>line-height</code> whenever the paragraph is resized. To do so, update the event listener like so:
</p>
- <p class="aside">Note that <code>overflow: hidden</code> <strong>will only hide text that is outside</strong> the
- container element. So if you resize the paragraph to cut through the middle of a line, the ellipsis will appear in
- the line above it but the cut-off text will still be visible.
- </p>
- </div>
- <p>
- If your paragraph's height is dynamic, it's useful to add some JavaScript to snap the paragraph's <code>height</code> to
- a multiple of its <code>line-height</code> whenever the paragraph is resized. To do so, update the event listener like so:
- </p>
- <pre>
+ <pre>
new ResizeObserver(_ => {
const lineHeight = getLineHeightInPx(elem);
const lines = Math.floor(elem.clientHeight / lineHeight);
elem.style.setProperty('--lines', lines);
elem.style.setProperty('height', `${lines * lineHeight}px`);
}).observe(elem);</pre>
- <p>Lastly, it's best to debounce the event listener for better performance and to prevent the event listener from fighting with
- the user for control over the element's height while the user is resizing it. Using this basic debounce function:</p>
- <pre>
+ <p>Lastly, it's best to debounce the event listener for better performance and to prevent the event listener from fighting with
+ the user for control over the element's height while the user is resizing it. Using this basic debounce function:</p>
+ <pre>
function debounce(fn, wait) {
let timeoutId;
return () => {
timeoutId = setTimeout(fn, wait);
}
}</pre>
- <p>You can update the event listener to cancel if another event is fired within 200 milliseconds:</p>
- <pre>
-new ResizeObserver(debounce(() => {
- const lineHeight = getLineHeightInPx(elem);
- const lines = Math.floor(elem.clientHeight / lineHeight);
- elem.style.setProperty('--lines', lines);
- elem.style.setProperty('height', `${lines * lineHeight}px`);
-}, 200)).observe(elem);</pre>
- <p>The final combined JavaScript looks like this:</p>
- <pre>
+ <p>You can update the event listener to cancel if another event is fired within 200 milliseconds:</p>
+ <pre>
new ResizeObserver(debounce(() => {
const lineHeight = getLineHeightInPx(elem);
const lines = Math.floor(elem.clientHeight / lineHeight);
elem.style.setProperty('--lines', lines);
elem.style.setProperty('height', `${lines * lineHeight}px`);
}, 200)).observe(elem);</pre>
- <p>Here's the final combined JavaScript with all the bells and whistles:</p>
- <pre>
+ </section>
+
+ <section>
+ <h2>Full example</h2>
+ <p>And the final combined JavaScript with all the bells and whistles:</p>
+ <pre>
function debounce(fn, wait) {
let timeoutId;
return () => {
elem.style.setProperty('--lines', lines);
elem.style.setProperty('height', `${lines * lineHeight}px`);
}, 200)).observe(elem);</pre>
- <p>And here it is in action!</p>
- <div class="height-resizable-container">
- <p id="full-observer" class="dynamic-line-clamp both-resizable">
- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore
- magna aliqua. Dolor sit amet consectetur adipiscing elit duis tristique sollicitudin. Suscipit adipiscing bibendum
- est ultricies integer quis auctor. Odio facilisis mauris sit amet massa vitae tortor condimentum lacinia. Nam
- libero justo laoreet sit amet cursus sit amet. Nisl vel pretium lectus quam id. Proin nibh nisl condimentum id.
- Sagittis vitae et leo duis ut diam quam nulla. Sed cras ornare arcu dui vivamus arcu felis. Vulputate ut pharetra
- sit amet aliquam id diam. Id neque aliquam vestibulum morbi. Tellus at urna condimentum mattis. Non enim praesent
- elementum facilisis leo vel. Turpis massa tincidunt dui ut. Risus quis varius quam quisque id. Amet purus gravida
- quis blandit. Felis eget velit aliquet sagittis id consectetur purus ut. Quis commodo odio aenean sed adipiscing.
- Pellentesque elit eget gravida cum sociis natoque penatibus et magnis. Facilisis leo vel fringilla est ullamcorper
- eget nulla. Montes nascetur ridiculus mus mauris. Nunc sed augue lacus viverra vitae congue. Morbi non arcu risus
- quis varius quam quisque id. Adipiscing tristique risus nec feugiat in fermentum posuere urna nec. Elit
- ullamcorper dignissim cras tincidunt lobortis feugiat vivamus.
- </p>
- </div>
+ <p>And here it is in action!</p>
+ <div class="height-resizable-container">
+ <p id="full-observer" class="dynamic-line-clamp both-resizable">
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore
+ magna aliqua. Dolor sit amet consectetur adipiscing elit duis tristique sollicitudin. Suscipit adipiscing bibendum
+ est ultricies integer quis auctor. Odio facilisis mauris sit amet massa vitae tortor condimentum lacinia. Nam
+ libero justo laoreet sit amet cursus sit amet. Nisl vel pretium lectus quam id. Proin nibh nisl condimentum id.
+ Sagittis vitae et leo duis ut diam quam nulla. Sed cras ornare arcu dui vivamus arcu felis. Vulputate ut pharetra
+ sit amet aliquam id diam. Id neque aliquam vestibulum morbi. Tellus at urna condimentum mattis. Non enim praesent
+ elementum facilisis leo vel. Turpis massa tincidunt dui ut. Risus quis varius quam quisque id. Amet purus gravida
+ quis blandit. Felis eget velit aliquet sagittis id consectetur purus ut. Quis commodo odio aenean sed adipiscing.
+ Pellentesque elit eget gravida cum sociis natoque penatibus et magnis. Facilisis leo vel fringilla est ullamcorper
+ eget nulla. Montes nascetur ridiculus mus mauris. Nunc sed augue lacus viverra vitae congue. Morbi non arcu risus
+ quis varius quam quisque id. Adipiscing tristique risus nec feugiat in fermentum posuere urna nec. Elit
+ ullamcorper dignissim cras tincidunt lobortis feugiat vivamus.
+ </p>
+ </div>
+ </section>
</main>
<script type="module">