Авторазмер динамического текста для заполнения контейнера фиксированного размера - PullRequest
299 голосов
/ 27 марта 2009

Мне нужно отобразить введенный пользователем текст в div фиксированного размера. Я хочу, чтобы размер шрифта автоматически настраивался так, чтобы текст заполнял поле как можно больше.

Итак - если div составляет 400px x 300px. Если кто-то входит в ABC, то это действительно большой шрифт. Если они введут абзац, это будет крошечный шрифт.

Возможно, я бы хотел начать с максимального размера шрифта - возможно, 32 пикселя, и, хотя текст слишком велик, чтобы поместиться в контейнер, уменьшите размер шрифта до его соответствия.

Ответы [ 20 ]

1 голос
/ 21 января 2014

РЕДАКТИРОВАТЬ: Этот код был использован для отображения заметок в верхней части видео HTML5. Он изменяет размер шрифта на лету, когда размер видео изменяется (когда размер окна браузера изменяется.) Примечания были подключены к видео (так же, как заметки на YouTube), поэтому код использует экземпляры вместо дескриптора DOM непосредственно.

В соответствии с запросом, я добавлю код, который я использовал для достижения этой цели. (Текстовые поля над видео HTML5.) Код был написан очень давно, и я, честно говоря, считаю его довольно грязным. Поскольку на вопрос уже дан ответ, и ответ уже принят давно, я не перезаписываю его. Но если кто-то хочет немного упростить это, то мы будем рады!

// Figure out the text size:
var text = val['text'];
var letters = text.length;
var findMultiplier = function(x) { // g(x)
    /* By analysing some functions with regression, the resulting function that
     gives the best font size with respect to the number of letters and the size
     of the note is:
     g(x) = 8.3 - 2.75x^0.15 [1 < x < 255]
     f(x) = g(letters) * (x / 1000)^0.5
     Font size = f(size)
     */
    return 8.3 - 2.75 * Math.pow(x, 0.15);
};

var findFontSize = function(x) { // f(x)
    return findMultiplier(letters) * Math.pow(x / 1000, 0.5);
};

val.setFontSizeListener = function() {
    p.style.fontSize = '1px'; // So the text should not overflow the box when measuring.
    var noteStyle = window.getComputedStyle(table);
    var width = noteStyle.getPropertyValue('width');
    var height = noteStyle.getPropertyValue('height');
    var size = width.substring(0, width.length - 2) * height.substring(0, height.length - 2);
    p.style.fontSize = findFontSize(size) + 'px';
};
window.addEventListener('resize', val.setFontSizeListener);

Возможно, вам придется настроить эти числа от семейства шрифтов до семейства шрифтов. Хороший способ сделать это - загрузить бесплатный визуализатор графиков под названием GeoGebra. Измените длину текста и размер поля. Затем вы вручную устанавливаете размер. Представьте результаты ручного анализа в систему координат. Затем вы вводите два уравнения, которые я выложил здесь, и изменяете числа, пока «мой» график не будет соответствовать вашим собственным точкам, нанесенным вручную.

1 голос
/ 20 сентября 2013

Вы можете использовать FitText.js ( github page ) для решения этой проблемы. Действительно маленький и эффективный по сравнению с TextFill. TextFill использует дорогой цикл while, а FitText - нет.

Также FitText более гибок (я использую его в проекте с очень особыми требованиями и работает как чемпион!).

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>

Вы также можете установить параметры для него:

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

CSS:

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

И если вам это нужно, FitText также имеет no-jQuery версию .

1 голос
/ 14 июля 2013

Предлагаемые итеративные решения могут быть значительно ускорены по двум направлениям:

1) Умножьте размер шрифта на некоторую константу, а не добавляя или вычитая 1.

2) Во-первых, ноль при использовании константы курса, скажем, удвоить размер каждой петли. Затем, имея приблизительное представление о том, с чего начать, проделайте то же самое с более точной настройкой, скажем, умножьте на 1,1. Хотя перфекционисту может потребоваться точный целочисленный размер пикселя для идеального шрифта, большинство наблюдателей не замечают разницы между 100 и 110 пикселями. Если вы перфекционист, повторите третий раз с еще более точной настройкой.

Вместо того, чтобы писать конкретную подпрограмму или плагин, который отвечает на точный вопрос, я просто полагаюсь на основные идеи и пишу варианты кода для решения всех видов проблем компоновки, а не только текста, включая подгонку div, span, изображения, ... по ширине, высоте, площади, ... внутри контейнера, соответствующие другому элементу ....

Вот пример:

  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');
1 голос
/ 22 сентября 2012

Вот версия принятого ответа, которая также может принимать параметр minFontSize.

(function($) {
    /**
    * Resizes an inner element's font so that the inner element completely fills the outer element.
    * @author Russ Painter WebDesign@GeekyMonkey.com
    * @author Blake Robertson 
    * @version 0.2 -- Modified it so a min font parameter can be specified.
    *    
    * @param {Object} Options which are maxFontPixels (default=40), innerTag (default='span')
    * @return All outer elements processed
    * @example <div class='mybigdiv filltext'><span>My Text To Resize</span></div>
    */
    $.fn.textfill = function(options) {
        var defaults = {
            maxFontPixels: 40,
            minFontPixels: 10,
            innerTag: 'span'
        };
        var Opts = jQuery.extend(defaults, options);
        return this.each(function() {
            var fontSize = Opts.maxFontPixels;
            var ourText = $(Opts.innerTag + ':visible:first', this);
            var maxHeight = $(this).height();
            var maxWidth = $(this).width();
            var textHeight;
            var textWidth;
            do {
                ourText.css('font-size', fontSize);
                textHeight = ourText.height();
                textWidth = ourText.width();
                fontSize = fontSize - 1;
            } while ((textHeight > maxHeight || textWidth > maxWidth) && fontSize > Opts.minFontPixels);
        });
    };
})(jQuery);
0 голосов
/ 27 декабря 2018

Я нашел способ предотвратить использование циклов для сжатия текста. Он корректирует размер шрифта, умножая его на коэффициент между шириной контейнера и шириной содержимого. Поэтому, если ширина контейнера составляет 1/3 содержимого, размер шрифта будет уменьшен на 1/3 и будет иметь ширину контейнера. Чтобы увеличить масштаб, я использовал цикл while, пока содержимое не будет больше контейнера.

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'; 
            }
        }
    }
}

Этот код является частью теста, который я загрузил на Github https://github.com/ricardobrg/fitText/

0 голосов
/ 11 декабря 2018

Просто хотел добавить мою версию для 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>
0 голосов
/ 16 апреля 2018

Мне понравилось

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));
0 голосов
/ 11 июня 2017

У меня та же проблема, и решение в основном заключается в использовании javascript для управления размером шрифта. Проверьте этот пример на codepen:

https://codepen.io/ThePostModernPlatonic/pen/BZKzVR

Это пример только для высоты, может быть, вам нужно поставить некоторые, если примерно ширина.

попробуйте изменить его размер

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Documento sem título</title>
<style>
</style>
</head>
<body>
<div style="height:100vh;background-color: tomato;" id="wrap">        
  <h1 class="quote" id="quotee" style="padding-top: 56px">Because too much "light" doesn't <em>illuminate</em> our paths and warm us, it only blinds and burns us.</h1>
</div>
</body>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script>
  var multiplexador = 3;
  initial_div_height = document.getElementById ("wrap").scrollHeight;
  setInterval(function(){ 
    var div = document.getElementById ("wrap");
    var frase = document.getElementById ("quotee");
    var message = "WIDTH div " + div.scrollWidth + "px. "+ frase.scrollWidth+"px. frase \n";
    message += "HEIGHT div " + initial_div_height + "px. "+ frase.scrollHeight+"px. frase \n";           
    if (frase.scrollHeight < initial_div_height - 30){
      multiplexador += 1;
      $("#quotee").css("font-size", multiplexador); 
    }
    console.log(message);          
  }, 10);
</script>
</html>
0 голосов
/ 23 февраля 2017

я знаю, что это старый, но все еще есть люди, которым нужна эта функциональность. Я пошел с решением GeekMonkey, но его удар. просто потому что это медленно. что он делает, он устанавливает максимальный размер шрифта (maxFontPixels) и затем проверяет, подходит ли он внутри контейнера. иначе это уменьшает размер шрифта на 1 пиксель и проверяет снова. почему бы просто не проверить предыдущий контейнер на высоту и передать это значение ?? (да, я знаю почему, но теперь я принял решение, которое работает только на высоте и также имеет опцию min / max)

гораздо более быстрое решение:

var index_letters_resize;
(index_letters_resize = function() {
  $(".textfill").each(function() {
    var
      $this = $(this),
      height = Math.min( Math.max( parseInt( $this.height() ), 40 ), 150 );
    $this.find(".size-adjust").css({
      fontSize: height
    });
  });
}).call();

$(window).on('resize', function() {
  index_letters_resize();
);

и это будет HTML:

<div class="textfill">
  <span class="size-adjust">adjusted element</span>
  other variable stuff that defines the container size
</div>

еще раз: это решение ТОЛЬКО проверяет высоту контейнера. вот почему эта функция не должна проверять, подходит ли элемент внутрь. но я также реализовал минимальное / максимальное значение (40 мин, 150 макс.), поэтому для меня это прекрасно работает (а также работает с изменением размера окна).

0 голосов
/ 04 июня 2014

Вот еще одна версия этого решения:

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";
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...