You can try looping through all the characters, in each loop, select the current character into a range object, from that you can use getBoundingClientRect()
method of the range object to get the bottom
of the character rect. It's the way we detect the ending character on each line. Here is the signs to detect the ending character:
- If we use normal wrapping, all the lines should break at some space character. The special thing is that in this case, the ending space character will have rect (getting from
getBoundingClientRect()
) with both top
and bottom
being 0
.
- If we use wrapping like
word-break:break-all
, the ending character may be some other character (not the space character). In this case we will detect the next character following the ending character, the next character will have bottom
different from the ending character's bottom
.
So it's fairly complicated indeed. In fact at first I thought we had only 1 case (the second case) but if we ignore the first case, we will have unexpected result. So firstly we need to check the first case, then the second case. Now detecting the ending character in each line helps us separate the whole text into separate lines. Then we can wrap each line in a div
element with appropritate style set (to align the text in each line).
Here is the demo's code:
HTML:
<h3>Original column</h3>
<div class='o-column'>racket kingpins are rounded up in bomb killing</div>
<h3>Column after adjusted</h3>
<div class='column'>racket kingpins are rounded up in bomb killing</div>
CSS:
.column, .o-column {
width:300px;
border:1px solid black;
margin-bottom:5px;
text-transform:uppercase;
padding:5px;
font-size:30px;
font-family:'Arial';
word-wrap:break-word;
}
JS:
console.clear();
var column = document.querySelector('.column');
var ends = [];
var range = document.createRange();
range.selectNodeContents(column);
var lines = [];
var lastBottom = null;
//if the innerHTML has some \n character, there will be some unexpected
//behavior, all the \n characters should be removed first.
column.innerHTML = column.innerHTML.replace(/\n/g,'');
var len = column.innerHTML.length;
for(var i = 0; i < len; i++){
//set range for current character
range.setStart(column.childNodes[0],i);
range.setEnd(column.childNodes[0],i+1);
var rect = range.getBoundingClientRect();
if((rect.bottom == 0 && rect.top == 0) ||
rect.bottom != lastBottom && lastBottom != null || i == len-1){
var line = document.createElement('div');
var lineStart = ends.length ? ends[ends.length - 1] + 1 : 0;
line.innerHTML = column.innerHTML.substring(lineStart, i == len - 1 ? len : i);
lines.push(line);
ends.push(rect.bottom ? i - 1 : i);
}
if(rect.bottom != 0) lastBottom = rect.bottom;
else lastBottom = null;
if(ends.length > 3) break;
}
var n = lines.length;
//we align each line only if there are less than 4 lines
if(n < 4 && n > 0){
column.innerHTML = "";
for(var i = 0; i < n; i++){
column.appendChild(lines[i]);
}
if(n == 1) lines[0].style.textAlign = 'center';
else {
lines[0].style.textAlign = 'left';
lines[n-1].style.textAlign = 'right';
if(n == 3) lines[1].style.textAlign = 'center';
}
}