Auto-size dynamic text to fill fixed size containe

2018-12-31 02:06发布

I need to display user entered text into a fixed size div. What i want is for the font size to be automatically adjusted so that the text fills the box as much as possible.

So - If the div is 400px x 300px. If someone enters ABC then it's really big font. If they enter a paragraph, then it would be a tiny font.

I'd probably want to start with a maximum font size - maybe 32px, and while the text is too big to fit the container, shrink the font size until it fits.

标签: jquery html css
20条回答
唯独是你
2楼-- · 2018-12-31 02:35

I did like

let name = "Making statements based on opinion; back them up with references or personal experience."
let originFontSize = 15;
let maxDisplayCharInLine = 50; 
let fontSize = Math.min(originFontSize, originFontSize / (name.length / maxDisplayCharInLine));
查看更多
看淡一切
3楼-- · 2018-12-31 02:36

Here is another version of this solution:

shrinkTextInElement : function(el, minFontSizePx) {
    if(!minFontSizePx) {
        minFontSizePx = 5;
    }
    while(el.offsetWidth > el.parentNode.offsetWidth || el.offsetHeight > el.parentNode.offsetHeight) {

        var newFontSize = (parseInt(el.style.fontSize, 10) - 3);
        if(newFontSize <= minFontSizePx) {
            break;
        }

        el.style.fontSize = newFontSize + "px";
    }
}
查看更多
ら面具成の殇う
4楼-- · 2018-12-31 02:37

Just wanted to add my version for contenteditables.

$.fn.fitInText = function() {
  this.each(function() {

    let textbox = $(this);
    let textboxNode = this;

    let mutationCallback = function(mutationsList, observer) {
      if (observer) {
        observer.disconnect();
      }
      textbox.css('font-size', 0);
      let desiredHeight = textbox.css('height');
      for (i = 12; i < 50; i++) {
        textbox.css('font-size', i);
        if (textbox.css('height') > desiredHeight) {
          textbox.css('font-size', i - 1);
          break;
        }
      }

      var config = {
        attributes: true,
        childList: true,
        subtree: true,
        characterData: true
      };
      let newobserver = new MutationObserver(mutationCallback);
      newobserver.observe(textboxNode, config);

    };

    mutationCallback();

  });
}

$('#inner').fitInText();
#outer {
  display: table;
  width: 100%;
}

#inner {
  border: 1px solid black;
  height: 170px;
  text-align: center;
  display: table-cell;
  vertical-align: middle;
  word-break: break-all;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="outer">
  <div id="inner" contenteditable=true>
    TEST
  </div>
</div>

查看更多
春风洒进眼中
5楼-- · 2018-12-31 02:38

I have found a way to prevent the use of loops to shrink the text. It adjusts the font-size by multiplying it for the rate between container's width and content width. So if the container's width is 1/3 of the content, the font-size will be reduced by 1/3 and will container's width. To scale up, I have used a while loop, until content is bigger than container.

function fitText(outputSelector){
    // max font size in pixels
    const maxFontSize = 50;
    // get the DOM output element by its selector
    let outputDiv = document.getElementById(outputSelector);
    // get element's width
    let width = outputDiv.clientWidth;
    // get content's width
    let contentWidth = outputDiv.scrollWidth;
    // get fontSize
    let fontSize = parseInt(window.getComputedStyle(outputDiv, null).getPropertyValue('font-size'),10);
    // if content's width is bigger than elements width - overflow
    if (contentWidth > width){
        fontSize = Math.ceil(fontSize * width/contentWidth,10);
        fontSize =  fontSize > maxFontSize  ? fontSize = maxFontSize  : fontSize - 1;
        outputDiv.style.fontSize = fontSize+'px';   
    }else{
        // content is smaller than width... let's resize in 1 px until it fits 
        while (contentWidth === width && fontSize < maxFontSize){
            fontSize = Math.ceil(fontSize) + 1;
            fontSize = fontSize > maxFontSize  ? fontSize = maxFontSize  : fontSize;
            outputDiv.style.fontSize = fontSize+'px';   
            // update widths
            width = outputDiv.clientWidth;
            contentWidth = outputDiv.scrollWidth;
            if (contentWidth > width){
                outputDiv.style.fontSize = fontSize-1+'px'; 
            }
        }
    }
}

This code is part of a test that I have uploaded to Github https://github.com/ricardobrg/fitText/

查看更多
浪荡孟婆
6楼-- · 2018-12-31 02:38

The proposed iterative solutions can be sped up dramatically on two fronts:

1) Multiply the font size by some constant, rather than adding or subtracting 1.

2) First, zero in using a course constant, say, double the size each loop. Then, with a rough idea of where to start, do the same thing with a finer adjustment, say, multiply by 1.1. While the perfectionist might want the exact integer pixel size of the ideal font, most observers don't notice the difference between 100 and 110 pixels. If you are a perfectionist, then repeat a third time with an even finer adjustment.

Rather than writing a specific routine or plug-in that answers the exact question, I just rely on the basic ideas and write variations of the code to handle all kinds of layout issues, not just text, including fitting divs, spans, images,... by width, height, area,... within a container, matching another element....

Here's an example:

  var                           nWindowH_px             = jQuery(window).height();
  var                           nWas                    = 0;
  var                           nTry                    = 5;

  do{
   nWas = nTry;
   nTry *= 2;
   jQuery('#divTitle').css('font-size' ,nTry +'px');
  }while( jQuery('#divTitle').height() < nWindowH_px );

  nTry = nWas;

  do{
   nWas = nTry;
   nTry = Math.floor( nTry * 1.1 );
   jQuery('#divTitle').css('font-size' ,nTry +'px');
  }while( nWas != nTry   &&   jQuery('#divTitle').height() < nWindowH_px );

  jQuery('#divTitle').css('font-size' ,nWas +'px');
查看更多
路过你的时光
7楼-- · 2018-12-31 02:39

You can use FitText.js (github page) to solve this problem. Is really small and efficient compared to TextFill. TextFill uses an expensive while loop and FitText don't.

Also FitText is more flexible (I use it in a proyect with very special requirements and works like a champ!).

HTML:

<div class="container">
  <h1 id="responsive_headline">Your fancy title</h1>
</div>

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script src="jquery.fittext.js"></script>
<script>
  jQuery("#responsive_headline").fitText();
</script>

You also can set options to it:

<script>
  jQuery("#responsive_headline").fitText(1, { minFontSize: '30px', maxFontSize: '90px'});
</script>

CSS:

#responsive_headline {
   width: 100%;
   display: block;
}

And if you need it, FitText also has a no-jQuery version.

查看更多
登录 后发表回答