Авторазмер динамического текста для заполнения контейнера фиксированного размера

296

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

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

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

  • 114
    Вероятно, одна из самых удивительных функций, которые должны были быть добавлены в HTML5 / CSS3 без необходимости JS.
  • 0
    Я провел некоторые измерения, в которых я изменил длину динамического текста и размер контейнера, чтобы выяснить, какой размер шрифта сделает текст идеально подходящим. И после некоторого регрессионного анализа я придумал простую математическую функцию, которая автоматически генерирует лучший размер шрифта.
Показать ещё 10 комментариев
Теги:

19 ответов

152
Лучший ответ

Спасибо Атака. Я хотел использовать jQuery.

Вы указали мне в правильном направлении, и это то, с чем я закончил:

Вот ссылка на плагин: https://plugins.jquery.com/textfill/
И ссылка на источник: http://jquery-textfill.github.io/

;(function($) {
    $.fn.textfill = function(options) {
        var fontSize = options.maxFontPixels;
        var ourText = $('span: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 > 3);
        return this;
    }
})(jQuery);

$(document).ready(function() {
    $('.jtextfill').textfill({ maxFontPixels: 36 });
});

и мой html выглядит следующим образом

<div class='jtextfill' style='width:100px;height:50px;'>
    <span>My Text Here</span>
</div>

Это мой первый плагин jquery, поэтому он, вероятно, не так хорош, как должен. Указатели, безусловно, приветствуются.

  • 8
    Я на самом деле просто очистил его и упаковал как плагин, доступный на jquery.com по адресу plugins.jquery.com/project/TextFill
  • 2
    @ GeekyMonkey, ты вытащил плагин? Просто перешел на двойную ссылку на эту страницу и подумал, что посмотрю, но ссылки jQuery.com на ваш сайт возвращают 404 .
Показать ещё 13 комментариев
51

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

Согласно этот тест производительности, он намного быстрее, чем другие найденные здесь решения.

(function($) {
    $.fn.textfill = function(maxFontSize) {
        maxFontSize = parseInt(maxFontSize, 10);
        return this.each(function(){
            var ourText = $("span", this),
                parent = ourText.parent(),
                maxHeight = parent.height(),
                maxWidth = parent.width(),
                fontSize = parseInt(ourText.css("fontSize"), 10),
                multiplier = maxWidth/ourText.width(),
                newSize = (fontSize*(multiplier-0.1));
            ourText.css(
                "fontSize", 
                (maxFontSize > 0 && newSize > maxFontSize) ? 
                    maxFontSize : 
                    newSize
            );
        });
    };
})(jQuery);

Если вы хотите внести свой вклад, я добавил это в Gist.

  • 0
    Хороший сценарий, но я думаю, что ОП ищет заполнение всего текстового поля, а не просто помещает одну строку текста по горизонтали. Похоже, это то, что делает Fiddle в вашей ссылке Gist.
  • 1
    @ Джон, спасибо! Вы правы в том, что мой сценарий не содержит нескольких строк, но опять-таки ОП не просил об этом, поэтому ваше предположение может быть неверным. Кроме того, такого рода поведение не имеет особого смысла. Я полагаю, что лучший способ добавить многострочную поддержку - разделить строку на основе количества слов, а затем вычислить каждую часть с помощью приведенного выше сценария, и это, скорее всего, будет быстрее в любом случае.
Показать ещё 13 комментариев
31

Большинство других ответов используют цикл, чтобы уменьшить размер шрифта до тех пор, пока он не подходит для div, это ОЧЕНЬ медленно, так как страница должна повторно отображать элемент каждый раз, когда размер шрифта изменяется. В конечном итоге мне пришлось написать свой собственный алгоритм, чтобы он выполнялся таким образом, чтобы я мог периодически обновлять его содержимое, не замораживая пользовательский браузер. Я добавил некоторые другие функции (вращающийся текст, добавление дополнений) и упаковал его как плагин jQuery, вы можете получить его по адресу:

https://github.com/DanielHoffmann/jquery-bigtext

просто вызовите

$("#text").bigText();

и он будет хорошо вписываться в ваш контейнер.

Смотрите здесь:

http://danielhoffmann.github.io/jquery-bigtext/

Теперь, когда он имеет некоторые ограничения, div должен иметь фиксированную высоту и ширину и не поддерживает перенос текста на несколько строк.

Я буду работать над настройкой максимального размера шрифта.

Изменить: я нашел еще некоторые проблемы с плагином, он не обрабатывает другую коробку, кроме стандартной, и div не может иметь поля или границы. Я буду работать над этим.

Edit2: Я исправил эти проблемы и ограничения и добавил дополнительные параметры. Вы можете установить максимальный размер шрифта, и вы также можете ограничить размер шрифта, используя либо ширину, высоту, либо и то, и другое. Я буду работать с принятием значений max-width и max-height в оберточном элементе.

Edit3: я обновил плагин до версии 1.2.0. Основная очистка кода и новых параметров (verticalAlign, horizontalAlign, textAlign) и поддержка внутренних элементов внутри тега span (например, разрывы строк или значки шрифта).

  • 1
    Мне интересно, почему не поддерживается перенос текста в несколько строк?
  • 1
    @ManishSapariya Поддерживается, но вам нужно добавить разрывы строк (теги br) вручную. Причина, по которой я не поддерживаю автоматическое перенос текста, заключается в том, что для его быстрого выполнения (меняйте размер шрифта только дважды, а не несколько раз), мне нужно сделать предположение, что текст не будет переноситься между словами. Мой плагин работает так, чтобы установить размер шрифта равным 1000 пикселей, а затем посмотреть, какой размер текста сравнивается с контейнером, а затем уменьшить размер шрифта на тот же коэффициент. Для поддержки обычного переноса текста мне нужно будет использовать медленный подход (уменьшить размер шрифта в несколько раз), который очень медленный.
Показать ещё 5 комментариев
30

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


Тем не менее, для справки, здесь мой оригинальный ответ:

<html>
<head>
<style type="text/css">
    #dynamicDiv
    {
    background: #CCCCCC;
    width: 300px;
    height: 100px;
    font-size: 64px;
    overflow: hidden;
    }
</style>

<script type="text/javascript">
    function shrink()
    {
        var textSpan = document.getElementById("dynamicSpan");
        var textDiv = document.getElementById("dynamicDiv");

        textSpan.style.fontSize = 64;

        while(textSpan.offsetHeight > textDiv.offsetHeight)
        {
            textSpan.style.fontSize = parseInt(textSpan.style.fontSize) - 1;
        }
    }
</script>

</head>
<body onload="shrink()">
    <div id="dynamicDiv"><span id="dynamicSpan">DYNAMIC FONT</span></div>
</body>
</html>

И здесь версия с классами:

<html>
<head>
<style type="text/css">
.dynamicDiv
{
    background: #CCCCCC;
    width: 300px;
    height: 100px;
    font-size: 64px;
    overflow: hidden;
}
</style>

<script type="text/javascript">
    function shrink()
    {
        var textDivs = document.getElementsByClassName("dynamicDiv");
        var textDivsLength = textDivs.length;

        // Loop through all of the dynamic divs on the page
        for(var i=0; i<textDivsLength; i++) {

            var textDiv = textDivs[i];

            // Loop through all of the dynamic spans within the div
            var textSpan = textDiv.getElementsByClassName("dynamicSpan")[0];

            // Use the same looping logic as before
            textSpan.style.fontSize = 64;

            while(textSpan.offsetHeight > textDiv.offsetHeight)
            {
                textSpan.style.fontSize = parseInt(textSpan.style.fontSize) - 1;
            }

        }

    }
</script>

</head>
<body onload="shrink()">
    <div class="dynamicDiv"><span class="dynamicSpan">DYNAMIC FONT</span></div>
    <div class="dynamicDiv"><span class="dynamicSpan">ANOTHER DYNAMIC FONT</span></div>
    <div class="dynamicDiv"><span class="dynamicSpan">AND YET ANOTHER DYNAMIC FONT</span></div>
</body>
</html>
  • 3
    Я нашел, что это работает лучше с offsetWidth , мне также пришлось создать переменную для размера, а затем добавить px textSpan.style.fontSize = size+"px";
  • 2
    обязательно '+ "px"' необходимо.
Показать ещё 3 комментария
9

Это основано на том, что GeekyMonkey опубликовал выше, с некоторыми изменениями.

; (function($) {
/**
* Resize inner element to fit the outer element
* @author Some modifications by Sandstrom
* @author Code based on earlier works by Russ Painter ([email protected])
* @version 0.2
*/
$.fn.textfill = function(options) {

    options = jQuery.extend({
        maxFontSize: null,
        minFontSize: 8,
        step: 1
    }, options);

    return this.each(function() {

        var innerElements = $(this).children(':visible'),
            fontSize = options.maxFontSize || innerElements.css("font-size"), // use current font-size by default
            maxHeight = $(this).height(),
            maxWidth = $(this).width(),
            innerHeight,
            innerWidth;

        do {

            innerElements.css('font-size', fontSize);

            // use the combined height of all children, eg. multiple <p> elements.
            innerHeight = $.map(innerElements, function(e) {
                return $(e).outerHeight();
            }).reduce(function(p, c) {
                return p + c;
            }, 0);

            innerWidth = innerElements.outerWidth(); // assumes that all inner elements have the same width
            fontSize = fontSize - options.step;

        } while ((innerHeight > maxHeight || innerWidth > maxWidth) && fontSize > options.minFontSize);

    });

};

})(jQuery);
  • 0
    Разница в том, что он может принимать несколько дочерних элементов и учитывать отступы. Использует размер шрифта в качестве максимального размера по умолчанию, чтобы избежать смешивания JavaScript и CSS.
  • 5
    Это здорово, но как мне это использовать? Я делаю $ ('. External'). Textfill (); и я не получаю изменений.
Показать ещё 1 комментарий
6

Здесь улучшенный метод циклирования, который использует бинарный поиск, чтобы найти максимально возможный размер, который вписывается в родительский элемент в наименьшие возможные шаги (это быстрее и точнее, чем наложение фиксированного размера шрифта). Код также оптимизирован несколькими способами для производительности.

По умолчанию будет выполнено 10 шагов бинарного поиска, которые будут находиться в пределах 0,1% от оптимального размера. Вместо этого вы можете установить numIter для некоторого значения N, чтобы получить в пределах 1/2 ^ N оптимального размера.

Вызовите его с помощью селектора CSS, например: fitToParent('.title-span');

/**
 * Fit all elements matching a given CSS selector to their parent elements'
 * width and height, by adjusting the font-size attribute to be as large as
 * possible. Uses binary search.
 */
var fitToParent = function(selector) {
    var numIter = 10;  // Number of binary search iterations
    var regexp = /\d+(\.\d+)?/;
    var fontSize = function(elem) {
        var match = elem.css('font-size').match(regexp);
        var size = match == null ? 16 : parseFloat(match[0]);
        return isNaN(size) ? 16 : size;
    }
    $(selector).each(function() {
        var elem = $(this);
        var parentWidth = elem.parent().width();
        var parentHeight = elem.parent().height();
        if (elem.width() > parentWidth || elem.height() > parentHeight) {
            var maxSize = fontSize(elem), minSize = 0.1;
            for (var i = 0; i < numIter; i++) {
                var currSize = (minSize + maxSize) / 2;
                elem.css('font-size', currSize);
                if (elem.width() > parentWidth || elem.height() > parentHeight) {
                    maxSize = currSize;
                } else {
                    minSize = currSize;
                }
            }
            elem.css('font-size', minSize);
        }
    });
};
  • 0
    Люблю этот вариант. Я изменил его, чтобы добавить параметры для vAlign и padding . vAlign == true устанавливает высоту строки выбранного элемента vAlign == true высоте родительского элемента. Отступ уменьшает окончательный размер на переданное значение. По умолчанию это 5. Я думаю, что это выглядит очень красиво.
6

Я создал директиву для AngularJS - heavely, вдохновленный ответом GeekyMonkey, но без зависимости jQuery.

Демо: http://plnkr.co/edit/8tPCZIjvO3VSApSeTtYr?p=preview

Разметка

<div class="fittext" max-font-size="50" text="Your text goes here..."></div>

Директива

app.directive('fittext', function() {

  return {
    scope: {
      minFontSize: '@',
      maxFontSize: '@',
      text: '='
    },
    restrict: 'C',
    transclude: true,
    template: '<div ng-transclude class="textContainer" ng-bind="text"></div>',
    controller: function($scope, $element, $attrs) {
      var fontSize = $scope.maxFontSize || 50;
      var minFontSize = $scope.minFontSize || 8;

      // text container
      var textContainer = $element[0].querySelector('.textContainer');

      angular.element(textContainer).css('word-wrap', 'break-word');

      // max dimensions for text container
      var maxHeight = $element[0].offsetHeight;
      var maxWidth = $element[0].offsetWidth;

      var textContainerHeight;
      var textContainerWidth;      

      var resizeText = function(){
        do {
          // set new font size and determine resulting dimensions
          textContainer.style.fontSize = fontSize + 'px';
          textContainerHeight = textContainer.offsetHeight;
          textContainerWidth = textContainer.offsetWidth;

          // shrink font size
          var ratioHeight = Math.floor(textContainerHeight / maxHeight);
          var ratioWidth = Math.floor(textContainerWidth / maxWidth);
          var shrinkFactor = ratioHeight > ratioWidth ? ratioHeight : ratioWidth;
          fontSize -= shrinkFactor;

        } while ((textContainerHeight > maxHeight || textContainerWidth > maxWidth) && fontSize > minFontSize);        
      };

      // watch for changes to text
      $scope.$watch('text', function(newText, oldText){
        if(newText === undefined) return;

        // text was deleted
        if(oldText !== undefined && newText.length < oldText.length){
          fontSize = $scope.maxFontSize;
        }
        resizeText();
      });
    }
  };
});
  • 0
    Одна проблема, с которой я resizeText заключается в том, что resizeText кажется, resizeText до того, как ng-bind фактически назначит текст элементу, что приводит к его размеру на основе предыдущего текста, а не текущего текста. Это не так уж плохо в приведенной выше демонстрации, где он вызывается несколько раз при вводе пользователем, но если он вызывается один раз, переходя от нуля к реальному значению (как в односторонней привязке), он остается на максимальном размере.
5

Я отклонил script выше от Marcus Ekwall: https://gist.github.com/3945316 и изменил его по моим предпочтениям, теперь он запускается, когда окно чтобы ребенок всегда соответствовал его контейнеру. Я вставлял script ниже для справки.

(function($) {
    $.fn.textfill = function(maxFontSize) {
        maxFontSize = parseInt(maxFontSize, 10);
        return this.each(function(){
            var ourText = $("span", this);
            function resizefont(){
                var parent = ourText.parent(),
                maxHeight = parent.height(),
                maxWidth = parent.width(),
                fontSize = parseInt(ourText.css("fontSize"), 10),
                multiplier = maxWidth/ourText.width(),
                newSize = (fontSize*(multiplier));
                ourText.css("fontSize", maxFontSize > 0 && newSize > maxFontSize ? maxFontSize : newSize );
            }
            $(window).resize(function(){
                resizefont();
            });
            resizefont();
        });
    };
})(jQuery);
  • 2
    Здорово, что ты пытаешься помочь аскеру. Однако в некоторых случаях оставлять ответ только с ссылкой. Хотя ваш ответ хорош сейчас, если ссылка когда-либо умрет, ваш ответ потеряет свою ценность. Так что будет полезно, если вы обобщите содержание статьи в своем ответе. Смотрите этот вопрос для уточнения.
  • 0
    @CodyGuldner Ты прав. Я добавил код.
Показать ещё 1 комментарий
4

Здесь моя модификация ответа OP.

Короче говоря, многие люди, которые пытались оптимизировать это, жаловались, что используется цикл. Да, хотя петли могут быть медленными, другие подходы могут быть неточными.

Поэтому мой подход использует Двоичный поиск, чтобы найти лучший размер шрифта:

$.fn.textfill = function()
{
    var self = $(this);
    var parent = self.parent();

    var attr = self.attr('max-font-size');
    var maxFontSize = parseInt(attr, 10);
    var unit = attr.replace(maxFontSize, "");

    var minFontSize = parseInt(self.attr('min-font-size').replace(unit, ""));
    var fontSize = (maxFontSize + minFontSize) / 2;

    var maxHeight = parent.height();
    var maxWidth = parent.width();

    var textHeight;
    var textWidth;

    do
    {
        self.css('font-size', fontSize + unit);

        textHeight = self.height();
        textWidth = self.width();

        if(textHeight > maxHeight || textWidth > maxWidth)
        {
            maxFontSize = fontSize;
            fontSize = Math.floor((fontSize + minFontSize) / 2);
        }
        else if(textHeight < maxHeight || textWidth < maxWidth)
        {
            minFontSize = fontSize;
            fontSize = Math.floor((fontSize + maxFontSize) / 2);
        }
        else
            break;

    }
    while(maxFontSize - minFontSize > 1 && maxFontSize > minFontSize);

    self.css('font-size', fontSize + unit);

    return this;
}

function resizeText()
{
  $(".textfill").textfill();
}

$(document).ready(resizeText);
$(window).resize(resizeText);

Это также позволяет элементу указывать минимальный и максимальный шрифты:

<div class="container">
    <div class="textfill" min-font-size="10px" max-font-size="72px">
        Text that will fill the container, to the best of its abilities, and it will <i>never</i> have overflow.
    </div>
</div>

Кроме того, этот алгоритм невозможен. Вы можете указать em, rem, % и т.д., И он будет использовать это для своего окончательного результата.

Здесь Fiddle: https://jsfiddle.net/fkhqhnqe/1/

2

У меня была точно такая же проблема с моим сайтом. У меня есть страница, которая отображается на проекторе, на стенах, на больших экранах.

Поскольку я не знаю максимальный размер моего шрифта, я повторно использовал плагин выше @GeekMonkey, но увеличивая размер шрифта:

$.fn.textfill = function(options) {
        var defaults = { innerTag: 'span', padding: '10' };
        var Opts = jQuery.extend(defaults, options);

        return this.each(function() {
            var ourText = $(Opts.innerTag + ':visible:first', this);
            var fontSize = parseFloat(ourText.css('font-size'),10);
            var doNotTrepass = $(this).height()-2*Opts.padding ;
            var textHeight;

            do {
                ourText.css('font-size', fontSize);
                textHeight = ourText.height();
                fontSize = fontSize + 2;
            } while (textHeight < doNotTrepass );
        });
    };
  • 0
    +1 за то, что был единственным плагином на этой странице, который действительно работал для меня!
  • 2
    Этот плагин сбивает страницу для меня.
1

EDIT: этот код использовался, чтобы показывать заметки поверх видео 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

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

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

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.

  • 0
    Fittext учитывает высоту?
  • 1
    @ManishSapariya нет, это не так. Он просто делит ширину контейнера на 10 и использует его как размер шрифта.
1

Предлагаемые итеративные решения можно резко ускорить на двух фронтах:

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

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

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

Вот пример:

  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

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

(function($) {
    /**
    * Resizes an inner element font so that the inner element completely fills the outer element.
    * @author Russ Painter [email protected]
    * @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
    спасибо, хотя я думаю, что у вас есть точка с запятой в верхней части кода, который не должен быть там
0

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

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

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

У меня такая же проблема, и решение в основном использует 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

Я знаю, что это старый, но есть люди, которым нужна эта функциональность. Я пошел с решением geekMonkey, но его ударом. просто потому, что он медленный. что он делает, он настраивает размер шрифта до максимума (maxFontPixels), а затем проверяет, подходит ли он внутри контейнера. в противном случае размер шрифта уменьшается на 1px и снова проверяется. почему бы просто не проверить предыдущий контейнер на высоту и представить это значение? (да, я знаю почему, но теперь я сделал решение, которое работает только на высоте, а также имеет параметр 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>

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

-1

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

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню