Reines CSS, um die Schriftgröße basierend auf der dynamischen Anzahl von Zeichen ansprechend zu gestalten

298

Ich weiß, dass dies mit Javascript ziemlich einfach gelöst werden kann, aber ich bin nur an einer reinen CSS-Lösung interessiert.

Ich möchte eine Möglichkeit, die Größe von Text dynamisch zu ändern, damit er immer in ein festes Div passt. Hier ist das Beispiel-Markup:

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

Ich dachte, dass dies möglicherweise möglich sein könnte, indem die Breite des Containers in ems angegeben und die Schriftgröße ermittelt wird, um diesen Wert zu erben.

DMTintner
quelle
1
Wow, warte. Die Angabe des widthin ems-Dings geht umgekehrt. Es ist das width, was davon abhängt font-size. @ JosephSilber Genau das habe ich mir gedacht.
Ana
1
Ich bin neugierig auf diese Frage. Was ist der Antrieb, eine reine CSS-Lösung zu verwenden, anstatt eine einfache Javascript-Funktion zu schreiben?
Austin Mullins
22
Das Laufwerk ist einfach, weil das Problem besteht und eine reine CSS-Lösung erstaunlich wäre. Denken Sie über die Möglichkeiten nach, nur wenige Stile anzuwenden, und wissen Sie, dass Ihr dynamischer Inhalt das Design niemals brechen wird.
DMTintner
4
Nur für den Fall, dass jemand über diese Frage stolpert und es nichts ausmacht, JS zu verwenden, hier ist ein Plugin dafür fittextjs.com
DMTintner
2
fitText hat Grenzen. Zum Beispiel möchte ich es nur für kleine Bildschirme mit einer Breite von mehr als 500 Pixel ausführen. Ich möchte nicht, dass meine Überschriften mehr in die Luft jagen. Dies erfordert das Schreiben von mehr JavaScript. Die Trennung von Bedenken bricht sehr schnell zusammen, wenn Sie JavaScript für das Layout verwenden. Es ist nie nur ein schneller Einzeiler.
Costa

Antworten:

513

Ich habe gerade herausgefunden, dass dies mit VW-Einheiten möglich ist. Dies sind die Einheiten, die mit dem Festlegen der Breite des Ansichtsfensters verbunden sind. Es gibt einige Nachteile, wie z. B. mangelnde Unterstützung für ältere Browser, aber dies ist definitiv etwas, über das man ernsthaft nachdenken sollte. Außerdem können Sie für ältere Browser wie folgt Fallbacks bereitstellen:

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

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

DMTintner
quelle
30
Würde 2 Ups für diesen geben. CSS-Lösungen für den Gewinn!
Mihkel L.
34
Pro-Tipp: Sie können verhindern, dass der Text zu klein wird, und die Kontrolle zurückerhalten, indem Sie etwas font-size:calc(100% + 2vw);Ähnliches tun . Es ist irgendwie min-font-size. Die Browserunterstützung für calcist ähnlich wie vw.
Prinzhorn
116
Upvoted, aber jetzt frage ich mich, ob dies tatsächlich die ursprüngliche Frage beantwortet. Nach meinem Verständnis ist Ihre Textlänge dynamisch und Sie möchten die Schriftgröße so ändern, dass sie immer der Breite Ihrer div(200 Pixel) entspricht. Wie löst dies das Problem?
Floremin
26
Ich stimme dem Gefühl von @ Floremin zu. Dadurch werden ALLE Schriftgrößen basierend auf der Breite / Höhe des Ansichtsfensters skaliert, nicht auf dem Container mit der Breite / Höhe des Texts.
MickJuice
24
@Floremin ist richtig, dies geht nicht auf die Frage ein. Dies berechnet die Schriftgröße als Funktion der Containerbreite, nicht als Funktion der Stringlänge, da sie sich auf die Containerbreite bezieht
Henry
113

CSS3 unterstützt neue Dimensionen, die sich auf den Ansichtsport beziehen. Aber das funktioniert nicht in Android <4.4

  1. 3,2vw = 3,2% der Breite des Ansichtsfensters
  2. 3,2vh = 3,2% der Höhe des Ansichtsfensters
  3. 3,2 vmin = kleiner als 3,2 vw oder 3,2 vh
  4. 3,2 vmax = größer als 3,2 vw oder 3,2 vh

    body
    {
        font-size: 3.2vw;
    }

siehe css-tricks.com / .... und siehe auch caniuse.com / ....

oder

Verwenden Medienabfrage .Simplest Weg Dimensionen in% oder em zu verwenden. Ändern Sie einfach die Grundschriftgröße, alles wird sich ändern.

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

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


h5{
    font-size: 1.4em;
}

Verwenden Sie die Abmessungen in % oder em . Ändern Sie einfach die Grundschriftgröße, alles wird sich ändern. In der vorherigen Version konnten Sie einfach die Hauptschriftart und nicht jedes Mal h1 ändern oder die Basisschriftgröße auf die Standardeinstellung des Geräts zurücksetzen und alle in em ruhen lassen

Weitere Informationen zu em, px und% finden Sie unter kyleschaeffer.com / ....

aWebDeveloper
quelle
12
Die Frage betraf die Skalierung relativ zum Container und nicht zum gesamten Ansichtsfenster.
Arnaud Weil
6
... und die Fragen betrafen die Skalierung basierend auf der Anzahl der Zeichen
Bravo
14

Der einzige Weg wäre wahrscheinlich, unterschiedliche Breiten für unterschiedliche Bildschirmgrößen festzulegen, aber dieser Ansatz ist ziemlich ungenau und Sie sollten eine js-Lösung verwenden.

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

Ich weiß, dass ich eine lange tote Frage wiederbelebe, aber ich hatte dieselbe Frage und wollte etwas hinzufügen. Bitte verbieten Sie mich nicht dafür. Ich fand es wichtig genug, um diese Antwort zu rechtfertigen. Ich werde sie bei Bedarf löschen. @Joseph Silber ist falsch, das Codieren aller Möglichkeiten ist tatsächlich ein praktikabler Weg, dies zu tun. Der Grund ist, dass es tatsächlich keine unendlichen Möglichkeiten gibt. Technisch gesehen gibt es das, aber 99% Ihrer Besucher verwenden eine Standardauflösung. Dies gilt in zweifacher Hinsicht für Mobilgeräte (der Hauptgrund für reaktionsschnelles Webdesign), da auf den meisten mobilen Betriebssystemen Apps im Vollbildmodus ohne Fenstergrößenänderung ausgeführt werden.

Außerdem spielt die Höhe aufgrund der Bildlaufleiste keine Rolle (bis zu einem gewissen Punkt würde ich sofort eine Webseite hinterlassen, die länger als 4 oder 5 Fuß ist, dies gilt jedoch meistens), sodass Sie sich nur um die Breite kümmern müssen. Die einzigen Breiten, für die Sie codieren müssen, sind die folgenden: 240, 320, 480 (für ältere iThings), 640, 800, 1024, 1280, 1440, 1600, 1920, 2048, 2560. Machen Sie sich nicht einmal die Mühe 4k, es wird Ihre Bilder zu sehr aufblähen und die auf 100% Breite gedehnte Größe 2560 sieht auf einem 4k-Monitor gut aus (ich habe dies getestet). Kümmern Sie sich auch nicht um 720 (720 x 480), wie im vorherigen Poster vorgeschlagen. Es ist eine Auflösung, die fast ausschließlich von Digitalkameras verwendet wird, und selbst dann ist es sehr ungewöhnlich.

Wenn jemand eine exotische Auflösung verwendet, wird fast jeder Renderer, der in den letzten 15 Jahren hergestellt wurde, abgerundet. Wenn also jemand eine Bildschirmbreite hat, sagen wir. 1100, es wird die 1024 CSS-Regel geladen, Ihre Site sollte nicht brechen. Dies macht die Berücksichtigung exotischer Auflösungen unnötig, indem versucht wird, eine Reaktionsregel zu erstellen, und die Idee, dass Sie Pixel für Pixel für jedes mögliche Setup codieren müssen, ist lächerlich, es sei denn, jemand verwendet einen Webbrowser, der so veraltet ist, dass Ihre Website wahrscheinlich nicht geladen wird alles sowieso.

user281058
quelle
1
Und jetzt 375 und 414 für iPhone
6/6
Möglicherweise noch einfacher, wenn Sie SASS oder Compass verwenden und in Funktionen einsteigen. Eine Funktion könnte die gesamte CSS-Arbeit für Sie erledigen. schreibe-einmal-benutze-viele.
CJBarth
Höhe ist so gut wie irrelevant, bis Sie das Gerät um 90 ° auf die Seite drehen, das heißt
Carvo Loco
Dies hat jedoch nichts mit der Breite eines Containers zu tun - von denen es leicht unendlich viele Möglichkeiten gibt.
mcheah
8

Als Referenz eine Nicht-CSS-Lösung:

Im Folgenden finden Sie einige JS, die die Größe einer Schriftart abhängig von der Textlänge in einem Container ändern.

Codepen mit leicht modifiziertem Code, aber der gleichen Idee wie unten:

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

Für mich rufe ich diese Funktion auf, wenn ein Benutzer eine Auswahl in einem Dropdown-Menü trifft und dann ein Div in meinem Menü ausgefüllt wird (hier tritt dynamischer Text auf).

    scaleFontSize("my_container_div");

Darüber hinaus verwende ich auch CSS-Ellipsen ("..."), um noch längeren Text abzuschneiden, wie zum Beispiel:

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

Also letztendlich:

  • Kurztext: zB "ÄPFEL"

    Vollständig gerenderte, schöne große Buchstaben.

  • Langtext : zB "ÄPFEL & ORANGEN"

    Wird über die obige JS-Skalierungsfunktion um 70% verkleinert.

  • Super langer Text: zB "APPLES & ORANGES & BANAN ..."

    Wird um 70% verkleinert UND wird über die obige JS-Skalierungsfunktion zusammen mit der CSS-Regel mit "..." - Ellipsen abgeschnitten.

Sie können auch das Spielen mit CSS-Buchstabenabständen untersuchen, um den Text bei gleicher Schriftgröße enger zu gestalten.

MarsAndBack
quelle
stimmte ab, als der Benutzer nach einer reinen CSS-Lösung
fragte
2

Wie viele in den Kommentaren zu @ DMTinters Beitrag erwähnt haben, fragte das OP nach der Anzahl ("Anzahl") der sich ändernden Zeichen. Er fragte auch nach CSS, aber wie @Alexander anzeigte, "ist es nicht nur mit CSS möglich". Soweit ich das beurteilen kann, scheint dies zu diesem Zeitpunkt der Fall zu sein, daher scheint es auch logisch, dass die Leute das nächstbeste wissen möchten.

Darauf bin ich nicht besonders stolz, aber es funktioniert. Scheint eine übermäßige Menge an Code zu sein, um dies zu erreichen. Das ist der Kern:

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

Hier ist ein JS-Bin: http://jsbin.com/pidavon/edit?html,css,js,console,output
Bitte schlagen Sie mögliche Verbesserungen vor (ich bin nicht wirklich daran interessiert, Canvas zum Messen des Textes zu verwenden ... scheint wie zu viel Overhead (?)).

Vielen Dank an @Pete für die MeasureText-Funktion: https://stackoverflow.com/a/4032497/442665

Spulen
quelle
2

Diese Lösung könnte auch helfen:

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

Es hat bei mir gut funktioniert!

Gaurav Krishn
quelle
Wie berücksichtigt dies den Zeilenumbruch?
Leif Neland
2
calc(42px + (60 - 42) * (100vw - 768px) / (1440 - 768));

Verwenden Sie diese Gleichung.

Für alles, was größer oder kleiner als 1440 und 768 ist, können Sie entweder einen statischen Wert angeben oder denselben Ansatz anwenden.

Der Nachteil bei der vw-Lösung besteht darin, dass Sie kein Skalierungsverhältnis einstellen können. Angenommen, ein 5vw bei einer Bildschirmauflösung von 1440 hat möglicherweise eine Schriftgröße von 60 Pixel, Ihre Ideenschriftgröße. Wenn Sie jedoch die Fensterbreite auf 768 verkleinern, kann dies zu einer Verkleinerung führen 12px, nicht das Minimum, das Sie wollen. Mit diesem Ansatz können Sie Ihre obere und untere Grenze festlegen, und die Schriftart skaliert sich dazwischen.

Shuwei
quelle
-2

Erstellen Sie eine Nachschlagetabelle, die die Schriftgröße basierend auf der Länge der Zeichenfolge in Ihrer berechnet <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';
}

Passen Sie alle Parameter durch empirische Tests an und stimmen Sie sie ab.

Lass mich darüber basteln
quelle
Das empirische Testen auf Parameter ist im Wesentlichen eine binäre Suche mit zeitlicher Komplexität: O (log n).
Lassen Sie mich darüber basteln
Sie haben tatsächlich vergessen, diese Funktion aufzurufen. Außerdem muss auf die Array-Länge mit ihrer Eigenschaft zugegriffen werden.
Lukk
@lukk: Danke für das Feedback. Es wurde jetzt behoben.
Lassen Sie mich darüber basteln