根据文本长度动态更改字体大小

56
我需要将用户输入的文本显示在固定大小的 div 中。我的目标是自动调整字体大小,使文本尽可能填充整个盒子。
我可能希望从最大字体大小开始,而当文本太大无法适应容器时,缩小字体大小,直到它适合并且字体必须显示为一行。

9
不,仅使用CSS无法实现这个。 - robertp
3
可以有人用 JavaScript 提供一个解决方案吗? - user2613399
11个回答

35

假设有以下代码:

<div id="outer" style="width:200px; height:20px; border:1px solid red;">
    <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer mollis dui felis, vel vehicula tortor cursus nec</div>
</div>

然后你可以像这样做:

$(document).ready(function () {
    resize_to_fit();
});

function resize_to_fit(){
    var fontsize = $('div#outer div').css('font-size');
    $('div#outer div').css('fontSize', parseFloat(fontsize) - 1);

    if($('div#outer div').height() >= $('div#outer').height()){
        resize_to_fit();
    }
}

工作示例

$(document).ready(function() {
  resize_to_fit();
});

function resize_to_fit() {
  var fontsize = $('div#outer div').css('font-size');
  $('div#outer div').css('fontSize', parseFloat(fontsize) - 1);

  if ($('div#outer div').height() >= $('div#outer').height()) {
    resize_to_fit();
  }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="outer" style="width:200px; height:20px; border:1px solid red;">
  <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer mollis dui felis, vel vehicula tortor cursus nec</div>
</div>


10
需要使用jQuery才能运行,OP并没有说明要使用jQuery。 - unsalted

34
根据这里排名最高的回答的逻辑,我创建了一个无jQuery版本

const input = document.querySelector('input');
const output = document.querySelector('.output');
const outputContainer = document.querySelector('.container');

function resize_to_fit() {
  let fontSize = window.getComputedStyle(output).fontSize;
  output.style.fontSize = (parseFloat(fontSize) - 1) + 'px';
  
  if(output.clientHeight >= outputContainer.clientHeight){
    resize_to_fit();
  }
}

function processInput() { 
  output.innerHTML =this.value;
  output.style.fontSize = '100px'; // Default font size
  resize_to_fit();
}

input.addEventListener('input', processInput);
<input type="text" placeholder="Add text input here" style="margin: 10px; width:50%;">

<div id="outer" class="container" 
style="width:80%; height:100px; border:2px solid red; font-size:20px;">
  
<div class="output" style="word-break: break-all; word-wrap: break-word;">
</div>

</div>


6

无需迭代字体大小。只需计算文本的当前大小和容器的大小,然后应用缩放即可。

const text_el = document.querySelector("#text");
const container_el = document.querySelector("#container");

text_el.addEventListener("input", function(e) {
  container_el.children[0].textContent = this.value;
  resize2fit(container_el)
});

function resize2fit(el) {
  if (!el.parentElement) return;
  el.style.setProperty("--font-size", "1em");
  const {width: max_width, height: max_height} = el.getBoundingClientRect();
  const {width, height} = el.children[0].getBoundingClientRect();
  el.style.setProperty("--font-size", Math.min(max_width/width, max_height/height)+"em");
}

window.addEventListener("resize", function(e) {
    resize2fit(container_el);
});
resize2fit(container_el);
#container {
  width: 100%;
  height: 100px;
  font-size: var(--font-size, 1em);
  white-space: nowrap;
  border: 1px solid blue;
}
#container > * {
  display: inline-block;
}
<input id="text" value="lorem ipsum" />
<div id="container">
  <span>lorem ipsum</span>
</div>


为什么你没有更多的赞?测量比迭代每个可能的字体大小值并在重新渲染之间等待要有效得多... 无论如何,我只是想补充一下这个解决方案,即所有在childContainer中调整大小的内容都必须使用em单位以保持比例 :) - Florent Descroix

3

2
尽管这是一个老问题,并且已经有了几个答案(大多数基于调整字体大小以适应内容),但我最近在我们的项目中需要做类似的事情。起初,我使用了 Joe 的答案的编辑版本(https://dev59.com/12Ml5IYBdhLWcg3wp4ak#33492161),但后来我开始思考并意识到可以通过使用简单的“transform: scale(x)”操作更轻松地实现相同的效果。另一个优点是,内容被缩放到完全适合容器的大小,而调整字体大小可能会导致子优化文本大小。计算比例因子的值非常简单,只需将父容器宽度除以子容器宽度即可。如果子内容大于父容器,则得到的值将小于1.0 - 将此传递给“transform: scale()”将导致完美重新调整大小的子元素。下面是我使用的函数。它使用 jQuery,但也可以轻松更新为直接使用可用的 DOM 函数。
这段话的意思是:“代码大部分都很容易理解,但我要指出,孩子的“显示”最初被更改为“inline-block”,因为像<p>、<span>等元素否则无法报告它们的宽度。”
“还有一件事需要注意,使用“transform:scale()”可能会影响边距。在我的情况下,我需要确保子元素在父容器内居中,因此我使用了display:flex:”
.parent-container {
    display: flex;
    flex-direction: column;
    align-items: center;
}

希望有人会觉得这个有用!
function resizeToFit(parent, child) {
    let $parent = jQuery(parent);
    let $child = jQuery(child);

    // Temporarily redefine child's display so we
    // can obtain the real width
    let $display = $child.css('display');
    $child.css('display', 'inline-block');


    // Remove any existing inline transform
    $child.css('transform', '');

    // Calculate the scale factor
    let factor = $parent.width() / $child.width();
    if (factor < 1.0) {
        let scale = 'scale(' + factor + ')';
        $child.css({
          '-webkit-transform' : scale,
          '-moz-transform'    : scale,
          '-ms-transform'     : scale,
          '-o-transform'      : scale,
          'transform'         : scale
        });
    }

    // Restore the original display value
    $child.css('display', $display);
};

2

获取一段文本的像素大小是一件比较困难的事情,它取决于浏览器和用户的设置,因此很难找到适用于所有情况的解决方案。

如果您所说的“显示用户输入的文本”是指用户在文本框中输入,那么您可以附加一个按键监听器来检查文本值的长度,然后相应地调整font-size。这里有一个示例,但您可能需要根据需要更改长度和字体大小:

演示

$('#text').on('keypress', function(e) {
    var that = $(this),
        textLength = that.val().length
    ;

    if(textLength > 30) {
        that.css('font-size', '5px');
    } else if(textLength > 20) {
        that.css('font-size', '10px');
    } else if(textLength > 10) {
        that.css('font-size', '15px');
    }
});

如果文本是从外部来源获取的(用户不会在框中输入),并且该文本必须显示在一个div中,我们如何知道文本的大小? - user2613399
看看@putvande的回答,我认为那可能更接近你想要的。 - cfs

1

感谢putvande让我知道了一般方法。 这是一个改进的版本。

  1. 摆脱回调地狱。
  2. 修复可能导致页面挂起的一些错误。

相同的HTML:

<div id="outer" style="width:200px; height:20px; border:1px solid red;">
    <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer mollis dui felis, vel vehicula tortor cursus nec</div>
</div>

这是函数:

resize_to_fit($('#outer'), $('#outer div'));

function resize_to_fit(outer, inner) {
    while(inner.height() > outer.height()) {
        var fontsize = parseInt(inner.css('font-size')) - 1;
        inner.css('font-size', fontsize);
        // some browsers(chrome) the min font return value is 12px
        if(fontsize <= 1 || parseInt(inner.css('font-size')) >= fontsize+1)
            break;
    }
}

递归有什么问题?回调地狱是什么?据我所知,回调地狱通常是无休止的 func().next().then().etc().. 或者非常嵌套的匿名函数传递... 对吧? - Canis
他可能指的是调用栈,而不是回调。递归不是一个好的实践方式,因为它可能会无限地填充调用栈,导致堆栈溢出。 - uTILLIty
@Joe,为什么不使用元素parentNode,而是明确期望它被传递呢? - uTILLIty

1
使用非常少的Javascript,您可以为字符串的长度分配CSS类,例如:text-length-5text-length-20
然后,只需使用CSS来针对这些类名目标不同的font-size
它可能不适用于所有情况,但对于我的情况效果非常好,其中最大长度约为10-12个字符。
如果您有100+或1000+个字符,还可以编写一个函数来接收长度并返回CSS类,然后根据这些范围进行样式设置。

HTML:

<div class="box">ABC</div>
<div class="box">ABCDE</div>

Javascript(jQuery,但相同的思路也适用于React或原生JS)

$(".box").each((i, el)=> {
  const length = $(el).text().length;
  $(el).addClass("text-length-"+length);
})

CSS:
.box {
  font-size: 16px;
}
.box.text-length-4,
.box.text-length-5,
.box.text-length-6 {
  font-size: 12px;
}

1
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        #div1{
            width: 200px;
            height: 200px;
            font-size: 32px;
            line-height: 1.2em;
        }
    </style>
    <script type="text/javascript" src="js/jquery-1.9.1.min.js"></script>
    <script>
        $(function(){
            n = 1;
            while(n==1){
                n = 0
                if ($('#div1 .holder').outerHeight()>$('#div1').outerHeight()){
                    var fz = parseInt($('#div1').css('font-size'));
                    $('#div1').css({'font-size' : fz-1});
                    n = 1
                } else {n = 0}
            }
        });
    </script>
</head>
<body>
    <div id="div1">
        <div class="holder">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.
I'd probably want to start with a maximum font size and while the text is too big to fit the container, shrink the font size until it fits and the font must be displayed as a single line. Is it possible to do this using only css and html.</div>
    </div>
</body>
</html>

为什么不使用布尔值而是n=1? - cfs
有什么区别吗?这只是一个标志。写下了脑海中浮现的第一件事。 - Anon
通常标志是布尔值,否则对于阅读您的代码的人来说可能会感到困惑,因为整数可能表示存在两个以上的状态。 - cfs
或者使用 while(true)break - reformed

0

谁想要一个依赖于元素宽度的动态函数(基于putvande的答案):

        $(document).ready(function () {
            var arrEl = ['div1', 'div2', 'div3'];
            resize_to_fit(arrEl);
        });

        function resize_to_fit(arr){
            for (var el in arr) {
                var jEl = $('.' + arr[el] + ' span');
                var fontsize = jEl.css('font-size');
                jEl.css('fontSize', parseFloat(fontsize) - 1);
                if (jEl.width() >= $('.' + arr[el]).width()){
                    resize_to_fit([arr[el]]);
                }        
            }
        }

以及HTML代码:

<div class="div1">
    <span>Lorem Ipsum</span>
</div>
<br/>
<div class="div2">
    <span>Lorem Ipsum 2</span>
</div>
<br />
<div class="div3">
    <span>Lorem Ipsum 3</span>
</div>

使用CSS:

.div1, .div2, .div3 {
    width: 207px;
    white-space: nowrap;
}

注意你只将字体大小设置为内部的span,而没有设置外部div的大小。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接