3

How can I align text around a "pivot" word, such that the pivot word appears in the center of its line (when displayed in a browser)?

Say [ and ] mark the beginning and end of lines, and X is a mid-line marker, included here for clarity.

So, for single-line:

 X [ I am centered around my PIVOT word. ] [ Here is the PIVOT word of this second example. ] 

With multi-line, it can be something like:

 X [ This is multiline text with ] [ one word which functions as the PIVOT. Then we have some more boring ] [ multiline text you don't have to worry about ] 
12
  • Yo can do a three column page. "pivot" in the middle column with center align. And right align for the left column and left align for rigth column Commented May 15, 2013 at 14:05
  • @Flowen, would it work if the text spans over multiple lines? would the spacing on the sides of the pivot word look "natural"? Commented May 15, 2013 at 14:11
  • If columns are aligned to the mid column, spacing on sides should always be the same. Commented May 15, 2013 at 14:16
  • You can set a margin-left or margin-rigth in order to look like natural "spacing" Commented May 15, 2013 at 14:21
  • I'think this can be done only with JavaScript. Commented May 15, 2013 at 14:36

4 Answers 4

1

Reworked my first answer. Works a lot better now. See the fiddle. It is based on the idea that you split the paragraph on the pivot word. The pivotword and the last section are placed back in the paragraph. The first half (before the pivot word) is then split into an array, which is traversed backwards (each time popping the last element) to fill the span until it reaches its width. This will repeat itself until there are no more words left in the array. I am not a native English speaker, so I hope this will all make some sense.

<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title></title> <script type="text/javascript" src="js/jquery-1.9.0/jquery.min.js"></script> <style type="text/css"> .container { width: 500px; border: 1px solid #ddd; } .pivotWord { background-color: red; color: white; font-weight: bold; } </style> </head> <body> <div class="container"> <p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in PIVOT voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. </p> <p> Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. PIVOT Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. </p> <p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et PIVOT dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. </p> <p> Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non PIVOT proident, sunt in culpa qui officia deserunt mollit anim id est laborum. </p> </div> <script type="text/javascript"> function pivotAround(pivotword){ $('p').each(function(){ //initialize a few things var sentence = $(this).html(); var splittedSentence = sentence.split(pivotword); var paragraphWidth = $(this).width(); $(this).html(""); //create elements from the sentence parts. var pivotSpan = $("<span />", { 'class': 'pivotWord' }).html(pivotword); var postSpan = $("<span />", { }).html(splittedSentence[1]); //append them to the DOM $(this).append(pivotSpan) .append(postSpan); //get size of pivotSpan var pivotSpanWidth = pivotSpan.width(); //calculate where the pivot word should be var pivotSpanLeftMargin = (paragraphWidth / 2) - (pivotSpanWidth / 2); //make global array of splittedSentence[0] preSpanArray = splittedSentence[0].split(' '); distributeWithinMargin(pivotSpanLeftMargin, this); //array not empty? while(preSpanArray.length > 0){ distributeWithinMargin(paragraphWidth, this); } }); } function distributeWithinMargin(margin, element) { var span = $("<span />", { 'style': 'margin-left: -40000px' }); $(element).prepend(span); while (preSpanArray.length > 0 && span.width() <= margin) { var lastElement = preSpanArray.pop(); span.prepend(lastElement + " "); } /* * last word makes the span too wide, so push it back to the stack * only do this when array not empty, or you will end up in an * endless loop */ if (preSpanArray.length > 0) { preSpanArray.push(lastElement); //remove that word from the span var firstSpaceIndex = $(span).html().indexOf(" "); $(span).html($(span).html().substring(firstSpaceIndex + 1)); } //calculate the text-indent from that value var textIndent = margin - span.width(); $(span).css('margin-left', textIndent); } pivotAround("PIVOT"); </script> </body> </html> 
Sign up to request clarification or add additional context in comments.

5 Comments

Interesting. I'll try it out.
It seems to be working. I got to admit I haven't managed to understand all of it yet (my js is a bit rusty). Well done.
Thank you. Feel free to ask for more info when needed.
can you explain how/why you use the global preSpanArray array?
That array is filled with all the words that have to be placed before the pivot word. I pop the last element off the array and prepend it in the span before the pivot word until the line is filled to its maximum. After that, repeat for the next line, until array is empty. Maybe it did not have to be global, but it was easy to do it like this.
1

So I've made a fiddle it's not totally finished and it has some bugs, each time you resize container you'll have to hit RUN button and if there are 2 lines above the pivot it starts to break, but it works in basics: http://jsfiddle.net/dFv3b/1/

HTML:

<div class="container"> <p>I am centered around my PIVOT word.</p> <p>Here is the PIVOT word of this second example.</p> <p>This is multiline text with one word which functions as the PIVOT then we have some more boring multiline text you don't have to worry about.</p> </div> 

JS/jQuery:

var containerWidth = $(".container").width(); $("p:contains('PIVOT')").html(function() { var text = $(this).html().split(' '); for( var i = 0, len = text.length; i < len; i++ ) { var p = ("PIVOT" == text[i]) ? " pivot" : ""; text[i] = '<span class="word-' + i + p + '">' + text[i] + '</span>';; } return text.join(' '); }).each(function() { var $pivot = $(this).find(".pivot"); var pivotPos = $pivot.offset().left; var pivotWidth = $pivot.width(); if (pivotPos + pivotWidth / 2 < containerWidth / 2) { // one line in the 1nd half $(this).css("text-indent", (containerWidth / 2) - (pivotWidth / 2) - pivotPos); } else { // multi line in the 2nd half var indent; // indent half width $(this).css("text-indent", containerWidth / 2); pivotPos = $pivot.offset().left; while (pivotPos + pivotWidth / 2 < containerWidth / 2) { var indent = Number($(this).css("text-indent").replace(/[^-\d\.]/g, '')); $(this).css("text-indent", indent + 1); pivotPos = $pivot.offset().left; } // return just before half $(this).css("text-indent", indent -1); pivotPos = $pivot.offset().left; var words = $(this).find("span").toArray(); var begin; // find the first word on pivot line for(var i=0, len=words.length; i<len; i++) { if (0 === $(words[i]).offset().left) { begin = words[i]; break; } } $(begin).css("margin-left", String((containerWidth /2) - (pivotWidth /2) - pivotPos) + "px"); } }); 

Comments

0

Finally I found a way to do this with tables. If you have different width of the table, you should play with the width value (must be equal in percent) of the left and right td-s.

<table width="700px"> <tr> <td style="width:47%;height:25px;text-align:right;overflow:hidden;whitespace: nowrap;">text</td> <td style="min-width:40px;width:40px;height:25px;">pivot</td> <td style="width:47%;height:25px;overflow:hidden;whitespace: nowrap;">text</td> </tr> <tr> <td style="width:47%;height:25px;text-align:right;overflow:hidden;whitespace: nowrap;">longer text tot the left</td> <td style="min-width:40px;width:40px;height:25px;">pivot</td> <td style="width:47%;height:25px;overflow:hidden;whitespace: nowrap;">short here</td> </tr> <tr> <td style="width:47%;height:25px;text-align:right;overflow:hidden;whitespace: nowrap;">sample</td> <td style="min-width:40px;width:40px;height:25px;">pivot</td> <td style="width:47%;height:25px;overflow:hidden;whitespace: nowrap;">text text text text text text text</td> </tr> </table> 

I also did a fiddle for you!

1 Comment

This won't work if the preceding / succeeding text goes over half a line, though. It's also not very maintainable.
0

I can think of a CSS-only solution, but it only works if the preceding and succeeding text doesn't go over a line. You can find it at http://jsfiddle.net/2UQhC/5/ (you will need to hit 'run' to see it properly).

The basic idea is this:

  • There is a parent container with position: relative
  • There is a para with the start of the sentence, and a para with the end of the sentence. Each contains a span at the start containing the pivot word.
  • Both paras are put into place with position:absolute. The start has right: 50% (so it's right edge is in the middle) and the end has left:50% likewise.
  • The spans in the paras are both floated towards the center.
  • The spans are then given pseudo-elements with percentage based negative margins, that push their respective containers to the center. The percentage-based widths use the widths of the containing floats (not the line block), meaning that the basis for these percentage widths will always be the real width of laying out the pivot word in whatever font or font size you choose.

Here's the code, in case that's too esoteric, using 'lilacs' as the pivot word:

The HTML -

<div> <p id="left"><span>LILACS</span>April is the cruellest month, breeding&nbsp;</p> <p id="right"><span>LILACS</span>&nbsp;out of the dead land</p> </div> 

And the CSS -

div { position: relative; } #left { position: absolute; right: 50%; } #right { position: absolute; left: 50%; } #left span { float: right; } #right span { float: left; visibility: hidden; } #left span:after { content: ""; margin-right: -50%; } #right span:before { content: ""; margin-left: -50%; } 

This will work whatever the widths of the two sides of the sentence (so long as they don't go to multiple lines), and should work from IE8 plus.

1 Comment

This is clever. But I'm really looking for a solution which also works if text is multi-line. Also, there are other consequences to duplicating the pivot word, e.g., searching (Ctrl-F) will find it twice. (Also, the words don't perfectly-overlap on my firefox...)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.