简体   繁体   中英

How can I evenly balance text over multiple lines?

I'd like to display a short piece of text that may wrap to two or three lines. It's inside a highly visual element and for styling purposes I'd like the lines to be as equal in length as possible, preferring one line over two.

Instead of this:

This is an example of a piece of text that will wrap to two

lines.

I want this:

This is an example of a piece of

text that will wrap to two lines.

But I don't want to limit the width of the text container:

This text is long enough to just barely fit in two lines. It

should not wrap to three or more lines so no width limiting.

Is there a way to do this in pure CSS or with a tolerable amount of JavaScript?

The CSS Text Module 4 property:

 text-wrap: balance;

will do this. https://drafts.csswg.org/css-text-4/#text-wrap

There's also a package which implements a polyfill for existing browsers.

Here's ademo of balance text . [ Archived copy ]

If I understand what you're asking (and if I do, the general theme of 'use justify' doesn't quite do it), I don't think you'll be able to avoid writing a fair bit of JavaScript.

The only way I can see to do what you're asking would be to compare the width of the text to the width of the container, and adjust accordingly.

Formula: Width of a single line = width of text / roundUp(width of text/width of container)

ie (probably needs some adjustment to prevent it cutting words in half)

var widthOfText = functionToGetWidthOfText(width); //==120
var widthOfContainer = container.width(); //==100
var containerWidth = widthOfText / ceil(widthOfText/widthOfContainer);
// containerWidth = 120 / ceil(120/100) == 120 / 2 == 60
var formattingTextContainer.width = containerWidth
// text would go inside the formattingTextContainer, which would
// give you 2 lines of equal, 60px width

However, the issue with this is, making a "functionToGetWidthOfText". After some quick searching, all I have found is this stack overflow question where the answer is to...

Wrap text in a span and use jquery width()

ie put it in an element and measure how wide it is...you might be able to do that off-screen somewhere/delete it after fast enough no-one sees it, but that will probably take quite a few lines of JavaScript. (I might investigate this more after work...)

The reason you can't flat-out figure out the width without rendering it is due to the various font types and sizes that it could be represented with. So if you are always using an exact font-type and font-size, you might be able to write a function that does it without rendering it.

I created an exmaple with text-align: justify and without text-align: justify.

Have a look at:

 .center {width:200px; float:left; margin-left: 20px;}.justify { text-align: justify; }
 <.-- 4, --> <section class="center"> <p class="justify">orem ipsum dolor sit amet, consectetur adipisici elit. sed eiusmod tempor incidunt ut labore et dolore magna aliqua, Ut enim ad minim veniam. quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur, Excepteur sint obcaecat cupiditat non proident. sunt in culpa qui officia deserunt mollit anim id est laborum,</p> </section> <section class="center"> <p class="">orem ipsum dolor sit amet, consectetur adipisici elit. sed eiusmod tempor incidunt ut labore et dolore magna aliqua, Ut enim ad minim veniam. quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur, Excepteur sint obcaecat cupiditat non proident. sunt in culpa qui officia deserunt mollit anim id est laborum.</p> </section>

Since there seems to be no ready solutions available, I wrote a relatively simple jQuery function to do what I want. Here it is in case someone else is looking for one.

It works by cloning the element we want to adjust. The clone is hidden to prevent it from blinking when it is injected to the DOM. We then make the clone narrower one pixel at a time until it has to wrap. The width right before that happens is then set to the original element and the clone element is removed.

Better ways to achieve this are still welcome, as are suggestions to improve this one. Codepen is available here: http://codepen.io/Kaivosukeltaja/pen/jWYqZN

 function adjust() { $('.quote').each(function() { // Create an invisible clone of the element var clone = $(this).clone().css({ visibility: 'hidden', width: 'auto' }).appendTo($(this).parent()); // Get the bigger width of the two elements to be our starting point var goodWidth = Math.max($(this).width(), $(clone).width()); var testedWidth = goodWidth; var initialHeight = $(clone).height(); // Make the clone narrower until it wraps again, causing height to increase while($(clone).height() == initialHeight && testedWidth > 0) { goodWidth = testedWidth; testedWidth--; $(clone).width(testedWidth); } // Set original element's width to last one before wrap $(this).width(goodWidth); // Remove the clone element $(clone).remove(); }); } $(window).resize(adjust); $(document).ready(function() { adjust(); });
 body { background-color: #f0f0f0; }.holder { text-align: center; margin: 2em auto; }.quote { display: inline-block; border: 1px solid #c0c0c0; background-color: #fff; padding: 1em; font-size: 40px; }
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div class="holder"> <div class="quote"> If I want text to wrap, I want the lines as close to equal length as possible. </div> </div>

You can use a parent tag like DIV and style that with width=50%. That would made the text in more lines.

I am afraid there is no way of doing that in CSS so I just searched it and found it here split-large-string-in-n-size-chunks-in-javascript AND counting-words-in-string

I am going to take this as a challenge and write a function for it:)

try and regex the number of words and find the length of half of that then this:

function chunkString(str, length) {
  length = length/2;
  return str.match(new RegExp('.{1,' + length + '}', 'g'));
}

.....

text-align: justify . I am not sure if i got the question right but looking at your reputation I am scared to answer this:! :)

put the text in ap, or span, make sure it is display: block , inline-block will do the job as well. width of the each element should be 50% of the parent element. then text-align: justify the child element.

You can put the text into a div and use both width and text-align css properties:

 #center{ width: 100px; text-align: justify; }
 <div id="center">This is an example of a piece of text that will wrap to two lines.This is an example of a piece of text that will wrap to two lines.</div>

Just shorten the width of the element holding this text:

 div { width: 210px; }
 <div>This is an example of a piece of text that will wrap to two lines.</div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM