2

I'm creating item boxes on a website (CodeIgniter, Bootstrap, jQuery included if it matters) where the title is usually longer than the box itself. I'm wrapping the text inside the box so it goes on multiple rows. The problem is that it still looks ugly in some cases. For example, the text "Brand new photo camera Nikon 3600" wraps to something like that:

Brand new photo camera Nikon
3600

and instead I would like it to be more even on each row like this:

Brand new photo
camera Nikon 3600

I could make an educated guess and insert line breaks at certain places but there should be a better way. Looking mainly for CSS solution but some JavaScript/jQuery will be welcome to as long as it works. Thanks!

mmvsbg
  • 3,570
  • 17
  • 52
  • 73

2 Answers2

2

I've developed a somewhat working solution - it isn't perfect, but it will find the middle space and split there. That being said, a better solution might involve the total character count to find the space that is closest to the true center, or even perhaps getting the width of the entire line and setting the string's container CSS to half of that width. But being that I had nothing but time...

Final Code

function nth_occurrence (string, char, nth) {
    var first_index = string.indexOf(char);
    var length_up_to_first_index = first_index + 1;

    if (nth == 1) {
        return first_index;
    } else {
        var string_after_first_occurrence = string.slice(length_up_to_first_index);
        var next_occurrence = nth_occurrence(string_after_first_occurrence, char, nth - 1);

        if (next_occurrence === -1) {
            return -1;
        } else {
            return length_up_to_first_index + next_occurrence;  
        }
    }
}

function splitValue(value, index) {
    return value.substring(0, index) + "," + value.substring(index);
}

function evenBreak(myString) {
    var count = (myString.match(/ /g) || []).length; //How many spaces are there
    var middle = Math.ceil(count/2); //Find the middle one

    var middleIndex = nth_occurrence(myString, " ", middle); //Get the index of the middle one
    var splitString = splitValue(myString, middleIndex).split(","); //Split the string into two pieces at our middle

    myString = splitString[0] + "<br>" + splitString[1].substring(1); //Put it back together with a line break between

    return myString;
}

var str = evenBreak("This is our newly split string with a line break in the center!");
alert(str);

How we got there

First, we need to find out how many spaces there are...

var count = (temp.match(/ /g) || []).length;

Now that we know there are X spaces, the middle-most is found by doing...

var middle = Math.ceil(count/2);

But how do we find WHERE in our string that middle space is? Here's something I grabbed from another question to do just that...

function nth_occurrence (string, char, nth) {
    var first_index = string.indexOf(char);
    var length_up_to_first_index = first_index + 1;

    if (nth == 1) {
        return first_index;
    } else {
        var string_after_first_occurrence = string.slice(length_up_to_first_index);
        var next_occurrence = nth_occurrence(string_after_first_occurrence, char, nth - 1);

        if (next_occurrence === -1) {
            return -1;
        } else {
            return length_up_to_first_index + next_occurrence;  
        }
    }
}

Okay, so we know exactly where we want to place our line break. But we need a function to do this. I'll split the string there and put a line break between them, by using the following function...

function splitValue(value, index) {
    return value.substring(0, index) + "," + value.substring(index);
}

Known Issues

  • This is only splitting once. It relies on just breaking the string in half, not multiple times.
  • The string will not be split perfectly if the character concentration is not somewhat uniform. It only counts spaces and does not factor in total characters. For example if you had the following sentence "He is a hilarious comedian", the difference in characters on either side of the center-most space is vast.
Community
  • 1
  • 1
Tyler Roper
  • 21,445
  • 6
  • 33
  • 56
0

You may have texts like this:

Photo camera Nikon 3600, brand new. 

that will lead to the same problem if to use any sort of "machine balanced wrap".

So the only reasonable option is to split the text on semantically meaningful blocks. And style them appropriately.

For example:

p {width:10em; border:1px solid; }
span.product { display:inline-block; background: yellow;}
<p>Brand new photo camera <span class="product">Nikon 3600</span></p>
<p>Photo camera <span class="product">Nikon 3600</span>, brand new.</p>

display:inline-block; will cause that fragment to be wrapped as a whole.

c-smile
  • 26,734
  • 7
  • 59
  • 86