简体   繁体   中英

How to set font size for a paragraph whose content is being constantly replaced

I want to set a box with a paragraph in it. The text of this paragraph is supposed to be replaced after every time I click on the button. And what is important to me is that this text should stay inside the box as a one line and not break. To do that I decided to use FitText.js plugin because words have different lengths (given words are just an example). By setting it as a table and table-cell I've achieved a nice align (both vertical and horizontal). Do you have any ideas why given code doesn't work as it should?

 var words = ["Emily", "William Callum Smith Jr.", "Edwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaard", "Bradley"]; var button1 = document.getElementById("give_me_a_name_please"); button1.addEventListener("click", function1); function getRandomItem(array){ return array.splice(Math.floor(Math.random() * array.length), 1)[0]; } function function1(){ var randomWord = getRandomItem(words); document.getElementById('word').innerHTML = randomWord; } $('#give_me_a_name_please').click(function() { function resize () { $("#word").fitText(0.6); } }); 
 #parent_of_word { width: 20%; height: 20%; top: 10%; left: 10%; display: flex; position: absolute; text-align: center; justify-content: center; line-height: 100%; border: 5px solid black; word-break: keep-all; white-space: nowrap; } #word { color: brown; display:flex; align-items: center; justify-content: center; } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <script src="https://cdn.rawgit.com/davatron5000/FitText.js/0b4183af/jquery.fittext.js"></script> <div id="parent_of_word"> <p id="word">----------------</p> </div> <button id="give_me_a_name_please">Button</button> 

Edit: updated code snippet and JSFiddle with a more optimal loop.

I've adapted your example code to be a bit leaner and easier to understand. It also uses pure jQuery instead of a mix of jQuery and pure JS and won't stop at 'undefined' after pressing the button several times, resulting in an empty array. It will instead cycle through all the words again.

There are two main solutions in effect here.

  • One takes inspiration from this iterative approach to JavaScript Scale Text to Fit in Fixed Div where the font size starts at a fixed value, then scales down as necessary until the word's width is less than its container's width. No need for a plugin as this is extremely trivial.
  • The second part implements overflow:hidden so that in the event that the text is so massive that it cannot possibly be shrunk small enough (see the lower limit of 8 in the while-loop), it will still not break out of its container.

See also the JSFiddle version .

 var words = [ "Emily", "William Callum Smith Jr.", "Edwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaard", "EdwaaaaaaaaaaaaaaaaaaaAAAAAAAAAaaaaaAAaaaaAAAaaaaaaaaaaaaaaaaaaaaaaaaard", "Bradley", "The quick brown fox" ]; var changeWord = $("#change_word"); var parentOfWord = $("#parent_of_word"); var word = $("#word"); var idx = 0; changeWord.click(function() { word.text(words[idx++ % words.length]); var size = 40; word.css("font-size", size); while (word.width() > parentOfWord.width() && size > 8) { word.css("font-size", --size); } }); 
 #parent_of_word { width: 200px; height: 50%; top: 50px; left: 50%; margin-left: -100px; display: flex; position: absolute; text-align: center; justify-content: center; line-height: 100%; border: 5px solid black; word-break: keep-all; white-space: nowrap; overflow: hidden; } #word { color: brown; display: flex; align-items: center; justify-content: center; } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <p> <button id="change_word">Button</button> </p> <div id="parent_of_word"> <p id="word">----------------</p> </div> 

To have your text in one line, without breaking:

white-space: nowrap;

To center anything vertically and horizontally:

display:flex;
align-items: center;
justify-content: center;

Applied to your example:

 var words = ["Emily", "William Callum Smith Jr.", "Edwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaard", "Resize this to see how it behaves on narrower screens. Lorem ipsum dolor sit amet bla bla bla, lorem ipsum dolor sit amet bla bla bla, lorem ipsum dolor sit amet bla bla bla.", "Bradley"]; var button1 = document.getElementById("give_me_a_name_please"); button1.addEventListener("click", function1); function getRandomItem(array){ return array.splice(Math.floor(Math.random() * array.length), 1)[0]; } function function1(){ var randomWord = getRandomItem(words) || 'No more options.'; document.getElementById('word').innerHTML = randomWord; } $( '#give_me_a_name_please' ).click(function() { function resize () { $("#word").fitText(0.6); } }); 
 #parent_of_word { display: flex; align-items: center; justify-content: center; /* rest optional, just to demo * vertical alignment */ height: calc(100vh - 40px); border: 1px solid red; padding: 1rem; } #word { white-space: nowrap; border: 5px solid; padding: 1rem; flex: 0 1 auto; max-width: 100%; overflow: hidden; text-overflow: ellipsis; } * { margin: 0; box-sizing: border-box; } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <script src="https://cdn.rawgit.com/davatron5000/FitText.js/0b4183af/jquery.fittext.js"></script> <div id="parent_of_word"> <p id="word">----------------</p> </div> <button id="give_me_a_name_please">Button</button> 

It's because you've defined the width of the #parent_of_word to be 20% , which of course is related to its parent element , ie the body element, based on the given example.

So the width of the #parent_of_word can't be just resized dynamically based on the width of its content . It can only be "visually resized" together with its parent width , but still, it will take 20% of it. Even though the used unit are % and the element's width is dynamic , it's still fixed.

So my solution would be to omit the width property and just define the padding of your choice:

Note: I've commented out the unnecessary.

 var words = ["Emily", "William Callum Smith Jr.", "Edwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaard", "Bradley"]; var button1 = document.getElementById("give_me_a_name_please"); button1.addEventListener("click", function1); function getRandomItem(array) { return array.splice(Math.floor(Math.random() * array.length), 1)[0]; } function function1() { var randomWord = getRandomItem(words); document.getElementById('word').innerHTML = randomWord; } $('#give_me_a_name_please').click(function() { function resize() { $("#word").fitText(0.6); } }); 
 #parent_of_word { display: flex; /*width: 20%; the culprit*/ height: 20%; padding: 0 20px; /* can also use [%] */ position: absolute; top: 10%; left: 10%; /*text-align: center;*/ justify-content: center; align-items: center; /* added; vertical alignment */ /*line-height: 100%;*/ border: 5px solid black; /* word-break: keep-all; white-space: nowrap; */ color: brown; } /* #word { color: brown; display: flex; align-items: center; justify-content: center; } */ 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <script src="https://cdn.rawgit.com/davatron5000/FitText.js/0b4183af/jquery.fittext.js"></script> <button id="give_me_a_name_please">Button</button> <div id="parent_of_word"> <p id="word">----------------</p> </div> 

Simplest solution to your problem is to change the #parent_of_word 's width value to width:auto . This'll have the width automatically adjust depending on the content (auto adjusts depending on the length of the paragraph).

Working example: https://jsfiddle.net/18faLbap/4/

I usually do it by this approach when I want to keep text in a line. especially I grids. So no matter how long your box is, it will be in one line and when you hover on it, it will bread to lines to be readable.

 var words = ["Emily", "William Callum Smith Jr.", "Edwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaard", "Bradley"]; var button1 = document.getElementById("give_me_a_name_please"); button1.addEventListener("click", function1); function getRandomItem(array){ return array.splice(Math.floor(Math.random() * array.length), 1)[0]; } function function1(){ var randomWord = getRandomItem(words); document.getElementById('word').innerHTML = randomWord; } $('#give_me_a_name_please').click(function() { function resize () { $("#word").fitText(0.6); } }); 
 #parent_of_word { width: 20%; top: 10%; left: 10%; display: flex; position: absolute; text-align: center; justify-content: center; line-height: 100%; border: 5px solid black; word-break: keep-all; } #word { text-overflow: ellipsis; white-space: nowrap; overflow: hidden; color: brown; display:flex; align-items: center; justify-content: center; } #word:hover { white-space: normal; } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <script src="https://cdn.rawgit.com/davatron5000/FitText.js/0b4183af/jquery.fittext.js"></script> <div id="parent_of_word"> <p id="word">----------------</p> </div> <button id="give_me_a_name_please">Button</button> 

#parent_of_word {
    min-width: 20%;
    width: auto;
    padding: 0px 20px;
}

All I've done here is add on width: auto and set a min-width:20% . This makes the width dynamic when the text updates inside the box. Added in a little padding to make it look nice too. Hope this helps.

Seeing as you already have jQuery on the page, consider using the jquery-textfill plugin:

http://jquery-textfill.github.io/

It will ensure your text fits to your container.

There is a CSS way to fit words in the content

I basically disable the absolute width of your #parent_of_word and change the display to inline-block , so that its width will fit its content. To make it more beautiful, I add padding property. The reduced and improved version of your code is shown below.

 var words = ["Emily", "William Callum Smith Jr.", "Edwaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaard", "Bradley"]; var button1 = document.getElementById("give_me_a_name_please"); button1.addEventListener("click", function1); function getRandomItem(array){ return array.splice(Math.floor(Math.random() * array.length), 1)[0]; } function function1(){ var randomWord = getRandomItem(words); document.getElementById('word').innerHTML = randomWord; } 
 #parent_of_word { top: 10%; left: 10%; display: inline-block; position: absolute; text-align: center; padding: 10px; border: 5px solid black; word-break: keep-all; } #word { text-overflow: ellipsis; white-space: nowrap; overflow: hidden; color: brown; display:flex; align-items: center; justify-content: center; } #word:hover { white-space: normal; } 
 <div id="parent_of_word"> <p id="word">----------------</p> </div> <button id="give_me_a_name_please">Button</button> 

So you no longer need the extra JavaScript library now. More knowledge can be found here

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