Авторазмер динамического текста для заполнения контейнера фиксированного размера
Мне нужно отобразить введенный пользователем текст в div фиксированного размера. Я хочу, чтобы размер шрифта автоматически настраивался так, чтобы текст заполнял поле как можно больше.
Итак - если div 400 х 300 пикселей. Если кто-то входит в ABC, то это действительно большой шрифт. Если они введут абзац, то это будет крошечный шрифт.
Возможно, я бы хотел начать с максимального размера шрифта - возможно, 32 пикселя, и, хотя текст слишком велик, чтобы вместить контейнер, уменьшайте размер шрифта, пока он не уместится.
20 ответов
Спасибо Атака. Я хотел использовать 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, так что он, вероятно, не так хорош, как следовало бы. Указатели, безусловно, приветствуются.
Я не нашел ни одного из предыдущих решений достаточно адекватным из-за плохой производительности, поэтому я сделал свое собственное, которое использует простую математику вместо цикла. Должно работать нормально во всех браузерах.
Согласно этому тесту производительности это намного быстрее, чем другие решения, найденные здесь.
(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.
Как бы мне ни нравились случайные отклики, которые я получаю за этот ответ (спасибо!), Это действительно не самый лучший подход к этой проблеме. Пожалуйста, ознакомьтесь с некоторыми другими замечательными ответами здесь, особенно те, которые нашли решения без зацикливания.
Тем не менее, для справки, вот мой оригинальный ответ:
<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>
В большинстве других ответов используется цикл для уменьшения размера шрифта до тех пор, пока он не уместится на элементе 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 (например, разрывов строк или значков с потрясающими шрифтами).
Это основано на том, что GeekyMonkey опубликовал выше, с некоторыми изменениями.
; (function($) {
/**
* Resize inner element to fit the outer element
* @author Some modifications by Sandstrom
* @author Code based on earlier works by Russ Painter (WebDesign@GeekyMonkey.com)
* @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);
Вот улучшенный метод зацикливания, который использует бинарный поиск, чтобы найти максимально возможный размер, который вписывается в родительский элемент за наименьшее количество возможных шагов (это быстрее и точнее, чем переход к фиксированному размеру шрифта). Код также оптимизирован несколькими способами для повышения производительности.
По умолчанию будет выполнено 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);
}
});
};
Я создал директиву для AngularJS - она вдохновлена ответом 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();
});
}
};
});
Вот моя модификация ответа ОП.
Короче говоря, многие люди, которые пытались оптимизировать это, жаловались на то, что используется цикл. Да, хотя петли могут быть медленными, другие подходы могут быть неточными.
Поэтому мой подход использует бинарный поиск, чтобы найти лучший размер шрифта:
$.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
, %
и т. д., и он будет использовать это для своего конечного результата.
Вот скрипка: https://jsfiddle.net/fkhqhnqe/1/
Я добавил вышеприведенный скрипт от Маркуса Эквалла: https://gist.github.com/3945316 и настроил его в соответствии со своими предпочтениями, теперь он запускается при изменении размера окна, так что дочерний элемент всегда помещается в свой контейнер. Я вставил скрипт ниже для справки.
(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);
У меня была точно такая же проблема с моим сайтом. У меня есть страница, которая отображается на проекторе, на стенах, на больших экранах..
Поскольку я не знаю максимальный размер моего шрифта, я повторно использовал плагин выше @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 );
});
};
Предлагаемые итеративные решения могут быть значительно ускорены по двум направлениям:
1) Умножьте размер шрифта на некоторую константу, а не добавляя или вычитая 1.
2) Во-первых, ноль при использовании константы курса, скажем, удвоить размер каждой петли. Затем, имея приблизительное представление о том, с чего начать, проделайте то же самое с более точной настройкой, скажем, умножьте на 1,1. Хотя перфекционисту может потребоваться точный целочисленный размер пикселя для идеального шрифта, большинство наблюдателей не замечают разницы между 100 и 110 пикселями. Если вы перфекционист, повторите третий раз с еще более точной настройкой.
Вместо того, чтобы писать конкретную подпрограмму или плагин, который отвечает на точный вопрос, я просто полагаюсь на основные идеи и пишу варианты кода для решения всех видов проблем компоновки, а не только текста, включая подгонку элементов div, spans, images... по ширине, высоте, площади,... в контейнере, соответствующем другому элементу....
Вот пример:
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');
Это самое элегантное решение, которое я создал. Он использует двоичный поиск, выполняя 10 итераций. Наивный способ заключался в том, чтобы выполнить цикл while и увеличить размер шрифта на 1, пока элемент не начнет переполняться. Вы можете определить, когда элемент начинает переполняться, используя element.offsetHeight и element.scrollHeight. Если scrollHeight больше, чем offsetHeight, у вас слишком большой размер шрифта.
Бинарный поиск - гораздо лучший алгоритм для этого. Он также ограничен количеством итераций, которые вы хотите выполнить. Просто вызовите flexFont и вставьте идентификатор div, и он изменит размер шрифта от 8 до 96 пикселей.
Я потратил некоторое время на изучение этой темы и пробовал разные библиотеки, но в конечном итоге я думаю, что это самое простое и простое решение, которое действительно будет работать.
Обратите внимание, если вы хотите, вы можете использовать offsetWidth
а также scrollWidth
, или добавьте оба в эту функцию.
// Set the font size using overflow property and div height
function flexFont(divId) {
var content = document.getElementById(divId);
content.style.fontSize = determineMaxFontSize(content, 8, 96, 10, 0) + "px";
};
// Use binary search to determine font size
function determineMaxFontSize(content, min, max, iterations, lastSizeNotTooBig) {
if (iterations === 0) {
return lastSizeNotTooBig;
}
var obj = fontSizeTooBig(content, min, lastSizeNotTooBig);
// if `min` too big {....min.....max.....}
// search between (avg(min, lastSizeTooSmall)), min)
// if `min` too small, search between (avg(min,max), max)
// keep track of iterations, and the last font size that was not too big
if (obj.tooBig) {
(lastSizeTooSmall === -1) ?
determineMaxFontSize(content, min / 2, min, iterations - 1, obj.lastSizeNotTooBig, lastSizeTooSmall) :
determineMaxFontSize(content, (min + lastSizeTooSmall) / 2, min, iterations - 1, obj.lastSizeNotTooBig, lastSizeTooSmall);
} else {
determineMaxFontSize(content, (min + max) / 2, max, iterations - 1, obj.lastSizeNotTooBig, min);
}
}
// determine if fontSize is too big based on scrollHeight and offsetHeight,
// keep track of last value that did not overflow
function fontSizeTooBig(content, fontSize, lastSizeNotTooBig) {
content.style.fontSize = fontSize + "px";
var tooBig = content.scrollHeight > content.offsetHeight;
return {
tooBig: tooBig,
lastSizeNotTooBig: tooBig ? lastSizeNotTooBig : fontSize
};
}
РЕДАКТИРОВАТЬ: Этот код был использован для отображения заметок в верхней части видео 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);
Возможно, вам придется настроить эти числа от font-family до font-family. Хороший способ сделать это - загрузить бесплатный визуализатор графиков под названием GeoGebra. Измените длину текста и размер поля. Затем вы вручную устанавливаете размер. Представьте результаты ручного анализа в систему координат. Затем вы вводите два уравнения, которые я выложил здесь, и настраиваете числа, пока "мой" график не будет соответствовать вашим собственным точкам, построенным вручную.
Вот версия принятого ответа, которая также может принимать параметр 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);
Просто хотел добавить мою версию для 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>
Вы можете использовать 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 также есть версия без jQuery.
Я получил ту же проблему, и решение в основном заключается в использовании 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>
Мне понравилось
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));
Я знаю, что это старый, но есть люди, которым нужна эта функциональность. я пошел с решением 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макс), так что для меня это работает отлично (а также работает с изменением размера окна).
Я нашел способ предотвратить использование циклов для сжатия текста. Он корректирует размер шрифта, умножая его на коэффициент между шириной контейнера и шириной содержимого. Таким образом, если ширина контейнера составляет 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/
Вот еще одна версия этого решения:
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";
}
}