CSS puro para que el tamaño de fuente responda en función de la cantidad dinámica de caracteres

298

Sé que esto podría resolverse con bastante facilidad con Javascript, pero solo estoy interesado en una solución CSS pura.

Quiero una forma de redimensionar dinámicamente el texto para que siempre encaje en un div fijo. Aquí está el marcado de muestra:

<div style="width: 200px; height: 1em; overflow: hidden;">
  <p>Some sample dynamic amount of text here</p>
</div>

Estaba pensando que tal vez esto podría ser posible al especificar el ancho del contenedor en ems y obtener el tamaño de fuente para heredar ese valor.

DMTintner
fuente
1
Guau, espera. La especificación de la cosa widthin ems va al revés. Es lo widthque depende de font-size. @JosephSilber Eso es exactamente lo que pensé.
Ana
1
Tengo curiosidad por esta pregunta. ¿Cuál es el impulso para usar una solución css pura en lugar de escribir una función javascript simple?
Austin Mullins
22
La unidad es simplemente porque el problema existe y una solución CSS pura sería increíble. Piense en las posibilidades de aplicar solo unos pocos estilos y saber que su contenido dinámico nunca romperá el diseño.
DMTintner
44
En caso de que alguien tropiece con esta pregunta y no le importe
DMTintner
2
fitText tiene límites. Por ejemplo, solo quiero ejecutarlo para pantallas pequeñas, más allá de 500px de ancho, no quiero que mis títulos exploten más. Esto requiere escribir más JavaScript. La separación de preocupaciones se rompe muy rápidamente cuando usa JavaScript para el diseño. Nunca es solo un trazador de líneas rápido.
Costa

Respuestas:

513

Me acabo de enterar de que esto es posible utilizando unidades VW. Son las unidades asociadas con la configuración del ancho de la ventana gráfica. Hay algunos inconvenientes, como la falta de compatibilidad con el navegador heredado, pero esto definitivamente es algo para considerar seriamente el uso. Además, aún puede proporcionar retrocesos para navegadores antiguos de esta manera:

p {
    font-size: 30px;
    font-size: 3.5vw;
}

http://css-tricks.com/viewport-sized-typography/ y https://medium.com/design-ux/66bddb327bb1

DMTintner
fuente
30
Daría 2 ups para este. Soluciones CSS para la victoria!
Mihkel L.
34
Consejo profesional: puede evitar que el texto se vuelva demasiado pequeño y recuperar el control haciendo algo font-size:calc(100% + 2vw);similar. Es un poco min-font-size. El soporte del navegador calces similar a vw.
Prinzhorn
116
Votado, pero ahora me pregunto si esto realmente responde a la pregunta original. Tengo entendido que la longitud de su texto es dinámica y desea cambiar el tamaño de la fuente para que siempre se ajuste al ancho de su div(200px). ¿Cómo resuelve esto ese problema?
Floremin
26
Estoy de acuerdo con el sentimiento de @ Floremin. Esto escala TODOS los tamaños de fuente según el ancho / alto del puerto de vista, no el contenedor del ancho / alto del texto.
MickJuice
24
@Floremin tiene razón, esto no responde a la pregunta. Este tamaño de fuente calcula como una función de la anchura del recipiente, no como una función de la longitud de la cadena lo que se refiere a un contenedor ancho
Henry
113

CSS3 admite nuevas dimensiones que son relativas al puerto de visualización. Pero esto no funciona en Android <4.4

  1. 3.2vw = 3.2% del ancho de la ventana gráfica
  2. 3.2vh = 3.2% de la altura de la ventana gráfica
  3. 3.2vmin = Menor de 3.2vw o 3.2vh
  4. 3.2vmax = Mayor de 3.2vw o 3.2vh

    body
    {
        font-size: 3.2vw;
    }

ver css-tricks.com / .... y también mirar caniuse.com / ....

o

Usar consulta de medios. La forma más sencilla es usar dimensiones en% o em. Simplemente cambie el tamaño de fuente base, todo cambiará.

@media (max-width: @screen-xs) {
    body{font-size: 10px;}
}

@media (max-width: @screen-sm) {
    body{font-size: 14px;}
}


h5{
    font-size: 1.4em;
}

Utilice dimensiones en % o em . Simplemente cambie el tamaño de fuente base, todo cambiará. En el anterior, podría cambiar la fuente del cuerpo y no h1 cada vez o dejar que el tamaño de fuente base sea el predeterminado del dispositivo y descansar todo en em

ver kyleschaeffer.com / .... para más información sobre em, px y%

aWebDeveloper
fuente
12
La pregunta era acerca de la escala relativa al contenedor, no a toda la ventana gráfica.
Arnaud Weil
66
... y las preguntas eran sobre el escalado basado en la cantidad de caracteres
Bravo
14

Probablemente la única forma sería establecer diferentes anchos para diferentes tamaños de pantalla, pero este enfoque es bastante impreciso y debería usar una solución js.

h1 {
    font-size: 20px;
}

@media all and (max-device-width: 720px){
    h1 {
        font-size: 18px;
    }
}

@media all and (max-device-width: 640px){
    h1 {
        font-size: 16px;
    }
}

@media all and (max-device-width: 320px){
    h1 {
        font-size: 12px;
    }
}
Sven Rojek
fuente
12

Sé que estoy resucitando una pregunta largamente muerta, pero tenía la misma pregunta y quería agregar algo. Por favor, no me prohíban esto, sentí que era lo suficientemente importante como para justificar esta respuesta, lo eliminaré si es necesario. @Joseph Silber está equivocado, codificar todas las posibilidades en realidad es una forma viable de hacer esto. La razón es porque en realidad no hay infinitas posibilidades. Bueno, técnicamente los hay, pero el 99% de tus visitantes usarán una resolución estándar. Esto es doblemente cierto para dispositivos móviles (la razón principal del diseño web receptivo) porque la mayoría de los sistemas operativos móviles ejecutan aplicaciones a pantalla completa sin cambiar el tamaño de las ventanas.

Además, la altura es prácticamente irrelevante debido a la barra de desplazamiento (hasta cierto punto, inmediatamente dejaría una página web que tenía más de 4 o 5 pies de largo, pero esto es cierto en su mayoría), por lo que solo debe preocuparse por el ancho. Y realmente, los únicos anchos que necesita codificar son los siguientes: 240, 320, 480 (para iThings más antiguos), 640, 800, 1024, 1280, 1440, 1600, 1920, 2048, 2560. Ni siquiera se moleste por 4k, hinchará tus imágenes demasiado y el tamaño 2560 estirado al 100% de ancho se ve muy bien en un monitor 4k (lo he probado). Además, no te molestes con 720 (720x480) como sugiere el póster anterior. Es una resolución utilizada casi exclusivamente por cámaras digitales, e incluso entonces es muy poco común.

Si alguien está usando una resolución exótica, casi cualquier renderizador hecho en los últimos 15 años se redondeará, así que si el ancho de pantalla de alguien es, digamos. 1100, va a cargar la regla CSS 1024, su sitio no debería romperse. Esto hace innecesaria la explicación de resoluciones exóticas al tratar de crear una regla receptiva innecesaria, y la idea de que necesita codificar para cada configuración posible píxel por píxel es ridícula, a menos que alguien esté usando un navegador web tan desactualizado que su sitio probablemente no se cargará en De todos modos.

usuario281058
fuente
1
Y ahora 375 y 414 para iPhone
6/6
Potencialmente aún más fácil si usa SASS o Compass y entra en funciones. Una función podría hacer todo el trabajo de CSS para usted; escribir una vez usar muchas.
cjbarth
la altura es prácticamente irrelevante hasta que gira el dispositivo 90º de lado, es decir
Carvo Loco
Sin embargo, esto no tiene nada que ver con el ancho de un contenedor, de los cuales hay posibilidades infinitas fácilmente.
mcheah
8

Como referencia, una solución que no sea CSS:

A continuación hay algunos JS que redimensionan una fuente dependiendo de la longitud del texto dentro de un contenedor.

Codepen con código ligeramente modificado, pero la misma idea que a continuación:

function scaleFontSize(element) {
    var container = document.getElementById(element);

    // Reset font-size to 100% to begin
    container.style.fontSize = "100%";

    // Check if the text is wider than its container,
    // if so then reduce font-size
    if (container.scrollWidth > container.clientWidth) {
        container.style.fontSize = "70%";
    }
}

Para mí, llamo a esta función cuando un usuario realiza una selección en un menú desplegable, y luego se llena un div en mi menú (aquí es donde aparece el texto dinámico).

    scaleFontSize("my_container_div");

Además, también uso puntos suspensivos CSS ("...") para truncar texto aún más largo , así:

#my_container_div {
    width: 200px; /* width required for text-overflow to work */
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

Entonces, en última instancia:

  • Texto corto: por ejemplo, "MANZANAS"

    Completamente rendido, bonitas letras grandes.

  • Texto largo: por ejemplo, "MANZANAS Y NARANJAS"

    Se reduce 70%, a través de la función de escala JS anterior.

  • Texto superlargo: por ejemplo, "MANZANAS, NARANJAS Y BANAN ..."

    Se reduce 70% y se trunca con puntos suspensivos "...", a través de la función de escala JS anterior junto con la regla CSS.

También puede explorar jugar con el espacio entre letras CSS para hacer que el texto sea más estrecho y mantener el mismo tamaño de fuente.

MarsAndBack
fuente
rechazado ya que el usuario estaba pidiendo una solución CSS pura
AnotherLongUsername
2

Como muchos mencionaron en los comentarios a la publicación de @ DMTinter, el OP preguntaba por el número ("cantidad") de caracteres que cambiaban. También estaba preguntando sobre CSS, pero como indicó @Alexander, "no es posible solo con CSS". Por lo que puedo decir, eso parece ser cierto en este momento, por lo que también parece lógico que la gente quiera saber la próxima mejor opción.

No estoy particularmente orgulloso de esto, pero funciona. Parece una cantidad excesiva de código para lograrlo. Este es el núcleo:

function fitText(el){
  var text = el.text();
  var fsize = parseInt(el.css('font-size'));
  var measured = measureText(text, fsize);

  if (measured.width > el.width()){
    console.log('reducing');
    while(true){
      fsize = parseInt(el.css('font-size'));
      var m = measureText(text, fsize );
      if(m.width > el.width()){
        el.css('font-size', --fsize + 'px');
      }
      else{
        break;
      }
    }
  }
  else if (measured.width < el.width()){
    console.log('increasing');
    while(true){
      fsize = parseInt(el.css('font-size'));
      var m = measureText(text, fsize);
      if(m.width < el.width()-4){ // not sure why -4 is needed (often)
        el.css('font-size', ++fsize + 'px');
      }
      else{
        break;
      }
    }
  }
}

Aquí hay un contenedor JS: http://jsbin.com/pidavon/edit?html,css,js,console,output
Sugiera posibles mejoras (no estoy realmente interesado en usar el lienzo para medir el texto ... parece como demasiada sobrecarga (?)).

Gracias a @Pete por la función measureText: https://stackoverflow.com/a/4032497/442665

jbobbins
fuente
2

Esta solución también podría ayudar:

$(document).ready(function () {
    $(window).resize(function() {
        if ($(window).width() < 600) {
            $('body').css('font-size', '2.8vw' );
        } else if ($(window).width() >= 600 && $(window).width() < 750) {
            $('body').css('font-size', '2.4vw');
        } 
         // and so on... (according to our needs)
        } else if ($(window).width() >= 1200) {
            $('body').css('font-size', '1.2vw');
        }
    }); 
  });

¡Me funcionó bien!

Gaurav Krishn
fuente
¿Cómo toma esto en cuenta el ajuste de texto?
Leif Neland
2
calc(42px + (60 - 42) * (100vw - 768px) / (1440 - 768));

usa esta ecuación.

Para cualquier cosa mayor o menor que 1440 y 768, puede asignarle un valor estático o aplicar el mismo enfoque.

El inconveniente con la solución vw es que no puede establecer una relación de escala, digamos que 5vw con una resolución de pantalla de 1440 puede terminar siendo 60px tamaño de fuente, su tamaño de fuente ideal, pero cuando reduce el ancho de la ventana a 768, puede terminar siendo 12px, no el mínimo que quieres. Con este enfoque, puede establecer su límite superior y límite inferior, y la fuente se escalará en el medio.

Shuwei
fuente
-2

Cree una tabla de búsqueda que calcule el tamaño de fuente en función de la longitud de la cadena dentro de su <div>.

const fontSizeLookupTable = () => {
  // lookup table looks like: [ '72px', ..., '32px', ..., '16px', ..., ]
  let a = [];
  // adjust this based on how many characters you expect in your <div>
  a.length = 32;
  // adjust the following ranges empirically
  a.fill( '72px' ,     );
  a.fill( '32px' , 4 , );
  a.fill( '16px' , 8 , );
  // add more ranges as necessary
  return a;
}

const computeFontSize = stringLength => {
  const table = fontSizeLookupTable();
  return stringLength < table.length ? table[stringLength] : '16px';
}

Ajuste y ajuste todos los parámetros mediante prueba empírica.

Déjame pensarlo
fuente
La prueba empírica de parámetros es esencialmente una búsqueda binaria con complejidad de tiempo: O (log n).
Déjame pensarlo
De hecho, olvidó llamar a esta función, también se debe acceder a la longitud de la matriz con su propiedad.
lukk
@lukk: Gracias por los comentarios. Lo arregló ahora.
Déjame pensarlo