Grow your CSS skills. Land your dream job.

Last updated on:

Underline Individual Words

There is no CSS for applying an underline (text-decoration: underline;) only to individual words in a multiple-word element. The best way would be to wrap each word in a span (not the spaces, just the words) in spans and apply underline to those spans. Here's jQuery to do that to h1 elements.

$('h1').each(function() {

	var words = $(this).text().split(' ');

	$(this).empty().html(function() {

		for (i = 0; i < words.length; i++) {
			if (i == 0) {
				$(this).append('<span>' + words[i] + '</span>');
			} else {
				$(this).append(' <span>' + words[i] + '</span>');
			}
		}
	
	});

});

Then you could do:

h1 span {
  text-decoration: underline;
}

Similar and slightly more robust solution: Lettering.js

Reference URL

Comments

  1. For the raw JS version:

    var h1s = document.getElementsByTagName('h1');
    for(var i=0; i < h1s.length; i++) {
        var t = h1s[i];
        t.innerHTML = '<span>' + t.innerHTML . split(' ') . join('</span><span>') +  '</span>'; 
    }

    I believe I reduced the footprint a little too. Although your version is a lot more abstract and uses better maintainable code.

  2. Just a note: If you do a for loop, you should declare the i variable with the var keyword. See here why.

    Furthermore, if this for-loop sees the length is 0, it will never reach the inside of the for loop and breaks off before initiating the code inside. Therefore, your if-else-statement is completely ignored, since only the else case can be true. If will never be reached, because the for loop breaks off before then.

  3. Permalink to comment#

    The code in the reference is correct, but that code on this page is missing the span tags within append().

  4. TeMc
    Permalink to comment#

    Although the raw JS version isn’t too bad either. There’s some performance to be gained in the jQuery version as wel. Why call $.fn.each, $.fn.empty, $.fn.html and then a dozen times $.fn.append ?

    
    function htmlEsc(txt){
      return txt.replace(/&/g, "&").replace(//g, ">");
    }
    $('h1').each(function() {
    
            var $el = $(this),
                words = $el.text().split(' '),
                newHtml = '',
                i = 0, 
                len = words.length;
    
            for ( ; i < len; i++) {
                    if (i < 0) {
                           newHtml += ' '; // space
                    }
                    newHtml += '' + htmlEsc( words[i] ) + '';
            }
    
            $(this).html( newHtml );
    
    });
    

    * the empty() is simply redundant
    * the calls to append() don’t make sense inside html. Either build outside and call $(this).append() a few times, or build it inside and call $(this).html( stuff ); The latter is recommended.
    * You’re using text() to retrieve the value but using html()/append() to put it back. This is very dangerous when working with user input and can also destroy your layout if there is anything like HTML in your titles. You must escape html here when building the strings (or use $.fn.text)
    * Don’t forget ‘var’ instead of i in the for loop. Or move it to the list of vars outside the for-loop, that way you save a few bits in not starting two var statements (those are all one var statement, not how they are separated by a comma.

  5. TeMc
    Permalink to comment#

    Although the raw JS version isn’t too bad either. There’s some performance to be gained in the jQuery version as wel. Why call $.fn.each, $.fn.empty, $.fn.html and then a dozen times $.fn.append ?

    
    function htmlEsc(txt){
      return txt.replace(/&/g, "&").replace(//g, ">");
    }
    $('h1').each(function() {
    
            var $el = $(this), words = $el.text().split(' '), newHtml = '',  i = 0,  len = words.length;
    
            for ( ; i < len; i++) {
                    if (i < 0) { newHtml += ' ';  } // add space between words
                    newHtml += '' + htmlEsc( words[i] ) + '';
            }
    
            $(this).html( newHtml );
    });
    

    * the empty() is simply redundant
    * the calls to append() don’t make sense inside html. Either build outside and call $(this).append() a few times, or build it inside and call $(this).html( stuff ); The latter is recommended.
    * You’re using text() to retrieve the value but using html()/append() to put it back. This is very dangerous when working with user input and can also destroy your layout if there is anything like HTML in your titles. You must escape html here when building the strings (or use $.fn.text)
    * Don’t forget ‘var’ instead of i in the for loop. Or move it to the list of vars outside the for-loop, that way you save a few bits in not starting two var statements (those are all one var statement, not how they are separated by a comma.

  6. Ecatherina
    Permalink to comment#

    Chris, tell me please how to put in the script, not only h1, but more and h2.
    Thank you in advance , Ecatherina.

  7. Permalink to comment#

    thanks

  8. Permalink to comment#

    i need some css code pls oga

  9. Permalink to comment#

    Your tutor is very nice guys…
    like it’s..

  10. Nice game! The thing that really irks us a lot is having if an individual online connection to play in solo mode. I mean seriously wtf?

  11. Yukulélé
    Permalink to comment#

    my version accept non-final nodes !

    gist :

    https://gist.github.com/yukulele/8668962

    pen :

Leave a Comment

Current ye@r *

*May or may not contain any actual "CSS" or "Tricks".