title: Truncate HTML text until the text does not overflow the container
body: <p>I am trying to build a function that reduces an <code>HTML</code> text until it does not overflow its container (I don't want the last line broken for the middle). I've taken a look at <a href="https://stackoverflow.com/questions/22821622/how-do-i-smartly-truncate-an-html-string-in-javascript">this question</a>, but the solution is just to manage special characters as <code>&lt;&gt;&amp;</code>. I've also taken a look at <a href="https://stackoverflow.com/questions/3822233/javascript-truncate-html-text">this other question</a> but the solution does not work if the <code>HTML</code>is very complex. Some solutions <a href="https://stackoverflow.com/questions/3922739/limit-text-length-to-n-lines-using-css">are for Webkit only</a> or do not work efficiently with any kind of text (My <code>HTML</code> could have different styles with different <code>line-heights</code>).</p>
  
  <p>Here is the code that I have until now (it is as inefficient as the others), with long and complex texts it could iterate thousands of times and as in my application the container should change its size continuously, this code is useless for my needs.</p>
  
  <p>Is there a good and efficient method to achieve this?</p>
  
  <blockquote>
    <p><strong>NOTE:</strong> My <code>HTML</code> text only contains <code>TEXT_NODEs</code> and <code>ELEMENT_NODEs</code> (excluding <code>scripts</code> and <code>styles</code>), I don't need to manage other kind of nodes.</p>
  </blockquote>
  
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>function reduceHTMLText (container) {
  
      var longer = false; 
      var reg = /^([\s\S]+?)\s*\.+$/;
      var regpunt = /^(.*?)[,;\:\.]$/;
  
      var isOverflow = function () {
          return container.scrollHeight &gt; container.clientHeight;
      };
  
      var reduce = function (element) {
  
          var nodes = element.childNodes;
  
          if (nodes.length === 0) {
  
              longer = isOverflow();
  
              if (longer) { reduce(container); }
  
              return;
  
          }
  
          var last = nodes[nodes.length - 1];
  
          //---Depend of the node type
          switch (last.nodeType) {
  
              //---If the node is a text
              case 3:
  
                  var str = last.data.replace(reg, "$1");
                  var words = str.split(" ");
  
                  //---If the words array has more than five words
                  if (words.length &gt; 5) {
  
                      words = words.slice(0, -5);
  
                      words[words.length - 1] = words[words.length - 1].replace(regpunt, "$1");
  
                      last.data = words.join(" ") + "...";
  
                  } else {
  
                      last.parentNode.removeChild(last);
  
                  }
  
                  longer = isOverflow();
  
                  if (longer) { reduce(element); }
  
              break;
  
              //---If the node is an element node
              case 1:
  
                  if (last.childNodes.length) {
  
                      reduce(last);
  
                  } else {
  
                      last.parentNode.removeChild(last);
  
                      longer = isOverflow();
  
                      if (longer) { reduce(element); }
  
                  }
  
              break;
  
          }
  
      };
  
      longer = isOverflow();
      
      if (longer) { reduce(container); }
  
  }
  
  var container = document.querySelector(".container");
  
  reduceHTMLText(container);</code></pre>
  <pre class="snippet-code-css lang-css prettyprint-override"><code>.container {
      background-color: #EEE;
      height: 170px;
      overflow: hidden;
      width: 500px;
  }</code></pre>
  <pre class="snippet-code-html lang-html prettyprint-override"><code>&lt;div class="container"&gt;
      &lt;p style="text-align: left;"&gt;
          Vestibulum imperdiet ipsum nec urna ornare, quis malesuada odio viverra. Etiam mollis dolor lacus, ac cursus leo aliquam ut. Etiam eu elit in &lt;strong&gt;massa egestas &lt;em&gt;interdum ut&lt;/em&gt; vel magna&lt;/strong&gt;. Suspendisse nisl velit, bibendum id hendrerit at, maximus vitae neque. Integer varius sed ante quis porta. Aenean venenatis pellentesque semper. Etiam a quam ut mauris imperdiet vehicula tristique id lacus. &lt;a href='#'&gt;Aliquam lacus metus, mattis a viverra a, &lt;strong&gt;convallis sit amet diam&lt;/strong&gt;. In dignissim lorem&lt;/a&gt; sit amet, consectetur adipiscing elit. Cras non sem laoreet, tristique felis id, fringilla mi. Fusce sit amet iaculis enim. In malesuada risus eu urna interdum gravida. &lt;strong&gt;Praesent malesuada felis et mi gravida&lt;/strong&gt;, at &lt;em&gt;interdum nunc sollicitudin. Quisque &lt;strong&gt;ultrices nibh&lt;/strong&gt; in malesuada tempus&lt;/em&gt;. Donec tempus efficitur maximus. Praesent ac lacinia odio. Maecenas vel nunc condimentum, luctus diam ac, molestie purus. Cras non tempor magna. Nulla et eros in nunc iaculis eleifend vel at nisi. &lt;strong&gt;Castro pero normal&lt;/strong&gt; Aenean quis ultricies arcu, non volutpat neque. Aliquam at justo sed nisi malesuada lobortis eu ut risus. Fusce at enim quis dolor dignissim gravida vel a felis &lt;span class="soleil-label"&gt;text paloma samona&lt;/span&gt; is cube rubick &lt;a href="http://google.com"&gt;because is impossible to&lt;/a&gt; mantain the text in a long way.
      &lt;/p&gt;
      &lt;p style="text-align: center;"&gt;
          &lt;div class='special'&gt;
              &lt;span class="soleil-cta-button-pink"&gt;
                  &lt;a href="http://google.com" class="soleil-cta-button-pink"&gt;NO REGRETS&lt;/a&gt;
              &lt;/span&gt;
          &lt;/div&gt;
      &lt;/p&gt;
  &lt;/div&gt;</code></pre>
  </div>
  </div>
  </p>