JavaScript to avoid widows [duplicate]

狂风中的少年 提交于 2019-11-28 07:01:56

问题


This question already has an answer here:

  • Widow/Orphan Control with JavaScript? 7 answers

A common problem when working with typography in HTML/CSS is something we call "horunge" in Swedish ("widow" in english).

What it is:

Let's say you have a box with a width of 200px and with the text "I love typograpy very much". Now the text breaks and becomes:

I love typography very
much

As a designer I don't want a word bastard (single word / row). If this was a document/PDF etc. I would break the word before very and look like this:

I love typography
very much

which looks much better.

Can I solve this with a CSS rule or with a javascript? The rule should be to never let a word stand empty on a row.

I know it can be solved by adding a <br /> but that's not a solution that works with dynamic widths, feed content, different translations, browser font rendering issues etc.

Update (solution) I solved my problem with this jquery plugin: http://matthewlein.com/widowfix/


回答1:


A simple jQuery / regrex solution could look like the following, if you add the class "noWidows" to the tag of any element that contains text you are worried about.

Such as:

<p class="noWidows">This is a very important body of text.</p>

And then use this script:

$('.noWidows').each(function(i,d){
   $(d).html( $(d).text().replace(/\s(?=[^\s]*$)/g, "&nbsp;") )
});

This uses regex to find and replace the last space in the string with a non-breaking character. Which means the last two words will be forced onto the same line. It's a good solution if you have space around the end of the line because this could cause the text to run outside of an element with a fixed width, or if not fixed, cause the element to become larger.




回答2:


Just wanted to add to this page as it helped me a lot.

If you have (widows) actually should be orphans as widows are single words that land on the next page and not single words on a new line.

Working with postcodes like "N12 5GG" will result in the full postcode being on a new line together but still classed as an orphan so a work around is this. (changed the class to "noWidow2" so you can use both versions.

123 Some_road, Some_town, N12 5GG

$('.noWidows2').each(function(i,d){ 
    var value="&nbsp;"
    $(d).html($(d).text().replace(/\s(?=[^\s]*$)/g, value).replace(/\s(?=[^\s]*$)/g, value)); 
}); 

This will result is the last 3 white spaces being on a new line together making the postcode issue work.

End Result

123 Some_road,
Some_town, N12 5GG



回答3:


I made a little script here, with the help of this function to find line height.

It's just an approach, it may or may not work, didn't have time to test throughly.

As of now, text_element must be a jQuery object.

function avoidBastardWord( text_element )
{
    var string = text_element.text();
    var parent = text_element.parent();
    var parent_width =  parent.width();
    var parent_height = parent.height();

    // determine how many lines the text is split into
    var lines = parent_height / getLineHeight(text_element.parent()[0]);

    // if the text element width is less than the parent width,
    // there may be a widow
    if ( text_element.width() < parent_width )
    {
        // find the last word of the entire text
        var last_word =  text_element.text().split(' ').pop();

        // remove it from our text, creating a temporary string
        var temp_string = string.substring( 0, string.length - last_word.length - 1);

        // set the new one-word-less text string into our element
        text_element.text( temp_string );

        // check lines again with this new text with one word less
        var new_lines = parent.height() / getLineHeight(text_element.parent()[0]); 

        // if now there are less lines, it means that word was a widow
        if ( new_lines != lines )
        {
            // separate each word
            temp_string = string.split(' ');

            // put a space before the second word from the last
            // (the one before the widow word)
            temp_string[ temp_string.length - 2 ] = '<br>' + temp_string[ temp_string.length - 2 ] ;

            // recreate the string again
            temp_string = temp_string.join(' ');

            // our element html becomes the string
            text_element.html( temp_string );
        }
        else
        {
            // put back the original text into the element
            text_element.text( string );
        }

    }

}

Different browsers have different font settings. Try to play a little to see the differences. I tested it on IE8 and Opera, modifying the string every time and it seemed to work ok.

I would like to hear some feedback and improve because I think it may come in handy anyway.

Just play with it! :)




回答4:


There are also CSS widows and orphans properties: see the about.com article.

Not sure about browser support...

EDIT: more information about WebKit implementation here: https://bugs.webkit.org/buglist.cgi?quicksearch=orphans.




回答5:


Manually, you could replace the space in between with &nbsp;

I've been looking for ways to dynamically add it in. I found a few, but haven't been able to make it work myself.




回答6:


$('span').each(function() {
  var w = this.textContent.split(" ");
  if (w.length > 1) {
    w[w.length - 2] += "&nbsp;" + w[w.length - 1];
    w.pop();
    this.innerHTML = (w.join(" "));
  }
});
#foo {
  width: 124px;
  border: 1px solid #ccc;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="foo">
  <span class="orphan">hello there I am a string really really long, I wonder how many lines I have</span> 
</div>


来源:https://stackoverflow.com/questions/7444656/javascript-to-avoid-widows

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!