0

I am working on a way to display posts in a way that if the text of the post has more than three lines, only the first three lines are displayed and the rest is toggled via a Show More/Show Less div. I am using liquid for the loop over the posts, a css class for truncating and jquery for toggeling the truncate class

My problem now is that I would like to give the Show More/Show Less div the display:none property if we have less than three lines, but I don't know how.

Here is the code excerpt:

html:

<div class="posts">
{% for post in site.posts %}
<div class="post-teaser">
  {% if post.thumbnail %} 
  <div class="post-img">
     <img src="{{ site.baseurl }}/{{ post.thumbnail }}">
  </div>
  {% endif %}
  <span>
      <header>
        <h1>
            {{ post.title }}
        </h1>
        <p class="meta">
          {{ post.date | date: "%B %-d, %Y" }}
        </p>
      </header>
      <div id="{{post.path}}" class="excerpt truncate">
          {{ post.content | strip_html | escape }}
      </div>
          <div class="txtcol"><a>Show More</a></div>
  </span>
</div>
{% endfor %}

CSS:

/* styles for '...' */ 
.truncate {
/* hide text if it more than N lines  */
overflow: hidden;
/* for set '...' in absolute position */
position: relative; 
/* use this value to count block height */
line-height: 1.2em;
/* max-height = line-height (1.2) * lines max number (3) */
max-height: 3.6em; 
/* fix problem when last visible word doesn't adjoin right side  */
text-align: justify;  
/* place for '...' */
margin-right: -1em;
padding-right: 1em;
}
/* create the ... */
.truncate:before {
/* points in the end */
content: '...';
/* absolute position */
position: absolute;
/* set position to right bottom corner of block */
right: 0;
bottom: 0;
}
/* hide ... if we have text, which is less than or equal to max lines 
*/
.truncate:after {
/* points in the end */
content: '';
/* absolute position */
position: absolute;
/* set position to right bottom corner of text */
right: 0;
/* set width and height */
width: 1em;
height: 1em;
margin-top: 0.2em;
/* bg color = bg color under block */
background: white;
}

from here: http://hackingui.com/front-end/a-pure-css-solution-for-multiline-text-truncation/

And jquery:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"> 
</script>
<script>
$(document).ready(function(){
  $(".txtcol").click(function(){
    if($(this).prev().hasClass("truncate")) {
            $(this).children('a').text("Show Less");
        } else {
            $(this).children('a').text("Show More");
        }
  $(this).prev().toggleClass("truncate");

  });
});
</script>

I would prefer a CSS solution, if possible.

EDIT: here is a snippet: https://jsfiddle.net/6349q51r/4/

In the second post, the show more/show less should not appear (on most devices).

EDIT 2: Here is my try to implement it, but somehow the line

$(this).next().css("display", "none;");

does not work. https://jsfiddle.net/6349q51r/29/+

EDIT 3: It was a typo; it now works: https://jsfiddle.net/6349q51r/36/

ge0rg
  • 63
  • 1
  • 11
  • 3
    It would really help if you create a snippet of your situation! – Thomas van Broekhoven Sep 13 '18 at 15:35
  • to further thomas' comment, it would also be very beneficial if you could use the rendered html rather than what looks like liquid – Pete Sep 13 '18 at 15:47
  • you can use regular expression to keep count of how many lines there is in the dom and then toggle the class to display or show the toggle link. – Jose CC Sep 13 '18 at 15:48
  • This answer might help: https://stackoverflow.com/questions/8720931/can-css-detect-the-number-of-children-an-element-has – Kent Brewster Sep 14 '18 at 18:17

2 Answers2

4

You can check for the height of the data with scrollHeight of the data. if scrollHeight is greater than height then show the Show More/Less div.

I have created one snippet for you.. see the js and css.

$(document).ready(function(){
  $(".content").each(function(){
    if($(this).height() < $(this)[0].scrollHeight){
      $(this).parent().find(".txtcol").show();
      $(this).toggleClass("truncate");
    }
  });
  $(".txtcol").click(function(){
    if($(this).prev().hasClass("truncate")) {
        $(this).parent().find(".content").css("max-height", $(this).parent().find(".content")[0].scrollHeight);
            $(this).children('a').text("Show Less");
        } else {
        $(this).parent().find(".content").css("max-height", "3.6em");
            $(this).children('a').text("Show More");
        }
  $(this).prev().toggleClass("truncate");

  });
});
.content {
    width:100px;
    overflow: hidden;
    white-space:normal;
    text-overflow: ellipsis;
    line-height: 1.2em;
    /* max-height = line-height (1.2) * lines max number (3) */
    max-height: 3.6em; 
    /* fix problem when last visible word doesn't adjoin right side  */
    text-align: justify;  
}
.txtcol{
  display:none;
  color:blue;
  cursor:pointer;
}
.maincontent{
  display:inline-block;
  vertical-align:top;
  border: 1px solid gray;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="maincontent">
<div class="content">
Lorem Ipsum is simply dummy text of the printing and typesetting industry. 
</div>
<div class="txtcol"><a>Show More</a></div>
</div>

<div class="maincontent">
<div class="content">
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been Lorem Ipsum has been Lorem Ipsum has been Lorem Ipsum has been 
</div>
<div class="txtcol"><a>Show More</a></div>
</div>


<div class="maincontent">
<div class="content">
Lorem Ipsum is simply 
</div>
<div class="txtcol"><a>Show More</a></div>
</div>

You can test it on jsfiddle with small amount of text..

https://jsfiddle.net/nimittshah/rdjyucpz/

Thanks,

Nimitt Shah
  • 4,477
  • 2
  • 10
  • 21
  • This doesn't work as soon as I have multiple entries like this one below each other. In particular, the code if($(".content").height() < $(".content")[0].scrollHeight){ $(".txtcol").show(); } needs to handle each element with such a class seperately. – ge0rg Sep 14 '18 at 18:19
  • If you have multiple entries, you will need to change your html little bit.. I have created jsfiddle.. https://jsfiddle.net/nimittshah/0rsmhte2/18/ – Nimitt Shah Sep 14 '18 at 18:30
  • It does not hide properly now when your text is short. – ge0rg Sep 14 '18 at 18:38
  • However, my latest version is based on an idea I got from your answer, can you check if you see what is wrong? I'm a total webdesign noob :D. – ge0rg Sep 14 '18 at 18:49
  • Updated the answer jsfiddle https://jsfiddle.net/nimittshah/1wxjv097/ and snippet. – Nimitt Shah Sep 14 '18 at 19:10
  • Thanks, it works now. I have a slightly different solution now, see last edit, but it uses the a similar method for hiding. – ge0rg Sep 14 '18 at 19:27
  • You're welcome.. please accept the answer if it helps you ;) – Nimitt Shah Sep 14 '18 at 19:28
  • This solution has a problem. Read more/less has to be clicked twice for first time to activate. I fixed it and here is my improved fiddle: https://jsfiddle.net/1ukvjc54/ – Sahriar Saikat May 11 '20 at 11:24
0

$(document).ready(function(){
  $(".content").each(function(){
    if($(this).height() < $(this)[0].scrollHeight){
      $(this).parent().find(".txtcol").show();
      $(this).toggleClass("truncate");
    }
  });
  $(".txtcol").click(function(){
    if($(this).prev().hasClass("truncate")) {
        $(this).parent().find(".content").css("max-height", $(this).parent().find(".content")[0].scrollHeight);
            $(this).children('a').text("Show Less");
        } else {
        $(this).parent().find(".content").css("max-height", "3.6em");
            $(this).children('a').text("Show More");
        }
  $(this).prev().toggleClass("truncate");

  });
});
.content {
    width:100px;
    overflow: hidden;
    white-space:normal;
    text-overflow: ellipsis;
    line-height: 1.2em;
    /* max-height = line-height (1.2) * lines max number (3) */
    max-height: 3.6em; 
    /* fix problem when last visible word doesn't adjoin right side  */
    text-align: justify;  
}
.txtcol{
  display:none;
  color:blue;
  cursor:pointer;
}
.maincontent{
  display:inline-block;
  vertical-align:top;
  border: 1px solid gray;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="maincontent">
<div class="content">
Lorem Ipsum is simply dummy text of the printing and typesetting industry. 
</div>
<div class="txtcol"><a>Show More</a></div>
</div>

<div class="maincontent">
<div class="content">
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been Lorem Ipsum has been Lorem Ipsum has been Lorem Ipsum has been 
</div>
<div class="txtcol"><a>Show More</a></div>
</div>


<div class="maincontent">
<div class="content">
Lorem Ipsum is simply 
</div>
<div class="txtcol"><a>Show More</a></div>
</div>