Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using it's URL and the proper URL extention.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <h1>
  <a href="https://dollarshaveclub.github.io/shave/" target="_blank">Shave</a>, A modern javascript plugin for truncating text within an html element.
</h1>
<h2>Time elapsed for <a href="https://dollarshaveclub.github.io/shave/" target="_blank">Shave</a> to truncate 50 elements: <span class="elapsed"></span></h2>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p><p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p><p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p><p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>
<p class="mh100">會全用民知多起功在有場館爾期臺多而不雄山選在場地市者電養說化運面遊聲時上教要下素的正一曾又如到性喜色體歷定部手里克業選陽響水起金園際吃權終麼意建本分香來象洋道方業動害有不財是了題此然把經會得善所建那各相標一來依正員由不古達解工面想推的</p>

              
            
!

CSS

              
                h1, 
h2,
p {
  margin: 1rem auto;
}
h1, 
h2 {
  max-width: 40rem;
  text-align: center;
}
p {
  max-width: 18.75rem;
  margin: 1rem auto;
}
              
            
!

JS

              
                /**
  shave - Shave is a javascript plugin that truncates multi-line text within a html element based on set max height
  @version v5.0.0
  @link https://github.com/yowainwright/shave#readme
  @author Jeff Wainwright <yowainwright@gmail.com> (jeffry.in)
  @license MIT
**/
(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
    typeof define === 'function' && define.amd ? define(factory) :
    (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.shave = factory());
})(this, (function () { 'use strict';

    /******************************************************************************
    Copyright (c) Microsoft Corporation.

    Permission to use, copy, modify, and/or distribute this software for any
    purpose with or without fee is hereby granted.

    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
    REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
    AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
    INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
    LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
    OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
    PERFORMANCE OF THIS SOFTWARE.
    ***************************************************************************** */

    function __read(o, n) {
        var m = typeof Symbol === "function" && o[Symbol.iterator];
        if (!m) return o;
        var i = m.call(o), r, ar = [], e;
        try {
            while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
        }
        catch (error) { e = { error: error }; }
        finally {
            try {
                if (r && !r.done && (m = i["return"])) m.call(i);
            }
            finally { if (e) throw e.error; }
        }
        return ar;
    }

    function __spreadArray(to, from, pack) {
        if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
            if (ar || !(i in from)) {
                if (!ar) ar = Array.prototype.slice.call(from, 0, i);
                ar[i] = from[i];
            }
        }
        return to.concat(ar || Array.prototype.slice.call(from));
    }

    function generateArrayOfNodes(target) {
        if (typeof target === 'string') {
            return __spreadArray([], __read(document.querySelectorAll(target)), false);
        }
        else if ('length' in target) {
            return __spreadArray([], __read(target), false);
        }
        else {
            return [target];
        }
    }
    function shave(target, maxHeight, opts) {
        if (opts === void 0) { opts = {}; }
        if (typeof maxHeight === 'undefined' || isNaN(maxHeight)) {
            throw Error('maxHeight is required');
        }
        var els = generateArrayOfNodes(target);
        if (!els.length) {
            return;
        }
        var _a = opts.character, character = _a === void 0 ? '…' : _a, _b = opts.classname, classname = _b === void 0 ? 'js-shave' : _b, _c = opts.spaces, initialSpaces = _c === void 0 ? true : _c, _d = opts.charclassname, charclassname = _d === void 0 ? 'js-shave-char' : _d, _e = opts.link, link = _e === void 0 ? {} : _e;
        /**
         * @notes
         * the initialSpaces + spaces variable definition below fixes
         * a previous bug where spaces being a boolean type wasn't clear
         * meaning people were using (a string, in example—which is truthy)
         * hence, doing it this way is a non-breaking change
         */
        var spaces = typeof initialSpaces === 'boolean' ? initialSpaces : true;
        /**
         * @notes
         * - create a span or anchor element and assign properties to it
         * - JSON.stringify is used to support IE8+
         * - if link.href is not provided, link object properties are ignored
         */
        var isLink = link && JSON.stringify(link) !== '{}' && link.href;
        var shavedTextElType = isLink ? 'a' : 'span';
        for (var i = 0; i < els.length; i += 1) {
            var el = els[i];
            var styles = el.style;
            var span = el.querySelector('.' + classname);
            var textProp = el.textContent === undefined ? 'innerText' : 'textContent';
            // If element text has already been shaved
            if (span) {
                // Remove the ellipsis to recapture the original text
                el.removeChild(el.querySelector('.' + charclassname));
                el[textProp] = el[textProp]; // eslint-disable-line
                // nuke span, recombine text
            }
            var fullText = el[textProp];
            var words = spaces ? fullText.split(' ') : fullText;
            // If 0 or 1 words, we're done
            if (words.length < 2) {
                continue;
            }
            // Temporarily remove any CSS height for text height calculation
            var heightStyle = styles.height;
            styles.height = 'auto';
            var maxHeightStyle = styles.maxHeight;
            styles.maxHeight = 'none';
            // If already short enough, we're done
            if (el.offsetHeight <= maxHeight) {
                styles.height = heightStyle;
                styles.maxHeight = maxHeightStyle;
                continue;
            }
            var textContent = isLink && link.textContent ? link.textContent : character;
            var shavedTextEl = document.createElement(shavedTextElType);
            var shavedTextElAttributes = {
                className: charclassname,
                textContent: textContent,
            };
            for (var property in shavedTextElAttributes) {
                shavedTextEl[property] = shavedTextElAttributes[property];
                shavedTextEl.textContent = character;
            }
            if (isLink) {
                for (var linkProperty in link) {
                    shavedTextEl[linkProperty] = link[linkProperty];
                }
            }
            // Binary search for number of words which can fit in allotted height
            var max = words.length - 1;
            var min = 0;
            var pivot = void 0;
            while (min < max) {
                pivot = (min + max + 1) >> 1; // eslint-disable-line no-bitwise
                el[textProp] = spaces
                    ? words.slice(0, pivot).join(' ')
                    : words.slice(0, pivot);
                el.insertAdjacentElement('beforeend', shavedTextEl);
                if (el.offsetHeight > maxHeight) {
                    max = pivot - 1;
                }
                else {
                    min = pivot;
                }
            }
            el[textProp] = spaces ? words.slice(0, max).join(' ') : words.slice(0, max);
            el.insertAdjacentElement('beforeend', shavedTextEl);
            var diff = spaces
                ? " ".concat(words.slice(max).join(' '))
                : words.slice(max);
            var shavedText = document.createTextNode(diff);
            var elWithShavedText = document.createElement('span');
            elWithShavedText.classList.add(classname);
            elWithShavedText.style.display = 'none';
            elWithShavedText.appendChild(shavedText);
            el.insertAdjacentElement('beforeend', elWithShavedText);
            styles.height = heightStyle;
            styles.maxHeight = maxHeightStyle;
        }
    }

    return shave;

}));

const startTime = new Date();

shave('p', 70, {spaces: false});

const endTime = new Date();
const elapsed = endTime - startTime;
$('.elapsed').html(`${elapsed} ms`);
console.log($('p').length);

              
            
!
999px

Console