Using jQuery to shorten long content and add a "Show the rest of this" link

My use case was that I had a super long blog entry that I didn't want to hog my blog's front page. So I needed to shorten it down to a certain pixel height, and add a link that would expand it completely.

First, we need a couple of jQuery bits:

  // Go through each item in the main blog page and shorten if bigger than 1500px
  $('.view-blog .views-row').each(function (i) {
    var div_height = $(this).height();
    if (div_height > 1500) {
      $(this).height(1500);
      $(this).append('<input type="hidden" class="item-height" value="' + div_height + '" />');
      var id = 'expando-num-' + i;
      $(this).attr('id', id);
      $(this).after('<a href="' + id + '" class="expando-div">This is a long blog post, click here to view the rest</a>');
    }
  });
  
  // Add the 'click to expand' behavior to the links
  $('.expando-div').click(function () {
    $(this).remove();
    var $div = $('#' + $(this).attr('href'));
    var div_height = $div.find('.item-height').val();
    $div.animate({height:div_height}, 1000);
    return false;
  });

I added this code inside of a function called Drupal.behaviors.custom_misc()Click here to read a bit more about Drupal behaviors.

Note that your selectors might be different. I'm using a Drupal view to display the blog, so I can rely on certain selectors.

Next, we need to add a couple of styles to our CSS (or LESS) file:

.view-blog .views-row {
  overflow:hidden;
}
.expando-div {
  display:block;
  margin-bottom:30px;
  background:#185686;
  color:white;
  text-decoration:none;
  padding:5px;
}

The only really necessary part there is the overflow:hidden, which makes it so the hidden content doesn't overlap on other stuff.

My result (with a little more CSS styling) looks like this:

Coming up with ideas out of the blue that meet these criteria was little tricky, but there are few things that came up for me: Transcribing the training videos on Build Module.com for searchable textual This is long blog post, click here to view the rest on


Comments

Currently on your home page if you scroll to the bottom entry and click the "This is a long blog post" link, the rest of the entry does not show. Is that a side-effect of using overflow:hidden?

Interesting. May I ask what browser you're using?

Well, now that the bottom post of your homepage isn't a long one I'm not seeing the issue. Saw it in both Firefox and Safari before though.

There is a jQuery plugin that works in a similar way—http://plugins.learningjquery.com/expander/demo/index.html

Hi Jon, I like that plugin, but from what I can tell it divides based on text rather than actual size. Because I'm using a bunch of screenshots in my post, cutting off at a particular character length would have inconsistent results.

But, still a good plugin to keep in mind, thanks!

Hi, you don't have to declare the "i" variable because the .each() method already has an iterator index available. Just use it like this: .each(i) where i is an index.

Also it's not necessary to use $(this) again and again, cache it in a variable for all future references: var $this = $(this);

Thanks, Bohdan, good to know! I've updated the script to use the i. The script was actually broken because I wasn't incrementing the i, so when you'd click on one of the expando-links below the others, it would expand the first one. Tricky.

One question, Bohdan: Is there a performance cost to using $(this) rather than a cached variable? I use the caching method when I have a nested .each() and need to parent variables, but I never thought about there being a possible performance gain.

There's definitely a performance cost because you're technically running the base jQuery function again with each $(this) call. jQuery has to convert a plain DOM element (this) to a jQuery object.

Another option is to chain all method calls on a single jQuery call:

$(this)
  .height(1500)
  .append('<input type="hidden" class="item-height" value="' + div_height + '" />')
  .attr('id', id);
  .after('<a href="' + id + '" class="expando-div">This is a long blog post, click here to view the rest</a>');

Thanks, and good idea about the chaining. I wonder if there are performance benefits to chaining as well? Cheers!

There is hardly any difference between caching $(this) in a variable and chaining. It's more about personal preference and code style. Take a look at this code excerpt from Views' ajax_view.js: http://pastie.org/1053865
There, chaining leads to worse code readability and must be balanced with heavy commenting. Not to mention other bad habits present there (like not caching jQuery objects).
I'm going to write an article on jQuery bad habits in Drupal world soon, because I really see such stuff every day in Drupal modules.

That would be great, feel free to post a link here if you do. I'm sure I've got more than a few bad jQuery habits. :)

Thanks for verifying the issue with the expander, I found the issue and it should work fine now.

Good question about the search engine rankings. I checked my Analytics and it looks like traffic from the search engines has been steadily climbing this month, so it looks like there hasn't been any negative effect.

What I know about search engines I know second hand, but what I've gathered is that they don't track directly when a site is using a content hiding strategy, either with CSS or javascript. However, if the site gets flagged for some reason (a badly managed link building campaign, link farming, paying for links, linking to spammy sites) then a manual review of the site might indicate that the site is in violation of the engine's TOS and they could penalize or blacklist the site.

Because there are so many legitimate reasons to hide content (drop-down menus, scrolling news feeds, "read more" links), I would imagine that multiple negative vectors would have to converge before you'd see a penalty being applied.

That said, it's been a while since I've updated my knowledge on the subject, and would love to hear some first-hand experiences.

I also see the front page failure. When clicking on the link in safari it scrolls the page but doesn't reveal any new content.

I'd also be curious what you see from the search engines with this approach. They seem to be very sensitive to approaches that put hidden text on pages. Have you seen any changes in ranking with this approach?