CSS puro per rendere reattiva la dimensione del carattere in base alla quantità dinamica di caratteri


298

So che questo potrebbe essere risolto abbastanza facilmente con Javascript, ma mi interessa solo una soluzione CSS pura.

Voglio un modo per ridimensionare dinamicamente il testo in modo che si adatti sempre a un div fisso. Ecco il markup di esempio:

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

Stavo pensando che forse questo potrebbe essere possibile specificando la larghezza del contenitore in ems e ottenendo la dimensione del carattere per ereditare quel valore?


1
Wow, aspetta. La specifica della cosa widthin ems va al contrario. È quello widthche dipende dal font-size. @JosephSilber Questo è esattamente quello che ho pensato.
Ana,

1
Sono curioso di questa domanda. Qual è l'unità per utilizzare una soluzione css pura invece di scrivere una semplice funzione javascript?
Austin Mullins,

22
L'unità è semplicemente perché il problema esiste e una soluzione CSS pura sarebbe sorprendente. Pensa alle possibilità di applicare solo alcuni stili e sapendo che i tuoi contenuti dinamici non romperanno mai il design.
DMTintner,

4
Nel caso in cui qualcuno si imbattesse in questa domanda e non dispiaccia usare JS, ecco un plugin per farlo fittextjs.com
DMTintner

2
fitText ha dei limiti. Ad esempio, voglio solo eseguirlo per schermi di piccole dimensioni, oltre la larghezza di circa 500 px, non voglio più far esplodere i titoli. Ciò richiede la scrittura di più JavaScript. La separazione delle preoccupazioni si interrompe molto rapidamente quando si utilizza JavaScript per il layout. Non è mai solo una veloce fodera.
Costa

Risposte:


513

Ho appena scoperto che questo è possibile utilizzando le unità VW. Sono le unità associate all'impostazione della larghezza della finestra. Ci sono alcuni inconvenienti, come la mancanza del supporto del browser legacy, ma questo è sicuramente qualcosa da considerare seriamente. Inoltre puoi ancora fornire fallback per i browser più vecchi in questo modo:

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

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


30
Darei 2 aumenti per questo. Soluzioni CSS per la vittoria!
Mihkel L.

34
Suggerimento pro: puoi impedire che il testo diventi troppo piccolo e ottenere un controllo indietro facendo qualcosa di font-size:calc(100% + 2vw);simile. È un pò min-font-size. Il supporto del browser per calcè simile a vw.
Prinzhorn,

116
Eseguito l'upgrade, ma ora mi chiedo se questo risponda effettivamente alla domanda originale. La mia comprensione è che la lunghezza del tuo testo è dinamica e vuoi cambiare la dimensione del carattere per adattarla sempre alla larghezza del tuo div(200px). Come risolve questo problema?
Floremin,

26
Sono d'accordo con il sentimento di @ Floremin. Ciò ridimensiona TUTTE le dimensioni dei caratteri in base alla larghezza / altezza della porta di visualizzazione, non al contenitore della larghezza / altezza del testo.
MickJuice,

24
@Floremin ha ragione, questo non affronta la domanda. Questo calcola la dimensione del carattere in funzione della larghezza del contenitore, non in funzione della lunghezza della stringa in relazione alla larghezza del contenitore
Henry

113

CSS3 supporta nuove dimensioni relative alla porta di visualizzazione. Ma questo non funziona in Android <4.4

  1. 3.2vw = 3.2% della larghezza della finestra
  2. 3.2 vh = 3.2% dell'altezza del viewport
  3. 3.2vmin = Più piccolo di 3.2vw o 3.2vh
  4. 3.2vmax = Più grande di 3.2vw o 3.2vh

    body
    {
        font-size: 3.2vw;
    }

vedi css-tricks.com / .... e guarda anche caniuse.com / ....

o

Usa media query. Il modo più semplice è usare le dimensioni in% o em. Basta cambiare la dimensione del carattere di base, tutto cambierà.

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

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


h5{
    font-size: 1.4em;
}

Usa le dimensioni in % o em . Basta cambiare la dimensione del carattere di base, tutto cambierà. Nel precedente potresti semplicemente cambiare il carattere del corpo e non h1 ogni volta o lasciare la dimensione del carattere di base sul valore predefinito del dispositivo e riposare tutto in em

vedi kyleschaeffer.com / .... per maggiori informazioni su em, px e%


12
La domanda riguardava il ridimensionamento rispetto al contenitore, non all'intera finestra.
Arnaud Weil,

6
... e le domande riguardavano il ridimensionamento in base alla quantità di personaggi
Bravo,


14

L'unico modo sarebbe probabilmente quello di impostare larghezze diverse per le diverse dimensioni dello schermo, ma questo approccio è piuttosto impreciso e dovresti usare una soluzione 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;
    }
}

12

So che sto risolvendo una domanda morta da tempo, ma avevo la stessa domanda e volevo aggiungere qualcosa. Per favore, non bandirmi per questo, ho ritenuto che fosse abbastanza importante giustificare questa risposta, eliminerò se necessario. @Joseph Silber ha torto, codificare tutte le possibilità in realtà è un modo fattibile per farlo. Il motivo è perché in realtà non ci sono infinite possibilità. Bene, tecnicamente ci sono, ma il 99% dei tuoi visitatori utilizzerà una risoluzione standard. Ciò è doppiamente vero per i dispositivi mobili (il motivo principale per la progettazione web reattiva) perché la maggior parte dei sistemi operativi mobili esegue app a schermo intero senza ridimensionamento delle finestre.

Inoltre, l'altezza è praticamente irrilevante a causa della barra di scorrimento (fino a un certo punto, lascerei immediatamente una pagina Web che era più di 4 o 5 piedi di lunghezza, ma questo è per lo più vera), quindi devi solo preoccuparti della larghezza. E davvero, le uniche larghezze che devi codificare sono le seguenti: 240, 320, 480 (per iThings meno recenti), 640, 800, 1024, 1280, 1440, 1600, 1920, 2048, 2560. Non preoccuparti nemmeno di 4k, gonferà troppo le tue immagini e la dimensione 2560 allungata al 100% della larghezza sembra perfetta su un monitor 4k (l'ho testato). Inoltre, non preoccuparti di 720 (720x480) come suggerito dal poster precedente. È una risoluzione usata quasi esclusivamente dalle fotocamere digitali e anche allora è molto rara.

Se qualcuno utilizza una risoluzione esotica, quasi tutti i renderer realizzati negli ultimi 15 anni verranno arrotondati, quindi se la larghezza dello schermo di qualcuno è, diciamo. 1100, caricherà la regola CSS 1024, il tuo sito non dovrebbe infrangersi. Ciò rende la contabilizzazione di risoluzioni esotiche cercando di creare una regola reattiva non necessaria e l'idea che sia necessario codificare per ogni possibile impostazione pixel per pixel è ridicola, a meno che qualcuno non stia utilizzando un browser Web così obsoleto che il tuo sito probabilmente non si carica tutto comunque.


1
E ora 375 e 414 per iPhone
6/6

Potenzialmente ancora più semplice se si utilizza SASS o Bussola e si accede alle funzioni. Una funzione potrebbe fare tutto ciò che CSS funziona per te; write-once-uso-molti.
cjbarth,

l'altezza è praticamente irrilevante finché non si gira il dispositivo di 90º su un lato, ovvero
Carvo Loco

Questo non ha nulla a che fare con la larghezza di un contenitore, di cui esistono facilmente infinite possibilità.
Sì,

8

Per riferimento, una soluzione non CSS:

Di seguito sono riportati alcuni JS che ridimensionano un carattere in base alla lunghezza del testo all'interno di un contenitore.

Codepen con codice leggermente modificato, ma stessa idea di seguito:

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%";
    }
}

Per me, chiamo questa funzione quando un utente effettua una selezione in un menu a discesa, quindi viene popolato un div nel mio menu (qui è dove si verifica il testo dinamico).

    scaleFontSize("my_container_div");

Inoltre, utilizzo anche i puntini di sospensione CSS ("...") per troncare anche il testo ancora più lungo , in questo modo:

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

Quindi, in definitiva:

  • Testo breve: ad es. "MELE"

    Completamente reso, belle lettere grandi.

  • Testo lungo: ad es. "MELE E ARANCE"

    Ottiene ridimensionato del 70%, tramite la funzione di ridimensionamento JS sopra.

  • Testo super lungo: ad es. "MELE E ARANCE & BANANO ..."

    Viene ridotto del 70% e viene troncato con una "..." ellissi, tramite la funzione di ridimensionamento JS sopra unita alla regola CSS.

Puoi anche esplorare giocando con la spaziatura tra lettere CSS per restringere il testo mantenendo le stesse dimensioni del carattere.


votato come l'utente chiedeva una soluzione CSS pura
AnotherLongUsername

2

Come molti hanno menzionato nei commenti al post di @ DMTinter, l'OP stava chiedendo il numero ("quantità") di caratteri che cambiano. Stava anche chiedendo informazioni sui CSS, ma come indicato da @Alexander, "non è possibile solo con i CSS". Per quanto ne so, sembra che sia vero in questo momento, quindi sembra anche logico che le persone vorrebbero sapere la prossima cosa migliore.

Non ne sono particolarmente orgoglioso, ma funziona. Sembra una quantità eccessiva di codice per realizzarlo. Questo è il nucleo:

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

Ecco un JS Bin: http://jsbin.com/pidavon/edit?html,css,js,console,output
Ti preghiamo di suggerire possibili miglioramenti ad esso (non sono davvero interessato a usare canvas per misurare il testo ... sembra come troppo sovraccarico (?)).

Grazie a @Pete per la funzione measureText: https://stackoverflow.com/a/4032497/442665


2

Questa soluzione potrebbe anche aiutare:

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

Ha funzionato bene per me!


In che modo questo tiene conto del ritorno a capo automatico?
Leif Neland,


2
calc(42px + (60 - 42) * (100vw - 768px) / (1440 - 768));

usa questa equazione.

Per qualcosa di più grande o più piccolo di 1440 e 768, puoi dargli un valore statico o applicare lo stesso approccio.

Lo svantaggio con la soluzione vw è che non è possibile impostare un rapporto di scala, ad esempio un 5vw alla risoluzione dello schermo 1440 potrebbe finire per essere 60px dimensione del carattere, la dimensione del carattere della tua idea, ma quando riduci la larghezza della finestra fino a 768, potrebbe finire essendo 12px, non il minimo che desideri. Con questo approccio, puoi impostare il limite superiore e il limite inferiore e il carattere si ridimensionerà in mezzo.


-2

Crea una tabella di ricerca che calcola la dimensione del carattere in base alla lunghezza della stringa all'interno di <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';
}

Regola e ottimizza tutti i parametri mediante test empirici.


Il test empirico per i parametri è essenzialmente una ricerca binaria con complessità temporale: O (log n).
Let Me Tink About It

In realtà hai dimenticato di chiamare questa funzione, inoltre è necessario accedere alla lunghezza dell'array con la sua proprietà.
lukk,

@lukk: grazie per il feedback. Risolto il problema ora.
Let Me Tink About It
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.