我需要显示用户输入的文本到一个固定大小的div。我想要的是字体大小自动调整,以便文本尽可能多地填充框。
如果div是400px x 300px。如果有人输入ABC,那么字体就很大。如果他们输入一个段落,那么它将是一个很小的字体。
我可能想要从最大字体大小开始——可能是32px,当文本太大而不适合容器时,缩小字体大小直到它适合。
我需要显示用户输入的文本到一个固定大小的div。我想要的是字体大小自动调整,以便文本尽可能多地填充框。
如果div是400px x 300px。如果有人输入ABC,那么字体就很大。如果他们输入一个段落,那么它将是一个很小的字体。
我可能想要从最大字体大小开始——可能是32px,当文本太大而不适合容器时,缩小字体大小直到它适合。
当前回答
我用geekMonkey解决方案,但它太慢了。他所做的就是将字体大小调整到最大(maxFontPixels),然后检查它是否适合容器。否则,它将字体大小减小1px,并再次检查。为什么不简单地检查前一个容器的高度并提交该值呢?(是的,我知道为什么,但我现在做了一个解决方案,这只适用于高度,也有一个最小/最大选项)
这里有一个更快的解决方案:
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>
同样,这个解决方案只检查容器的高度。这就是为什么这个函数不需要检查元素是否在里面。但我也实现了一个最小/最大值(40min, 150max),所以对我来说,这是完美的(也适用于窗口大小调整)。
其他回答
我为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();
});
}
};
});
这是我对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, %等,它将使用它的最终结果。
这是小提琴:https://jsfiddle.net/fkhqhnqe/1/
尽管我很喜欢这个答案偶尔得到的点赞(谢谢!),但这真的不是解决这个问题的最好方法。请在这里查看其他一些精彩的答案,特别是那些没有循环的答案。
不过,为了便于参考,以下是我最初的答案:
<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>
只是想增加我的内容表版本。
$.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页面)来解决这个问题。与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版本。