O'Reilly

Pretty Word Wrapper with MooTools or PHP

By on  

Details, details, details. Details are what take a good site to the next level. Small details like link nudging (jQuery, MooTools), simple but stylish CSS enhancements, and opacity effects are the cheeky effects that give your website the edge over similar websites. The detail we'll be addressing today is "widowed" text. A "widow" occurs when only one word of a long string wraps to the next line. An example would be:

Widow

No offense to raging cougars out there but widows look wonky. The best way to prevent widows is to add a " " between the last and second-to-last words in a string. Doing this, the example above would split to the next like at "or" so that two words would be on the second line. Today I'll show you how to accomplish this using a tiny MooTools class or PHP.

The MooTools JavaScript

//class
var WordWrapper = new Class({
	
	Implements: [Options],
	
	options: {
		elements: 'h1',
		minWords: 3
	},
	
	initialize: function(options) {
		this.elements = $$(options.elements);
		this.elements.each(function(el) {
			this.apply(el);
		},this);
	},
	
	apply: function(element) {
		var original = element.get('html'), arr = original.split(' ');
		if(arr.length >= this.options.minWords) {
			//join the last and second to last
			arr[arr.length - 2] += ' ' + arr[arr.length - 1];
			arr.pop();
			element.set('html',arr.join(' '));
		}
	}	
});

The MooTools plugin offers just a few options: the elements to apply this too and the minimum number of words the element must have before the substitution takes place. The usage is just as easy as you'd expect:

//usage
window.addEvent('domready',function() {
	var ww = new WordWrapper({
		elements: 'h2'
	});
});

//sample results
//"This Is The First Attempt" becomes: This Is The First Attempt
//"Leave Me" is not long enough to modify
//"Que?" is not long enough to modify
//"I Am, I Am SuperMan, And I Can Do Anything" becomes: I Am, I Am SuperMan, And I Can Do Anything

Awesome....but what about a PHP version? Sure, why not?

The PHP

function word_wrapper($text,$minWords = 3) {
	$return = $text;
	$arr = explode(' ',$text);
	if(count($arr) >= $minWords) {
		$arr[count($arr) - 2].= ' '.$arr[count($arr) - 1];
		array_pop($arr);
		$return = implode(' ',$arr);
	}
	return $return;
}

And Voila! Now you can update any text before it hits the DOM!

The jQuery

Wanna see how you'd accomplish this feat with jQuery? Hop over to Chris Coyier's CSS-Tricks blog post to find out!

Track.js Error Reporting

Upcoming Events

Recent Features

  • Creating Scrolling Parallax Effects with CSS

    Introduction For quite a long time now websites with the so called "parallax" effect have been really popular. In case you have not heard of this effect, it basically includes different layers of images that are moving in different directions or with different speed. This leads to a...

  • 5 Ways that CSS and JavaScript Interact That You May Not Know About

    CSS and JavaScript:  the lines seemingly get blurred by each browser release.  They have always done a very different job but in the end they are both front-end technologies so they need do need to work closely.  We have our .js files and our .css, but...

Incredible Demos

  • CSS content and attr

    CSS is becoming more and more powerful but in the sense that it allows us to do the little things easily.  There have been larger features added like transitions, animations, and transforms, but one feature that goes under the radar is generated content.  You saw a...

  • Sexy Album Art with MooTools or jQuery

    The way that album information displays is usually insanely boring. Music is supposed to be fun and moving, right? Luckily MooTools and jQuery allow us to communicate that creativity on the web. The XHTML A few structure DIVs and the album information. The CSS The CSS...

Discussion

  1. Chris the Developer

    Wouldn’t it be more safe-mode friendly if you used document.getElements() instead of $$?

  2. @Chris the Developer: How so?

  3. Francis

    Took me a while to understand what this was doing until I noticed that the &nbsp is replaced by a blank space ‘ ‘ in the code!
    Should read: $arr[count($arr) – 2].= ‘&nbsp’.$arr[count($arr) – 1];

  4. Thanks Francis! Stupid WordPress…

  5. Ineresting approach, I use a little function that cuts the text off after a certain amount of characters and then adds … to it. Of course I’m checking correctly for things like, cutting at the first space before the max amount of chars, taking care of commas and hyphens, etc

  6. Dutchie

    Hmm.. I like this idea, but still the www is not a thing like print is in combination with InDesign (I reffuse to mention Quark, lol), which have advanced widow cut rules etc. build in. I mean, it’s not always appropriate to move the two last words to the next line as a default in various languages/situations.. then I rather blame the browser’s neanderthaler rudeness :)

    But again, it’s an original idea which probably makes the headlines in most cases a bit nicer, and the JS is small (and php is fast).

  7. Greg

    You can stream line you code a little by changing the

    arr[arr.length - 2] += ' ' + arr[arr.length - 1];
    arr.pop();
    

    with

    arr[arr.length - 2] += ' ' + arr.pop();
    

    You can do the same with the PHP too.

    since the array Pop method both removes the last item in the array AND returns its value. Though this will not make a huge impact on the performance of the code it is code practice.

  8. Simon

    I can’t get this to work. Am I doing something wrong?

    I add the php code into the head but it doesn’t add a non-break-space

    Can anyone point me to a working example?

    • Works fine for us with PHP, example in the h1 headline at http://charleston.thedigitel.com/politics/folly-beach-bans-discrimination-based-sexual-orien-38425-0315

      I also modified it a bit to allow for us to concat the last three words if there are six or more words (good for our headline setup), code below.

      /**
       * Prevent widows
       * based off http://davidwalsh.name/word-wrap-mootools-php
       *
       * If there are 6+ words it will concat three words with ' '
       * otherwise if 3+ it will concat two words at end
       *
       * The longWords can be disabled by setting $longWords 
       * to a high value (i.e. 99999) when calling the function
       * 
       **/
      function word_wrapper($text,$longWords = 6,$minWords = 3) {
        $return = $text;
        $arr = explode(' ',$text);
        if(count($arr) >= $longWords) {
          $arr[count($arr) - 2].= ' '.$arr[count($arr) - 1];
          array_pop($arr);
          $arr[count($arr) - 2].= ' '.$arr[count($arr) - 1];
          array_pop($arr);
          $return = implode(' ',$arr);
        } elseif(count($arr) >= $minWords) {
          $arr[count($arr) - 2].= ' '.$arr[count($arr) - 1];
          array_pop($arr);
          $return = implode(' ',$arr);
        }
        return $return;
      }
       
       
  9. Fiddlesticks, it garbled my code paste (I even used the tags!) See it here http://pastebin.com/DhVKZu1T

  10. Okay, I give up. Here is a Gist on how to do it in Ruby: https://gist.github.com/stephenhowells/6245701“>https://gist.github.com/stephenhowells/6245701″ rel=”nofollow”>https://gist.github.com/stephenhowells/6245701

  11. Andrew Zammit

    I believe this should be done on the front-end, however here’s an alternate PHP implementation (no support for min words):

    function noWidow($str) {
        return preg_replace('/\\s+([^\\s]+\\s*)$/',' $1',$str);
    }
    
  12. Andrew Zammit

    I believe this should be done on the front-end, however here’s an alternate PHP implementation (no support for min words): http://pastebin.com/0h6ZqZUE

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!

Recently on David Walsh Blog

  • Generating Alternative Stylesheets for Browsers Without @media

    If your CSS code is built with a mobile-first approach, it probably contains all the rules that make up the "desktop" view inside @media statements. That's great, but browsers that don't support media queries (IE 8 and below) will simply ignore them, ending up getting the...

  • Serve a Directory with PHP

    Many developers have a giggle at PHP, even looking down at the language, but let's be honest:  most of our blogs are powered by it (WordPress) and it's a great language to dabble around with.  I cut my teeth on PHP, though I prefer to avoid PHP these days. But...

  • Tips you can Use to Build an Excellent eCommerce Experience

    There are many reasons to build a good eCommerce experience if you are planning to build an eCommerce website. Visitors can place items in their cart and leave your site without making a purchase. In fact, three out of every four of them will do so....

  • OSCON: Live Stream

    O'Reilly's OSCON is upon us and I'm super excited to share with you a live stream of OSCON keynotes, courtesy of O'Reilly! Check back here every morning this week to get a sneak peek at the best conference in the open source community! Thank you...

  • OâReilly Velocity Conference â New York

    My favorite front-end conference has always been O'Reilly's Velocity Conference because the conference series has focused on one of the most undervalued parts of client side coding:  speed.  So often we're so excited that our JavaScript works that we forget that speed, efficiency, and performance are just as important. The next Velocity...