Tự động kích thước văn bản động để điền vào container kích thước cố định


312

Tôi cần hiển thị văn bản người dùng nhập vào một div kích thước cố định. Những gì tôi muốn là cho kích thước phông chữ được tự động điều chỉnh để văn bản điền vào hộp càng nhiều càng tốt.

Vì vậy - Nếu div là 400px x 300px. Nếu ai đó vào ABC thì đó thực sự là phông chữ lớn. Nếu họ nhập một đoạn, thì đó sẽ là một phông chữ nhỏ.

Có lẽ tôi muốn bắt đầu với kích thước phông chữ tối đa - có thể là 32px và trong khi văn bản quá lớn để vừa với thùng chứa, hãy thu nhỏ kích thước phông chữ cho đến khi phù hợp.


119
Có lẽ là một tính năng tuyệt vời nhất cần được thêm vào HTML5 / CSS3 mà không cần đến JS.
John Magnolia

Tôi đã thực hiện một số phép đo trong đó tôi đã thay đổi độ dài của văn bản động và kích thước của vùng chứa để tìm ra kích thước phông chữ nào sẽ làm cho văn bản phù hợp hoàn hảo. Và sau khi thực hiện một số phân tích hồi quy, tôi đã đưa ra một hàm toán học đơn giản sẽ tự động tạo ra cỡ chữ tốt nhất.
Bạn của Kim

2
Nó thực sự chỉ ra rằng biểu đồ cung cấp cho bạn kích thước phông chữ tốt nhất được đưa ra bởi f (x) = g (chữ cái) * (x / 1000) ^ n, trong đó g (x) là một hàm đơn giản, n thay đổi tùy thuộc vào phông chữ bạn đang sử dụng. (Mặc dù nó có thể có một giá trị tiêu chuẩn cho tất cả các phông chữ, nếu bạn không muốn điều chỉnh nó để làm cho nó hoàn toàn hoàn hảo ...). x là kích thước tính bằng pixel vuông của container.
Bạn của Kim

1
Nếu bạn vẫn quan tâm, tôi có thể thêm một câu trả lời. Cá nhân tôi nghĩ rằng đó là một phương pháp tốt hơn nhiều để tạo kích thước phông chữ chính xác ở vị trí đầu tiên, thay vì thử và thất bại cho đến khi tập lệnh "làm cho đúng".
Bạn của Kim

1
Kiểm tra câu trả lời của tôi để biết cách tốt hơn để làm điều này
Hoffmann

Câu trả lời:


167

Cảm ơn tấn công . Tôi muốn sử dụng jQuery.

Bạn chỉ cho tôi đi đúng hướng, và đây là những gì tôi đã kết thúc với:

Đây là một liên kết đến plugin: https://plugins.jquery.com/textfill/
Và một liên kết đến nguồn: 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 });
});

và html của tôi là như thế này

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

Đây là plugin jquery đầu tiên của tôi, vì vậy nó có thể không tốt như nó phải vậy. Con trỏ chắc chắn được chào đón.


8
Tôi thực sự chỉ làm sạch nó lên và đóng gói nó như là một plug-in có sẵn từ jquery.com tại plugins.jquery.com/project/TextFill
GeekyMonkey

3
@GeekyMonkey, bạn đã kéo plugin chưa? Chỉ cần theo một liên kết dupe đến trang này và nghĩ rằng tôi sẽ xem, nhưng jQuery.com liên kết đến trang web của bạn trở lại 404.
David nói phục hồi Monica

Lưu ý: Tôi thấy rằng vì một số lý do, plugin này chỉ hoạt động khi div ($ ('. Jtextfill') trong ví dụ trên) là một phần của tài liệu gốc. Dường như. Băng thông () trả về 0 khi div được nhúng bên trong các div khác.
Jayesh

1
Dòng "while" trên vòng lặp đó có vẻ sai đối với tôi - nên có dấu ngoặc đơn xung quanh "||" biểu hiện phụ. Cách viết bây giờ, kích thước phông chữ tối thiểu chỉ được kiểm tra khi chiều rộng quá lớn, không phải chiều cao.
Pointy

4
Cách tiếp cận này RẤT chậm, mỗi lần phông chữ thay đổi kích thước, nó đòi hỏi phần tử phải được kết xuất lại. Kiểm tra câu trả lời của tôi cho một cách tốt hơn để làm điều này.
Hoffmann

52

Tôi đã không tìm thấy bất kỳ giải pháp nào trước đây là đủ, do hiệu suất kém, vì vậy tôi đã tự tạo ra cách sử dụng toán học đơn giản thay vì lặp. Nên hoạt động tốt trong tất cả các trình duyệt.

Theo trường hợp kiểm tra hiệu suất này, nó nhanh hơn nhiều so với các giải pháp khác được tìm thấy ở đây.

(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);

Nếu bạn muốn đóng góp, tôi đã thêm nó vào Gist .


1
@Jon, cảm ơn! Bạn đúng rằng tập lệnh của tôi không thực hiện nhiều dòng, nhưng một lần nữa OP không yêu cầu cụ thể điều đó để giả định của bạn có thể sai. Ngoài ra, loại hành vi đó không có ý nghĩa nhiều imo. Tôi đoán cách tốt nhất để thêm hỗ trợ nhiều dòng sẽ là phân tách chuỗi dựa trên số lượng từ và sau đó tính toán từng phần với tập lệnh trên và rất có thể nó sẽ nhanh hơn.
mekwall

4
@Jon, tôi đã chơi xung quanh một chút với textfill multiline và kết thúc với giải pháp này . Phương pháp của bão cát rất có thể chính xác hơn nhưng phương pháp này nhanh hơn;)
mekwall

2
Đây là phiên bản có kích thước phông chữ tối thiểu cũng như tối đa: gist.github.com/1714284
Jess Telford

1
@Hoffmann Hmm. Giải pháp của tôi không gọi .css("font-size")trong một vòng lặp. bạn đã nhận được ở đâu đó từ đâu? Giải pháp của tôi có thể nhanh hơn vì nó không có bất kỳ nội dung ưa thích nào bạn đã thêm vào plugin của mình. Bạn có thể thêm plugin của mình vào jsperf và chúng tôi sẽ xem cái nào nhanh nhất;)
mekwall

1
@MarcusEkwall Xin lỗi, vì một số lý do tôi mặc dù tôi đã thấy một vòng lặp ở đó. Cách tiếp cận của bạn tương tự như của tôi và thực sự tôi sẽ chậm hơn một chút vì plugin của tôi cũng thực hiện một số nội dung khác (như điều chỉnh để phù hợp với cả chiều cao và chiều rộng, tập trung văn bản và một số tùy chọn khác), không quan trọng, phần thực sự chậm đang gọi hàm .css bên trong một vòng lặp.
Hoffmann

35

Nhiều như tôi yêu thích các upvote thỉnh thoảng tôi nhận được cho câu trả lời này (cảm ơn!), Đây thực sự không phải là cách tiếp cận lớn nhất cho vấn đề này. Vui lòng kiểm tra một số câu trả lời tuyệt vời khác ở đây, đặc biệt là những câu trả lời đã tìm ra giải pháp mà không cần lặp.


Tuy nhiên, để tham khảo, đây là câu trả lời ban đầu của tôi :

<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>

Và đây là một phiên bản với các lớp :

<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
Tôi thấy điều này hoạt động tốt hơn với offsetWidth, tôi cũng phải tạo một biến cho kích thước và sau đó nối thêm pxtextSpan.style.fontSize = size+"px";
Wez

2
chắc chắn '+ "px"' là cần thiết.
Sandun dhammika

@IdanShechter Xin lỗi vì đã chờ đợi lâu, rất lâu! Đã thêm một ví dụ!
tấn công

Cảm ơn bạn, cứu người! Tôi không biết về jQuery, vì vậy tôi gắn bó với giải pháp của bạn :)
vintproykt

32

Hầu hết các câu trả lời khác sử dụng một vòng lặp để giảm kích thước phông chữ cho đến khi nó vừa với div, đây là RẤT chậm vì trang cần phải kết xuất lại phần tử mỗi khi phông chữ thay đổi kích thước. Cuối cùng tôi đã phải viết thuật toán của riêng mình để làm cho nó hoạt động theo cách cho phép tôi cập nhật nội dung của nó theo định kỳ mà không bị đóng băng trình duyệt người dùng. Tôi đã thêm một số chức năng khác (xoay văn bản, thêm phần đệm) và đóng gói dưới dạng plugin jQuery, bạn có thể lấy nó tại:

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

chỉ cần gọi

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

và nó sẽ phù hợp độc đáo trên container của bạn.

Nhìn thấy nó trong hành động ở đây:

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

Hiện tại nó có một số hạn chế, div phải có chiều cao và chiều rộng cố định và nó không hỗ trợ gói văn bản thành nhiều dòng.

Tôi sẽ làm việc để có được một tùy chọn để đặt kích thước phông chữ tối đa.

Chỉnh sửa: Tôi đã tìm thấy một số vấn đề khác với plugin, nó không xử lý mô hình hộp khác ngoài mô hình chuẩn và div không thể có lề hoặc viền. Tôi sẽ làm việc này.

Edit2: Bây giờ tôi đã sửa những vấn đề và giới hạn đó và thêm nhiều tùy chọn hơn. Bạn có thể đặt kích thước phông chữ tối đa và bạn cũng có thể chọn giới hạn kích thước phông chữ bằng chiều rộng, chiều cao hoặc cả hai. Tôi sẽ làm việc để chấp nhận một giá trị chiều rộng tối đa và chiều cao tối đa trong phần tử trình bao bọc.

Edit3: Tôi đã cập nhật plugin lên phiên bản 1.2.0. Dọn dẹp chính mã và các tùy chọn mới (verticalAlign, verticalAlign, textAlign) và hỗ trợ cho các thành phần bên trong bên trong thẻ span (như ngắt dòng hoặc biểu tượng tuyệt vời về phông chữ.)


1
Tôi tự hỏi tại sao gói văn bản thành nhiều dòng không được hỗ trợ?
Manish Sapariya

1
@M BiếnSapariya Nó được hỗ trợ, nhưng bạn cần thêm dấu ngắt dòng (thẻ br) theo cách thủ công. Lý do tôi không hỗ trợ gói văn bản tự động là vì để làm cho nó nhanh (chỉ thay đổi kích thước phông chữ hai lần thay vì nhiều lần) Tôi cần đưa ra giả định rằng văn bản sẽ không bao bọc giữa các từ. Cách plugin của tôi hoạt động là đặt kích thước phông chữ thành 1000px sau đó xem yếu tố kích thước văn bản được so sánh với vùng chứa, sau đó tôi giảm kích thước phông chữ theo cùng một yếu tố. Để hỗ trợ gói văn bản thông thường, tôi sẽ cần sử dụng cách tiếp cận chậm (giảm kích thước phông chữ nhiều lần) rất chậm.
Hoffmann

Chào! Vì không có tin nhắn riêng tư ở đây, trên StackOverflow, tôi sẽ phải hỏi bạn bằng cách nhận xét câu trả lời của bạn. Tôi yêu plugin jQuery của bạn, nhưng tôi không thể làm cho nó hoạt động được. Tôi đã bao gồm đúng thư viện jQuery, tải xuống plugin của bạn và bao gồm nó. Bây giờ khi tôi thử và sử dụng nó, bảng điều khiển nói 'Uncaught TypeError: không xác định không phải là một chức năng'. Đây có phải là một cái gì đó bạn quen thuộc? Bạn có biết làm sao để sửa cái này không? Cảm ơn
Gust van de Wal

@GustvandeWal Bạn cần bao gồm plugin sau khi bao gồm thư viện jquery
Hoffmann

Tôi đã làm. Tôi đã có <script type = "text / javascript" src = " code.jquery.com/jquery-2.1.1.min.js"> </ s src" js / jquery-bigtext.js "> </ script > Trình duyệt không thông báo cho tôi rằng nó không thể tải thư viện jQuery hoặc plugin.
Gust van de Wal

9

Điều này dựa trên những gì GeekyMonkey đã đăng ở trên, với một số sửa đổi.

; (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);

sự khác biệt là nó có thể lấy nhiều phần tử con và nó có tính đến phần đệm. Sử dụng kích thước phông chữ làm kích thước tối đa mặc định, để tránh trộn lẫn javascript và css.
sandstrom

5
Điều này thật tuyệt, nhưng làm thế nào để tôi sử dụng nó? Tôi làm $ ('. Bên ngoài'). Textfill (); và tôi không nhận được sự thay đổi.
Drew Baker

3
Cảm ơn, đây là một thực hiện rất tốt đẹp. Một điều tôi gặp phải: nếu bạn đang xử lý các chuỗi văn bản rất dài và các thùng chứa rất hẹp, chuỗi văn bản sẽ dính ra khỏi vùng chứa, nhưng bên ngoàiWidth vẫn sẽ được tính như thể không có. Toss "word-quấn: break-word;" vào CSS của bạn cho container đó, nó sẽ khắc phục vấn đề này.
Jon

8

Đây là một phương pháp lặp được cải tiến sử dụng tìm kiếm nhị phân để tìm kích thước lớn nhất có thể phù hợp với cha mẹ trong vài bước có thể (điều này nhanh hơn và chính xác hơn so với bước theo kích thước phông chữ cố định). Mã này cũng được tối ưu hóa theo nhiều cách để thực hiện.

Theo mặc định, 10 bước tìm kiếm nhị phân sẽ được thực hiện, sẽ nhận được trong vòng 0,1% kích thước tối ưu. Thay vào đó, bạn có thể đặt numIter thành một số giá trị N để có được trong vòng 1/2 ^ N với kích thước tối ưu.

Gọi nó bằng bộ chọn CSS, vd: 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);
        }
    });
};

Yêu lựa chọn này. Tôi đã sửa đổi nó để thêm các tham số cho vAlignpadding. vAlign == trueđặt chiều cao của phần tử được chọn thành chiều cao của cha mẹ. Đệm giảm kích thước cuối cùng bởi giá trị được thông qua. Nó mặc định là 5. Tôi nghĩ rằng nó trông rất đẹp.
Người ủng hộ của quỷ

6

Tôi đã tạo một chỉ thị cho AngularJS - được truyền cảm hứng mạnh mẽ từ câu trả lời của GeekyMonkey nhưng không có sự phụ thuộc của jQuery.

Bản trình diễn: http://plnkr.co/edit/8tPCZIjvO3VSApSeTtYr?p=preview

Đánh dấu

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

Chỉ thị

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();
      });
    }
  };
});

Một vấn đề tôi gặp phải là vấn đề này resizeTextdường như được gọi trước khi ng-bindthực sự gán văn bản cho thành phần, dẫn đến kích thước của nó dựa trên văn bản trước đó thay vì văn bản hiện tại. Điều này không quá tệ trong bản demo ở trên, nơi nó được gọi liên tục theo kiểu người dùng, nhưng nếu nó được gọi một lần đi từ null đến giá trị thực (như trong ràng buộc một chiều) thì nó vẫn ở kích thước tối đa.
Miral

5

Tôi đã chia đoạn script ở trên từ Marcus Ekwall: https://gist.github.com/3945316 và điều chỉnh nó theo sở thích của tôi, nó sẽ kích hoạt khi cửa sổ được thay đổi kích thước, để đứa trẻ luôn vừa với thùng chứa của nó. Tôi đã dán đoạn script bên dưới để tham khảo.

(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
Thật tuyệt khi bạn đang cố gắng giúp người hỏi. Tuy nhiên, để lại một câu trả lời chỉ với một liên kết có thể có hại trong một số trường hợp. Mặc dù câu trả lời của bạn rất tốt, nhưng nếu liên kết đã chết, câu trả lời của bạn sẽ mất đi giá trị của nó. Vì vậy, nó sẽ hữu ích nếu bạn tóm tắt nội dung từ bài viết trong câu trả lời của bạn. Xem câu hỏi này để làm rõ.
Cody Guldner

5

Đây là sửa đổi của tôi về câu trả lời của OP.

Nói tóm lại, nhiều người đã cố gắng tối ưu hóa điều này phàn nàn rằng một vòng lặp đang được sử dụng. Có, trong khi các vòng lặp có thể chậm, các cách tiếp cận khác có thể không chính xác.

Do đó, cách tiếp cận của tôi sử dụng Tìm kiếm nhị phân để tìm Kích thước phông chữ tốt nhất:

$.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);

Điều này cũng cho phép phần tử chỉ định phông chữ tối thiểu và tối đa:

<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>

Hơn nữa, thuật toán này là đơn vị. Bạn có thể chỉ định em, rem,% , vv và nó sẽ sử dụng cho kết quả cuối cùng của nó.

Đây là Fiddle: https://jsfiddle.net/fkhqhnqe/1/


2

Tôi đã có chính xác cùng một vấn đề với trang web của tôi. Tôi có một trang được hiển thị trên máy chiếu, trên tường, màn hình lớn ..

Vì tôi không biết kích thước tối đa của phông chữ của mình, tôi đã sử dụng lại plugin ở trên @GeekMonkey nhưng tăng kích thước phông chữ:

$.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 vì là plugin duy nhất trên trang này thực sự hiệu quả với tôi!
skybondsor

2
Plugin này sập trang cho tôi.
Jezen Thomas

1

Đây là một phiên bản của câu trả lời được chấp nhận cũng có thể lấy tham số 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);

cảm ơn, mặc dù tôi nghĩ rằng bạn đã có một dấu chấm phẩy ở đầu mã không nên có
Patrick Moore

1

Bạn có thể sử dụng FitText.js ( trang github ) để giải quyết vấn đề này. Thực sự nhỏ và hiệu quả so với TextFill. TextFill sử dụng vòng lặp while đắt tiền và FitText thì không.

Ngoài ra FitText linh hoạt hơn (tôi sử dụng nó trong một proyect với các yêu cầu rất đặc biệt và hoạt động như một nhà vô địch!).

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>

Bạn cũng có thể đặt tùy chọn cho nó:

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

CSS:

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

Và nếu bạn cần nó, FitText cũng có phiên bản không có jQuery .


Liệu fittext có tính đến chiều cao?
Manish Sapariya

1
@M BiếnSapariya không, không. Nó chỉ chia chiều rộng của container cho 10 và sử dụng kích thước đó làm cỡ chữ.
Dan H

1

EDIT: Mã này đã được sử dụng để hiển thị ghi chú trên đầu video HTML5. Nó thay đổi kích thước phông chữ khi đang thay đổi kích thước video (khi cửa sổ trình duyệt được thay đổi kích thước.) Các ghi chú được kết nối với video (giống như ghi chú trên YouTube), đó là lý do tại sao mã sử dụng phiên bản thay vì xử lý DOM trực tiếp

Theo yêu cầu, tôi sẽ gửi một số mã mà tôi đã sử dụng để đạt được điều này. (Các hộp văn bản trên một video HTML5.) Mã được viết cách đây rất lâu và tôi thực sự nghĩ rằng nó khá lộn xộn. Vì câu hỏi đã được trả lời và một câu trả lời đã được chấp nhận từ lâu, tôi không buồn viết lại câu hỏi này. Nhưng nếu bất cứ ai muốn đơn giản hóa điều này một chút, bạn sẽ được chào đón nhiều hơn!

// 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);

Có lẽ bạn sẽ cần phải điều chỉnh những con số này từ họ phông chữ sang họ phông chữ. Một cách tốt để làm điều này là tải xuống một trình hiển thị đồ thị miễn phí có tên GeoGebra. Thay đổi độ dài của văn bản và kích thước của hộp. Sau đó, bạn tự đặt kích thước. Vẽ các kết quả thủ công vào hệ tọa độ. Sau đó, bạn nhập hai phương trình tôi đã đăng ở đây và bạn điều chỉnh các số cho đến khi biểu đồ "của tôi" khớp với các điểm được vẽ thủ công của riêng bạn.


1

Các giải pháp lặp được đề xuất có thể được tăng tốc đáng kể trên hai mặt trận:

1) Nhân kích thước phông chữ với một số hằng số, thay vì thêm hoặc bớt 1.

2) Đầu tiên, bằng không khi sử dụng hằng số khóa học, giả sử, nhân đôi kích thước mỗi vòng lặp. Sau đó, với một ý tưởng sơ bộ về nơi bắt đầu, hãy làm điều tương tự với sự điều chỉnh tốt hơn, giả sử, nhân với 1.1. Mặc dù người cầu toàn có thể muốn kích thước pixel nguyên chính xác của phông chữ lý tưởng, hầu hết các nhà quan sát không nhận thấy sự khác biệt giữa 100 và 110 pixel. Nếu bạn là người cầu toàn, thì hãy lặp lại lần thứ ba với sự điều chỉnh thậm chí tốt hơn.

Thay vì viết một thói quen hoặc trình cắm cụ thể trả lời chính xác câu hỏi, tôi chỉ dựa vào các ý tưởng cơ bản và viết các biến thể của mã để xử lý tất cả các loại vấn đề bố cục, không chỉ văn bản, bao gồm cả div, spans, hình ảnh ,. .. theo chiều rộng, chiều cao, diện tích, ... trong một thùng chứa, khớp với phần tử khác ....

Đây là một ví dụ:

  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

Đây là giải pháp thanh lịch nhất mà tôi đã tạo ra. Nó sử dụng tìm kiếm nhị phân, thực hiện 10 lần lặp. Cách ngây thơ là thực hiện một vòng lặp while và tăng kích thước phông chữ lên 1 cho đến khi phần tử bắt đầu tràn. Bạn có thể xác định khi một phần tử bắt đầu tràn bằng cách sử dụng phần tử.offsetHeightElement.scrollHeight . Nếu scrollHeight lớn hơn offsetHeight, bạn có kích thước phông chữ quá lớn.

Tìm kiếm nhị phân là một thuật toán tốt hơn nhiều cho việc này. Nó cũng bị giới hạn bởi số lần lặp bạn muốn thực hiện. Chỉ cần gọi flexFont và chèn id id và nó sẽ điều chỉnh kích thước phông chữ trong khoảng từ 8px đến 96px .

Tôi đã dành thời gian nghiên cứu chủ đề này và thử các thư viện khác nhau, nhưng cuối cùng tôi nghĩ đây là giải pháp đơn giản và đơn giản nhất sẽ thực sự hiệu quả.

Lưu ý nếu bạn muốn, bạn có thể thay đổi để sử dụng offsetWidthscrollWidth, hoặc thêm cả hai vào chức năng này.

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

Cảm ơn, điều này có vẻ tuyệt vời! Tôi chỉ nhận được ReferenceError: lastSizeTooSmall is not defined. Có lẽ điều đó cần được xác định ở đâu đó?
ndbroadbent

0

Tôi gặp vấn đề tương tự và về cơ bản, giải pháp là sử dụng javascript để kiểm soát kích thước phông chữ. Kiểm tra ví dụ này trên codepen:

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

Đây là ví dụ chỉ dành cho chiều cao, có thể bạn cần đặt một số nếu về chiều rộng.

cố gắng thay đổi kích thước nó

<!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

tôi thích

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

Chỉ muốn thêm phiên bản của tôi cho nội dung.

$.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

Tôi đã tìm ra cách để ngăn chặn việc sử dụng các vòng lặp để thu nhỏ văn bản. Nó điều chỉnh kích thước phông chữ bằng cách nhân nó với tỷ lệ giữa chiều rộng của container và chiều rộng nội dung. Vì vậy, nếu chiều rộng của bộ chứa là 1/3 nội dung, kích thước phông chữ sẽ bị giảm đi 1/3 và sẽ có chiều rộng của bộ chứa. Để mở rộng quy mô, tôi đã sử dụng một vòng lặp while, cho đến khi nội dung lớn hơn container.

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

Mã này là một phần của bài kiểm tra mà tôi đã tải lên Github https://github.com/ricardobrg/fitText/


0

Tôi đã đi với giải pháp geekMonkey, nhưng nó quá chậm. Những gì anh ta làm, là anh ta điều chỉnh kích thước phông chữ đến mức tối đa (maxFontPixels) và sau đó kiểm tra xem nó có vừa trong thùng chứa không. mặt khác, nó giảm kích thước phông chữ xuống 1px và kiểm tra lại. Tại sao không chỉ đơn giản là kiểm tra container trước cho chiều cao và gửi giá trị đó? (vâng, tôi biết tại sao, nhưng bây giờ tôi đã thực hiện một giải pháp, chỉ hoạt động theo chiều cao và cũng có tùy chọn tối thiểu / tối đa)

Đây là một giải pháp nhanh hơn nhiều:

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();
);

và đây sẽ là HTML:

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

Một lần nữa: giải pháp này CHỈ kiểm tra chiều cao của container. Đó là lý do tại sao chức năng này không phải kiểm tra, nếu phần tử phù hợp bên trong. Nhưng tôi cũng đã triển khai một giá trị tối thiểu / tối đa (40 phút, 150max) vì vậy đối với tôi điều này hoạt động hoàn toàn tốt (và cũng hoạt động trên thay đổi kích thước cửa sổ).


-1

Đây là một phiên bản khác của giải pháp này:

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";
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.