CSS puro para tornar o tamanho da fonte responsivo com base na quantidade dinâmica de caracteres

298

Eu sei que isso poderia ser resolvido facilmente com Javascript, mas estou interessado apenas em uma solução CSS pura.

Eu quero uma maneira de redimensionar dinamicamente o texto para que ele sempre caiba em uma div fixa. Aqui está o exemplo de marcação:

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

Eu estava pensando que talvez isso fosse possível especificando a largura do contêiner no ems e obtendo o tamanho da fonte para herdar esse valor?

DMTintner
fonte
1
Uau, espera. A especificação do widthno emcoisa s vai a outra maneira ao redor. É o widthque depende do font-size. @JosephSilber Isso é exatamente o que eu pensava.
Ana
1
Estou curioso sobre esta questão. Qual é a unidade para usar uma solução css pura em vez de escrever uma função javascript simples?
Austin Mullins
22
A unidade é simplesmente porque o problema existe e uma solução CSS pura seria incrível. Pense nas possibilidades de aplicar apenas alguns estilos e sabendo que seu conteúdo dinâmico nunca quebrará o design.
precisa saber é o seguinte
4
Caso alguém se depare com essa questão e não se importe em usar o JS, aqui está um plugin para fazê-lo. Fittextjs.com
DMTintner
2
fitText tem limites. Por exemplo, eu só quero executá-lo para telas pequenas, com mais ou menos 500px de largura, não quero que meus cabeçalhos explodam mais. Isso requer escrever mais JavaScript. A separação de preocupações se decompõe muito rapidamente quando você usa JavaScript para o layout. Nunca é apenas um forro rápido.
Costa

Respostas:

513

Acabei de descobrir que isso é possível usando unidades VW. São as unidades associadas à configuração da largura da janela de exibição. Existem algumas desvantagens, como a falta de suporte legado ao navegador, mas isso é definitivamente algo a considerar seriamente. Além disso, você ainda pode fornecer fallbacks para navegadores mais antigos, como:

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

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

DMTintner
fonte
30
Daria 2 ups para este. Soluções CSS para a vitória!
Mihkel L.
34
Dica profissional: você pode impedir que o texto fique muito pequeno e recuperar algum controle fazendo algo font-size:calc(100% + 2vw);parecido. É meio que min-font-size. O suporte do navegador para calcé semelhante a vw.
Prinzhorn
116
Voto positivo, mas agora estou me perguntando se isso realmente responde à pergunta original. Meu entendimento é que o tamanho do seu texto é dinâmico e você deseja alterar o tamanho da fonte para sempre se ajustar à largura do seu div(200px). Como isso resolve esse problema?
Floremin 03/02
26
Eu concordo com o sentimento de @ Floremin. Isso dimensiona TODOS os tamanhos de fonte com base na largura / altura da porta de visualização, não no contêiner da largura / altura do texto.
MickJuice
24
@ Floremin está certo, isso não aborda a questão. Este calcula tamanho da fonte como uma função da largura do recipiente, e não como uma função do comprimento da cadeia que se refere ao recipiente largura
Henry
113

CSS3 suporta novas dimensões que são relativas à porta de visualização. Mas isso não funciona no android <4.4

  1. 3.2vw = 3.2% da largura da janela de visualização
  2. 3.2vh = 3,2% da altura da janela de visualização
  3. 3.2vmin = Menor de 3.2vw ou 3.2vh
  4. 3.2vmax = Maior de 3.2vw ou 3.2vh

    body
    {
        font-size: 3.2vw;
    }

veja css-tricks.com / .... e também veja caniuse.com / ....

ou

Usar consulta de mídia . A maneira mais simples é usar dimensões em% ou em. Basta alterar o tamanho da fonte base, tudo mudará.

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

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


h5{
    font-size: 1.4em;
}

Use dimensões em % ou em . Basta alterar o tamanho da fonte base, tudo mudará. Na versão anterior, você poderia simplesmente mudar a fonte do corpo e não h1 todas as vezes ou deixar o tamanho da fonte padrão para o dispositivo e descansar

veja kyleschaeffer.com / .... para mais informações sobre em, px e%

aWebDeveloper
fonte
12
A pergunta era sobre a escala em relação ao contêiner, não a toda a janela de exibição.
Arnaud Weil
6
... e as perguntas era sobre o dimensionamento com base na quantidade de caracteres
Bravo
14

A única maneira provavelmente seria definir larguras diferentes para diferentes tamanhos de tela, mas essa abordagem é bastante imprecisa e você deve usar uma solução 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
fonte
12

Sei que estou ressuscitando uma pergunta há muito morta, mas tinha a mesma pergunta e queria acrescentar algo. Por favor, não me proíba por isso, eu senti que era importante o suficiente para justificar esta resposta, vou excluir, se necessário. @ Joseph Silber está errado, codificar todas as possibilidades é realmente uma maneira viável de fazer isso. A razão é porque, na verdade, não existem infinitas possibilidades. Bem, tecnicamente existem, mas 99% dos seus visitantes estarão usando uma resolução padrão. Isso é duplamente verdadeiro para dispositivos móveis (a principal razão do design responsivo da web) porque a maioria dos sistemas operacionais móveis executa aplicativos em tela cheia sem redimensionar a janela.

Além disso, a altura é praticamente irrelevante por causa da barra de rolagem (até certo ponto, eu deixaria imediatamente uma página da Web com mais de 1,80 metro de comprimento, mas isso geralmente é verdade), então você só precisa se preocupar com a largura. E realmente, as únicas larguras que você precisa codificar são as seguintes: 240, 320, 480 (para iThings mais antigos), 640, 800, 1024, 1280, 1440, 1600, 1920, 2048, 2560. Não se preocupe em 4k, ele inchará muito suas imagens e o tamanho 2560 esticado até 100% de largura ficará bem em um monitor 4k (eu testei isso). Além disso, não se preocupe com 720 (720x480), como sugerido no pôster anterior. É uma resolução usada quase exclusivamente por câmeras digitais e, mesmo assim, é muito incomum.

Se alguém estiver usando uma resolução exótica, quase todos os renderizadores criados nos últimos 15 anos serão redondos, portanto, se a largura da tela de alguém for, digamos. 1100, vai carregar a regra CSS 1024, seu site não deve quebrar. Isso torna desnecessária a contabilização de resoluções exóticas, tentando criar uma regra responsiva, e a idéia de que você precisa codificar para cada configuração possível pixel por pixel é ridícula, a menos que alguém esteja usando um navegador da Web tão desatualizado que seu site provavelmente não carregaria em tudo de qualquer maneira.

user281058
fonte
1
E agora 375 e 414 para o iPhone 6/6 +: - /
yar1
Potencialmente ainda mais fácil se você estiver usando SASS ou Compass e entrar em funções. Uma função poderia fazer todo esse CSS funcionar para você; escreva uma vez, use muitos.
Cjbarth # 28/17
altura é praticamente irrelevante até que você desligue o dispositivo 90º do seu lado, que é
Carvo Loco
Isso não tem nada a ver com a largura de um contêiner - do qual existem facilmente possibilidades infinitas.
mcheah
8

Para referência, uma solução não CSS:

Abaixo estão algumas JS que redimensionam uma fonte, dependendo do tamanho do texto em um contêiner.

Codepen com código ligeiramente modificado, mas com a mesma idéia abaixo:

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 mim, chamo essa função quando um usuário faz uma seleção em um menu suspenso e, em seguida, uma div no meu menu é preenchida (é aqui que ocorre a ocorrência de texto dinâmico).

    scaleFontSize("my_container_div");

Além disso, eu também uso reticências CSS ("...") para truncar textos ainda mais longos , assim:

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

Então, finalmente:

  • Pequeno texto: por exemplo, "MAÇÃS"

    Totalmente renderizado, boas letras grandes.

  • Texto longo: por exemplo, "MAÇÃS E LARANJAS"

    É reduzido em 70%, através da função de dimensionamento JS acima.

  • Texto super longo: por exemplo, "MAÇÃS, LARANJAS E BANAN ..."

    É reduzido em 70% E é truncado com reticências "...", através da função de dimensionamento JS acima, juntamente com a regra CSS.

Você também pode explorar a reprodução com espaçamento entre letras CSS para tornar o texto mais estreito, mantendo o mesmo tamanho de fonte.

MarsAndBack
fonte
votado
negativamente
2

Como muitos mencionados nos comentários da postagem do @ DMTinter, o OP estava perguntando sobre o número ("quantidade") de caracteres alterados. Ele também estava perguntando sobre CSS, mas como o @Alexander indicou, "não é possível apenas com CSS". Até onde eu sei, isso parece verdade neste momento, então também parece lógico que as pessoas desejem saber a próxima melhor coisa.

Não estou particularmente orgulhoso disso, mas funciona. Parece uma quantidade excessiva de código para realizá-lo. Este é o 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;
      }
    }
  }
}

Aqui está um JS Bin: http://jsbin.com/pidavon/edit?html,css,js,console,output
Sugira possíveis melhorias para ele (não estou realmente interessado em usar a tela para medir o texto ... parece como muita sobrecarga (?)).

Graças a @Pete para a função measureText: https://stackoverflow.com/a/4032497/442665

jbobbins
fonte
2

Esta solução também pode ajudar:

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

Funcionou bem para mim!

Gaurav Krishn
fonte
Como isso leva em conta a quebra de linha?
Leif Neland #
2
calc(42px + (60 - 42) * (100vw - 768px) / (1440 - 768));

use esta equação.

Para algo maior ou menor que 1440 e 768, você pode atribuir um valor estático ou aplicar a mesma abordagem.

A desvantagem da solução vw é que você não pode definir uma proporção de escala, digamos que um 5vw na resolução de tela 1440 pode ter o tamanho de fonte de 60px, o tamanho da fonte da sua ideia, mas quando você reduz a largura da janela para 768, pode acabar sendo 12px, não o mínimo que você deseja. Com essa abordagem, você pode definir o limite superior e o limite inferior, e a fonte se dimensionará no meio.

Shuwei
fonte
-2

Crie uma tabela de pesquisa que calcule o tamanho da fonte com base no comprimento da string dentro do seu <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 e ajuste todos os parâmetros por teste empírico.

Deixe-me mexer nisso
fonte
O teste empírico para parâmetros é essencialmente uma pesquisa binária com complexidade de tempo: O (log n).
Deixe-me mexer nisso
Você realmente esqueceu de chamar essa função, também o comprimento do array precisa ser acessado com sua propriedade.
Lukk 13/06/19
@ukuk: Obrigado pelo feedback. Corrigido agora.
Deixe-me mexer nisso