Reputation: 15298
Suppose a text shows up as follows on an HTML page (just one word too long to fit on one line):
Lorem ipsum dolores amet foo
bar
How can one avoid with CSS that the last word appears on the last line, and force two (or more)?
Lorem ipsum dolores amet
foo bar
Upvotes: 21
Views: 11946
Reputation: 2059
This question has been answered at https://stackoverflow.com/a/76701845/2076595. Nowadays, after many years of waiting, you can do this with CSS: text-wrap: pretty
.
I initially added that answer to this question here as well, but a moderator deleted my answer saying I should flag questions as duplicates instead. All good, but unfortunately I don’t have enough points to cast duplicate-votes so here we are: me referring to the other answer. Sorry about that, but apparently that’s the rules.
For completeness: this questions is the OG question. These two other questions are duplicates and should get marked as duplicates of this question:
Upvotes: 2
Reputation: 365
here's some newbie php that you might use if you wanted to do this in wordpress
function add_nobr_spans($string) {
$words = explode(' ', $string);
if (count($words) < 3){
return $string;
}
$last_word = array_pop($words);
while ($last_word == "") {
$last_word = array_pop($words);
}
if (preg_match('#[<>]+#is', $last_word)) {
return $string;
}
$almost_last_word = array_pop($words);
if (preg_match('#[<>]+#is', $almost_last_word)) {
return $string;
}
array_push($words, "<span class='nobr'>".$almost_last_word." ".$last_word."</span>");
return implode(' ', $words);
}
function no_widows_for_end_tag($input, $end_tag){
$split_stuff = explode($end_tag, $input);
$split_stuff = array_map('add_nobr_spans', $split_stuff);
$result = implode($end_tag, $split_stuff);
return $result;
}
function no_widows($string) {
$string = no_widows_for_end_tag($string, "</p>");
$string = no_widows_for_end_tag($string, "</h3>");
$string = no_widows_for_end_tag($string, "</h4>");
$string = no_widows_for_end_tag($string, "</h5>");
return $string;
}
Upvotes: 0
Reputation: 7049
If JavaScript is an option, one can use typogr.js, a JavaScript "typogrify" implementation. This particular filter is called Widont.
<script src="https://cdnjs.cloudflare.com/ajax/libs/typogr/0.6.7/typogr.min.js"></script>
<script>
document.body.innerHTML = typogr.widont(document.body.innerHTML);
</script>
</body>
Upvotes: 1
Reputation: 13105
Just wrote this dependency-free JS snippet that will solve this very problem
https://github.com/ajkochanowicz/BuddySystem
Essentially this is the source code
var buddySystem=function(e){var n=[],r=[]
n=e.length?e:n.concat(e),Array.prototype.map.call(n,function(e){var n=String(e.innerHTML)
n=n.replace(/\s+/g," ").replace(/^\s|\s$/g,""),r.push(n?e.innerHTML=n.replace(new RegExp("((?:[^ ]* ){"+((n.match(/\s/g)||0).length-1)+"}[^ ]*) "),"$1 "):void 0)})}
and you can implement it by doing this
objs = document.getElementsByClassName('corrected');
buddySystem(objs);
Now you'll never have a word by itself for any tags with the corrected
class.
You can also use jQuery if you want.
$(".corrected").buddySystem()
Check out the link for all possibilities.
Upvotes: 6
Reputation: 2474
I don't think it can be done in CSS alone but this is what I came up with to solve the one word per line problem. It will replace the last n spaces with a non breaking space for all the matched elements.
https://jsfiddle.net/jackvial/19e3pm6e/2/
function noMoreLonelyWords(selector, numWords){
// Get array of all the selected elements
var elems = document.querySelectorAll(selector);
var i;
for(i = 0; i < elems.length; ++i){
// Split the text content of each element into an array
var textArray = elems[i].innerText.split(" ");
// Remove the last n words and join them with a none breaking space
var lastWords = textArray.splice(-numWords, numWords).join(" ");
// Join it all back together and replace the existing
// text with the new text
var textMinusLastWords = textArray.join(" ");
elems[i].innerHTML = textMinusLastWords + " " + lastWords;
}
}
// Goodbye lonely words
noMoreLonelyWords("p", 3);
Upvotes: 10
Reputation: 424
Can't be done with CSS, but Shaun Inman wrote a very useful bit of Javascript to help with this a while ago:
http://www.shauninman.com/archive/2006/08/22/widont_wordpress_plugin
It's a Wordpress plugin, but there are plenty of non-Wordpress clones around.
Upvotes: 2
Reputation: 449485
I don't think you can do this in pure CSS.
You would have to either put a non-breaking space in between the last two words:
foo bar
or put the last two words into a span
:
<span style="white-space: nowrap">foo bar</span>
Upvotes: 27