Teks dinamis ukuran otomatis untuk mengisi wadah ukuran tetap


312

Saya perlu menampilkan teks yang dimasukkan pengguna ke dalam div ukuran tetap. Yang saya inginkan adalah ukuran font disesuaikan secara otomatis sehingga teks memenuhi kotak sebanyak mungkin.

Jadi - Jika divnya adalah 400px x 300px. Jika seseorang memasuki ABC maka itu font yang sangat besar. Jika mereka memasukkan paragraf, maka itu akan menjadi font kecil.

Saya mungkin ingin memulai dengan ukuran font maksimum - mungkin 32px, dan sementara teks terlalu besar untuk muat wadah, perkecil ukuran font sampai cocok.


119
Mungkin salah satu fitur paling menakjubkan yang seharusnya ditambahkan ke HTML5 / CSS3 tanpa perlu JS.
John Magnolia

Saya melakukan beberapa pengukuran di mana saya mengubah panjang teks dinamis, dan ukuran wadah untuk mengetahui ukuran font mana yang akan membuat teks pas. Dan setelah melakukan beberapa analisis regresi, saya datang dengan fungsi matematika sederhana yang secara otomatis akan menghasilkan ukuran font terbaik.
Teman Kim

2
Sebenarnya ternyata grafik yang memberi Anda ukuran font terbaik diberikan oleh f (x) = g (huruf) * (x / 1000) ^ n, di mana g (x) adalah fungsi sederhana, n bervariasi tergantung pada font yang Anda gunakan. (Meskipun dapat memiliki nilai standar untuk semua font, jika Anda tidak ingin mengubahnya untuk membuatnya benar-benar sempurna ...). x adalah ukuran dalam piksel persegi wadah.
Teman Kim

1
Jika Anda masih tertarik, saya dapat menambahkan jawaban. Secara pribadi saya pikir itu metode yang jauh lebih baik untuk menghasilkan ukuran font yang benar di tempat pertama, daripada mencoba dan gagal sampai script "beres".
Teman Kim

1
Periksa jawaban saya untuk cara yang lebih baik untuk melakukan ini
Hoffmann

Jawaban:


167

Terima kasih Attack . Saya ingin menggunakan jQuery.

Anda menunjuk saya ke arah yang benar, dan inilah yang akhirnya saya dapatkan:

Berikut ini tautan ke plugin: https://plugins.jquery.com/textfill/
Dan tautan ke sumber: 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 });
});

dan html saya seperti ini

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

Ini adalah plugin jquery pertama saya, jadi mungkin tidak sebagus yang seharusnya. Pointer tentu diterima.


8
Aku benar-benar hanya membersihkan diri dan dikemas sebagai tersedia Plugin dari jquery.com di plugins.jquery.com/project/TextFill
GeekyMonkey

3
@ GeekyMonkey, apakah Anda menarik plugin? Cukup ikuti tautan dupe ke halaman ini, dan saya pikir saya akan melihatnya, tetapi tautan jQuery.com ke situs Anda kembali 404.
David mengatakan mengembalikan Monica

Catatan: Saya menemukan bahwa karena alasan tertentu plugin ini hanya berfungsi ketika div ($ ('. Jtextfill') dalam contoh di atas) adalah bagian dari dokumen root. Sepertinya .width () mengembalikan nol ketika div tertanam di dalam div lain.
Jayesh

1
Baris "while" pada loop itu terlihat salah bagi saya - harus ada tanda kurung di sekitar "||" subekspresi. Cara ini ditulis sekarang, ukuran font minimum hanya diperiksa ketika lebarnya terlalu besar, bukan tinggi.
Runcing

4
Pendekatan ini SANGAT lambat, setiap kali font berubah ukuran, elemen tersebut harus di-render ulang. Periksa jawaban saya untuk cara yang lebih baik untuk melakukan ini.
Hoffmann

52

Saya tidak menemukan salah satu solusi sebelumnya yang cukup memadai karena kinerja yang buruk, jadi saya membuat sendiri yang menggunakan matematika sederhana alih-alih perulangan. Seharusnya berfungsi dengan baik di semua browser juga.

Menurut kasus uji kinerja ini jauh lebih cepat daripada solusi lain yang ditemukan di sini.

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

Jika Anda ingin berkontribusi saya telah menambahkan ini ke Gist .


1
@ Jon, terima kasih! Anda benar bahwa skrip saya tidak melakukan banyak baris, tetapi sekali lagi OP tidak secara spesifik menanyakannya sehingga asumsi Anda mungkin salah. Juga, perilaku semacam itu tidak masuk akal. Saya kira cara terbaik untuk menambahkan dukungan multi-line adalah dengan membagi string berdasarkan jumlah kata dan kemudian menghitung setiap bagian dengan skrip di atas dan kemungkinan besar akan lebih cepat pula.
mekwall

4
@ Jon, saya bermain-main sedikit dengan multiline textfill dan berakhir dengan solusi ini . Metode sandstorm kemungkinan besar lebih akurat tetapi yang ini lebih cepat;)
mekwall

2
Ini adalah versi dengan ukuran font minimum dan maksimum: gist.github.com/1714284
Jess Telford

1
@ Hoffmann Hmm. Solusi saya tidak memanggil .css("font-size")dalam satu lingkaran. Dari mana Anda mendapatkan itu? Solusi saya mungkin lebih cepat karena tidak ada hal-hal mewah yang Anda tambahkan ke plugin Anda. Anda dapat menambahkan plugin Anda ke jsperf dan kita akan melihat mana yang paling cepat;)
mekwall

1
@ MarscusEkwall Oh maaf, untuk beberapa alasan saya pikir saya melihat loop sementara di sana. Pendekatan Anda mirip dengan saya sendiri dan memang saya akan sedikit lebih lambat karena plugin saya juga melakukan beberapa hal lain (seperti menyesuaikan agar sesuai dengan tinggi dan lebar, memusatkan teks dan beberapa opsi lain), tidak masalah, bagian yang sangat lambat memanggil fungsi .css di dalam satu lingkaran.
Hoffmann

35

Meskipun saya suka upvotes yang sesekali saya dapatkan untuk jawaban ini (terima kasih!), Ini sebenarnya bukan pendekatan terhebat untuk masalah ini. Silakan periksa beberapa jawaban indah lainnya di sini, terutama yang telah menemukan solusi tanpa mengulang.


Namun, demi referensi, inilah jawaban asli saya :

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

Dan inilah versi dengan kelas :

<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
Saya menemukan ini bekerja lebih baik dengan offsetWidth, saya juga harus membuat variabel untuk ukuran dan kemudian menambahkan pxtextSpan.style.fontSize = size+"px";
Wez

2
yakin '+ "px"' diperlukan.
sandun dhammika

@IdanShechter Maaf untuk menunggu sangat lama! Menambahkan contoh!
serang

Terima kasih, penyelamat hidup! Saya tidak mengetahui jQuery, jadi saya tetap dengan solusi Anda :)
vintproykt

32

Sebagian besar jawaban lain menggunakan loop untuk mengurangi ukuran font hingga pas pada div, ini SANGAT lambat karena halaman perlu merender ulang elemen setiap kali font berubah ukuran. Saya akhirnya harus menulis algoritma saya sendiri untuk membuatnya tampil dengan cara yang memungkinkan saya untuk memperbarui isinya secara berkala tanpa membekukan browser pengguna. Saya menambahkan beberapa fungsionalitas lain (memutar teks, menambahkan padding) dan mengemasnya sebagai plugin jQuery, Anda bisa mendapatkannya di:

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

cukup telepon

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

dan itu akan pas dengan wadah Anda.

Lihat beraksi di sini:

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

Untuk saat ini memiliki beberapa batasan, div harus memiliki tinggi dan lebar yang tetap dan tidak mendukung pembungkusan teks menjadi beberapa baris.

Saya akan berusaha untuk mendapatkan opsi untuk mengatur ukuran font maksimum.

Sunting: Saya telah menemukan beberapa masalah dengan plugin, itu tidak menangani model kotak lain selain yang standar dan div tidak dapat memiliki margin atau batas. Saya akan mengerjakannya.

Sunting2: Saya sekarang telah memperbaiki masalah dan keterbatasan itu dan menambahkan lebih banyak opsi. Anda dapat mengatur ukuran font maksimum dan Anda juga dapat memilih untuk membatasi ukuran font menggunakan lebar, tinggi atau keduanya. Saya akan berusaha menerima nilai lebar-lebar dan tinggi-maksimum di elemen pembungkus.

Edit3: Saya telah memperbarui plugin ke versi 1.2.0. Pembersihan besar-besaran pada kode dan opsi baru (verticalAlign, horizontalAlign, textAlign) dan dukungan untuk elemen-elemen dalam di dalam tag span (seperti ikon garis-putus atau ikon-mengagumkan.)


1
Saya bertanya-tanya mengapa membungkus teks ke dalam beberapa baris tidak didukung?
Manish Sapariya

1
@ManishSapariya Didukung, tetapi Anda perlu menambahkan jeda baris (br tag) secara manual. Alasan saya tidak mendukung bungkus teks otomatis adalah karena membuatnya cepat (hanya mengubah ukuran font dua kali alih-alih berkali-kali) Saya perlu membuat asumsi bahwa teks tidak akan membungkus di antara kata-kata. Cara kerja plugin saya adalah mengatur ukuran font menjadi 1000px kemudian melihat faktor ukuran teks dibandingkan dengan wadah, saya kemudian mengurangi ukuran font dengan faktor yang sama. Untuk mendukung pembungkusan teks biasa saya perlu menggunakan pendekatan lambat (mengurangi ukuran font beberapa kali) yang sangat lambat.
Hoffmann

Hei! Karena tidak ada pesan pribadi di sini, di StackOverflow, saya harus bertanya kepada Anda dengan mengomentari jawaban Anda. Saya suka plugin jQuery Anda, tetapi saya tidak bisa membuatnya bekerja untuk saya. Saya telah memasukkan pustaka jQuery yang tepat, mengunduh plugin Anda dan memasukkannya. Sekarang ketika saya mencoba dan menggunakannya, konsol mengatakan 'Uncaught TypeError: undefined bukan fungsi'. Apakah ini sesuatu yang Anda kenal? Apakah Anda tahu cara memperbaikinya? Terima kasih
Gust van de Wal

@GustvandeWal Anda harus menyertakan plugin setelah menyertakan perpustakaan jquery
Hoffmann

Aku melakukannya. Saya punya <script type = "text / javascript" src = " code.jquery.com/jquery-2.1.1.min.js"></… src" js / jquery-bigtext.js "> </ script > Browser tidak memberi tahu saya bahwa itu tidak dapat memuat perpustakaan jQuery atau plugin.
Gust van de Wal

9

Ini didasarkan pada apa yang diposting GeekyMonkey di atas, dengan beberapa modifikasi.

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

Perbedaannya adalah bahwa ia dapat mengambil banyak elemen anak, dan itu perlu padding ke akun. Menggunakan ukuran font sebagai ukuran maksimum default, untuk menghindari pencampuran javascript dan css.
sandstrom

5
Ini bagus, tapi bagaimana cara menggunakannya? Saya melakukan $ ('. Luar'). Textfill (); dan saya tidak mendapat perubahan.
Drew Baker

3
Terima kasih, ini adalah implementasi yang sangat bagus. Satu hal yang saya temui: jika Anda berurusan dengan string teks yang sangat panjang dan wadah yang sangat sempit, string teks akan tetap keluar dari wadah, tetapi outerWidth masih akan dihitung seolah-olah tidak. Aduk "bungkus kata: break-word;" ke dalam CSS Anda untuk wadah itu, itu akan memperbaiki masalah ini.
Jon

8

Berikut adalah metode pengulangan yang ditingkatkan yang menggunakan pencarian biner untuk menemukan ukuran terbesar yang sesuai dengan induk dalam langkah sesedikit mungkin (ini lebih cepat dan lebih akurat daripada melangkah dengan ukuran font tetap). Kode ini juga dioptimalkan dalam beberapa cara untuk kinerja.

Secara default, 10 langkah pencarian biner akan dilakukan, yang akan mencapai 0,1% dari ukuran optimal. Anda bisa mengatur numIter ke beberapa nilai N untuk mendapatkan dalam 1/2 ^ N dari ukuran optimal.

Sebut saja dengan pemilih CSS, misalnya: 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);
        }
    });
};

Suka opsi ini. Saya memodifikasinya untuk menambahkan parameter untuk vAligndan padding. vAlign == truemengatur ketinggian garis elemen yang dipilih dengan tinggi orangtua. Padding mengurangi ukuran akhir dengan nilai yang diteruskan. Standarnya menjadi 5. Saya pikir itu terlihat sangat bagus.
Pengacara Setan

6

Saya telah membuat arahan untuk AngularJS - sangat terinspirasi oleh jawaban GeekyMonkey tetapi tanpa ketergantungan jQuery.

Demo: http://plnkr.co/edit/8tPCZIjvO3VSApSeTtYr?p=preview

Markup

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

Pengarahan

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

Salah satu masalah yang saya alami dengan ini adalah bahwa resizeTexttampaknya dipanggil sebelum ng-bindbenar - benar memberikan teks ke elemen, sehingga ukurannya berdasarkan pada teks sebelumnya daripada teks saat ini. Ini tidak terlalu buruk dalam demo di atas di mana ia disebut berulang kali sebagai tipe pengguna, tetapi jika dipanggil sekali pergi dari nol ke nilai nyata (seperti dalam satu arah mengikat) itu tetap pada ukuran maksimal.
Miral

5

Saya bercabang script di atas dari Marcus Ekwall: https://gist.github.com/3945316 dan men-tweak itu untuk preferensi saya, sekarang menyala ketika jendela diubah ukurannya, sehingga anak selalu sesuai wadahnya. Saya telah menempelkan skrip di bawah ini untuk referensi.

(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
Sangat bagus bahwa Anda mencoba untuk membantu penanya keluar. Namun, meninggalkan jawaban hanya dengan tautan dapat berbahaya dalam beberapa kasus. Sementara jawaban Anda baik sekarang, jika tautannya pernah mati, jawaban Anda akan kehilangan nilainya. Jadi akan sangat membantu jika Anda meringkas konten dari artikel dalam jawaban Anda. Lihat pertanyaan ini untuk klarifikasi.
Cody Guldner

5

Inilah modifikasi saya atas jawaban OP.

Singkatnya, banyak orang yang mencoba mengoptimalkan ini mengeluh bahwa loop sedang digunakan. Ya, meskipun loop bisa lambat, pendekatan lain mungkin tidak akurat.

Karena itu, pendekatan saya menggunakan Binary Search untuk menemukan Ukuran Font terbaik:

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

Ini juga memungkinkan elemen menentukan font minimum dan maksimum:

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

Lebih lanjut, algoritma ini tidak memiliki unit. Anda dapat menentukan em, rem, %, dll dan akan menggunakannya untuk hasil akhir.

Inilah Fiddle: https://jsfiddle.net/fkhqhnqe/1/


2

Saya memiliki masalah yang persis sama dengan situs web saya. Saya memiliki halaman yang ditampilkan pada proyektor, di dinding, layar besar ..

Karena saya tidak tahu ukuran maksimum font saya, saya menggunakan kembali plugin di atas dari @GeekMonkey tetapi menambah ukuran font:

$.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 untuk menjadi satu-satunya plugin di halaman ini yang benar-benar berfungsi untuk saya!
skybondsor

2
Plugin ini membuat saya crash halaman.
Jezen Thomas

1

Ini adalah versi dari jawaban yang diterima yang juga dapat mengambil parameter 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);

terima kasih, meskipun saya pikir Anda punya titik koma di bagian atas kode yang seharusnya tidak ada
Patrick Moore

1

Anda dapat menggunakan FitText.js ( halaman github ) untuk menyelesaikan masalah ini. Sangat kecil dan efisien dibandingkan dengan TextFill. TextFill menggunakan loop sementara yang mahal dan FitText tidak.

Juga FitText lebih fleksibel (saya menggunakannya dalam proyect dengan persyaratan yang sangat khusus dan berfungsi seperti jagoan!).

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>

Anda juga dapat mengatur opsi untuk itu:

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

CSS:

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

Dan jika Anda membutuhkannya, FitText juga memiliki versi no-jQuery .


Apakah fittext memperhitungkan ketinggian?
Manish Sapariya

1
@ManishSapariya tidak, tidak. Itu hanya membagi lebar kontainer dengan 10 dan menggunakannya sebagai ukuran font.
Dan H

1

EDIT: Kode ini digunakan untuk menampilkan catatan di atas video HTML5. Ini mengubah ukuran font dengan cepat ketika video diubah ukurannya (ketika jendela browser diubah ukurannya). Catatan terhubung ke video (seperti catatan di YouTube), itulah sebabnya kode menggunakan instance bukannya pegangan DOM langsung.

Sesuai permintaan saya akan memasukkan beberapa kode yang saya gunakan untuk mencapai ini. (Kotak teks di atas video HTML5.) Kode itu sudah lama ditulis, dan saya pikir itu cukup berantakan. Karena pertanyaan sudah dijawab dan jawaban sudah lama diterima, saya tidak repot menulis ulang ini. Tetapi jika ada yang ingin menyederhanakan ini sedikit, Anda lebih dari diterima!

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

Anda mungkin perlu mengubah angka-angka ini dari font-family ke font-family. Cara yang baik untuk melakukan ini adalah mengunduh visualizer grafik gratis yang disebut GeoGebra. Ubah panjang teks dan ukuran kotak. Kemudian Anda mengatur ukuran secara manual. Plot hasil manual ke dalam sistem koordinat. Kemudian Anda memasukkan dua persamaan yang saya posting di sini dan Anda mengubah angka-angka sampai grafik "saya" cocok dengan poin yang Anda buat secara manual.


1

Solusi iteratif yang diusulkan dapat dipercepat secara dramatis di dua bidang:

1) Lipat gandakan ukuran font dengan konstanta, daripada menambah atau mengurangi 1.

2) Pertama, nol dalam menggunakan konstanta saja, katakanlah, gandakan ukuran setiap loop. Kemudian, dengan ide kasar dari mana harus memulai, lakukan hal yang sama dengan penyesuaian yang lebih baik, katakanlah, kalikan dengan 1.1. Sementara perfeksionis mungkin menginginkan ukuran piksel integer yang tepat dari font yang ideal, sebagian besar pengamat tidak melihat perbedaan antara 100 dan 110 piksel. Jika Anda perfeksionis, ulangi untuk yang ketiga kalinya dengan penyesuaian yang bahkan lebih baik.

Daripada menulis rutin atau plug-in tertentu yang menjawab pertanyaan yang tepat, saya hanya mengandalkan ide-ide dasar dan menulis variasi kode untuk menangani semua jenis masalah tata letak, bukan hanya teks, termasuk pas div, rentang, gambar,. .. berdasarkan lebar, tinggi, luas, ... dalam sebuah wadah, cocok dengan elemen lain ....

Ini sebuah contoh:

  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

Ini adalah solusi paling elegan yang saya buat. Ini menggunakan pencarian biner, melakukan 10 iterasi. Cara naif adalah melakukan loop sementara dan meningkatkan ukuran font sebanyak 1 hingga elemen mulai meluap. Anda bisa menentukan kapan suatu elemen mulai meluap menggunakan element.offsetHeight dan element.scrollHeight . Jika scrollHeight lebih besar dari offsetHeight, Anda memiliki ukuran font yang terlalu besar.

Pencarian biner adalah algoritma yang jauh lebih baik untuk ini. Itu juga dibatasi oleh jumlah iterasi yang ingin Anda lakukan. Cukup panggil flexFont dan masukkan id id dan itu akan menyesuaikan ukuran font antara 8px dan 96px .

Saya telah menghabiskan beberapa waktu meneliti topik ini dan mencoba berbagai perpustakaan, tetapi pada akhirnya saya pikir ini adalah solusi termudah dan paling mudah yang benar-benar akan berhasil.

Catatan jika mau, Anda dapat mengubah untuk menggunakan offsetWidthdan scrollWidth, atau menambahkan keduanya ke fungsi ini.

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

Terima kasih, ini terlihat hebat! Saya baru saja mendapatkan ReferenceError: lastSizeTooSmall is not defined. Mungkin itu perlu didefinisikan di suatu tempat?
ndbroadbent

0

Saya mendapat masalah yang sama dan solusinya pada dasarnya menggunakan javascript untuk mengontrol ukuran font. Lihat contoh ini pada codepen:

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

Ini adalah contoh hanya untuk tinggi, mungkin Anda perlu menaruh jika tentang lebar.

coba ubah ukurannya

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

saya suka

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

Hanya ingin menambahkan versi saya untuk konten yang dapat diedit.

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

Saya telah menemukan cara untuk mencegah penggunaan loop untuk menyusutkan teks. Ini menyesuaikan ukuran font dengan mengalikannya untuk tingkat antara lebar wadah dan lebar konten. Jadi, jika lebar penampung adalah 1/3 dari konten, ukuran font akan berkurang 1/3 dan lebar penampung. Untuk meningkatkan, saya telah menggunakan loop sementara, hingga konten lebih besar dari wadah.

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

Kode ini adalah bagian dari tes yang saya unggah ke Github https://github.com/ricardobrg/fitText/


0

Saya menggunakan solusi geekMonkey, tetapi terlalu lambat. Apa yang dia lakukan, adalah dia menyesuaikan ukuran font ke maksimum (maxFontPixels) dan kemudian memeriksa apakah cocok di dalam wadah. selain itu mengurangi ukuran font sebanyak 1px dan memeriksa lagi. Mengapa tidak memeriksa ketinggian wadah sebelumnya dan mengirimkan nilai itu? (ya, saya tahu mengapa, tetapi saya sekarang membuat solusi, yang hanya berfungsi pada ketinggian dan juga memiliki opsi min / max)

Inilah solusi yang jauh lebih cepat:

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

dan ini akan menjadi HTML:

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

Sekali lagi: solusi ini HANYA memeriksa ketinggian wadah. Itu sebabnya fungsi ini tidak harus memeriksa, jika elemen cocok di dalam. Tapi saya juga menerapkan nilai min / max (40 menit, 150max) jadi bagi saya ini berfungsi dengan baik (dan juga bekerja pada ukuran jendela).


-1

Ini adalah versi lain dari solusi ini:

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";
    }
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.