Texto dinámico de tamaño automático para llenar un contenedor de tamaño fijo
Necesito mostrar el texto ingresado por el usuario en un div de tamaño fijo. Lo que quiero es que el tamaño de fuente se ajuste automáticamente para que el texto llene el cuadro tanto como sea posible.
Entonces, si el div es de 400 px x 300 px. Si alguien ingresa ABC, entonces es una fuente muy grande. Si ingresan un párrafo, será una fuente pequeña.
Probablemente quiera comenzar con un tamaño de fuente máximo, tal vez 32 píxeles, y aunque el texto sea demasiado grande para caber en el contenedor, reducir el tamaño de fuente hasta que quepa.
Esto es con lo que terminé:
Aquí hay un enlace al complemento: https://plugins.jquery.com/textfill/
Y un enlace a la fuente: 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 });
});
y mi HTML es así
<div class='jtextfill' style='width:100px;height:50px;'>
<span>My Text Here</span>
</div>
No encontré que ninguna de las soluciones anteriores fuera lo suficientemente adecuada debido al mal rendimiento, así que hice la mía propia que usa matemáticas simples en lugar de bucles. También debería funcionar bien en todos los navegadores.
Según este caso de prueba de rendimiento , es mucho más rápido que las otras soluciones que se encuentran aquí.
(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);
Si quieres contribuir, agregué esto a Gist .
Por mucho que me gusten los votos positivos ocasionales que recibo por esta respuesta (¡gracias!), este no es realmente el mejor enfoque para este problema. Consulte algunas de las otras respuestas maravillosas aquí, especialmente las que han encontrado soluciones sin bucles.
Aún así, a modo de referencia, aquí está mi respuesta original :
<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>
Y aquí hay una versión con clases :
<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>
La mayoría de las otras respuestas usan un bucle para reducir el tamaño de fuente hasta que quepa en el div, esto es MUY lento ya que la página necesita volver a representar el elemento cada vez que la fuente cambia de tamaño. Eventualmente tuve que escribir mi propio algoritmo para que funcionara de una manera que me permitiera actualizar su contenido periódicamente sin congelar el navegador del usuario. Agregué alguna otra funcionalidad (rotar texto, agregar relleno) y la empaqueté como un complemento jQuery, puedes obtenerla en:
https://github.com/DanielHoffmann/jquery-bigtext
simplemente llama
$("#text").bigText();
y encajará muy bien en su contenedor.
Véalo en acción aquí:
http://danielhoffmann.github.io/jquery-bigtext/
Por ahora tiene algunas limitaciones, el div debe tener una altura y un ancho fijos y no admite ajustar texto en varias líneas.
Trabajaré para obtener una opción para establecer el tamaño máximo de fuente.
Editar: encontré algunos problemas más con el complemento, no maneja otro modelo de caja además del estándar y el div no puede tener márgenes ni bordes. Voy a trabajar en él.
Edit2: ahora solucioné esos problemas y limitaciones y agregué más opciones. Puede establecer el tamaño de fuente máximo y también puede optar por limitar el tamaño de fuente usando el ancho, el alto o ambos. Trabajaré para aceptar valores de ancho máximo y alto máximo en el elemento contenedor.
Edit3: He actualizado el complemento a la versión 1.2.0. Limpieza importante en el código y nuevas opciones (verticalAlign, horizontalAlign, textAlign) y compatibilidad con elementos internos dentro de la etiqueta span (como saltos de línea o íconos de fuentes impresionantes).
Esto se basa en lo que GeekyMonkey publicó anteriormente, con algunas modificaciones.
; (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);