Czysty CSS, dzięki któremu rozmiar czcionki reaguje na podstawie dynamicznej liczby znaków

298

Wiem, że można to dość łatwo rozwiązać za pomocą Javascript, ale interesuje mnie tylko czyste rozwiązanie CSS.

Chcę sposób dynamicznie zmieniać rozmiar tekstu, aby zawsze mieścił się w stałym div. Oto przykładowy znacznik:

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

Myślałem, że może to być możliwe, określając szerokość kontenera w ems i sprawiając, że rozmiar czcionki odziedziczy tę wartość?

DMTintner
źródło
1
Wow, czekaj. Określająca Spośród widthW ems rzeczy przechodzi na odwrót. To widthzależy od font-size. @JosephSilber Właśnie tak myślałem.
Ana
1
Jestem ciekawa tego pytania. Jaki jest napęd do korzystania z czystego rozwiązania css zamiast pisania prostej funkcji javascript?
Austin Mullins,
22
Dysk jest po prostu dlatego, że problem istnieje, a czyste rozwiązanie CSS byłoby niesamowite. Pomyśl o możliwości zastosowania tylko kilku stylów i wiedz, że Twoja dynamiczna treść nigdy nie złamie projektu.
DMTintner
4
Na wypadek, gdyby ktoś natknął się na to pytanie i nie miał nic przeciwko użyciu JS, oto wtyczka do robienia tego fittextjs.com
DMTintner
2
fitText ma ograniczenia. Na przykład chcę go uruchamiać tylko na małych ekranach, o szerokości przekraczającej około 500 pikseli, nie chcę, aby moje nagłówki już wybuchały. Wymaga to napisania większej ilości kodu JavaScript. Rozdzielenie problemów rozpada się bardzo szybko, gdy używasz JavaScript do układu. To nigdy nie jest tylko szybki liniowiec.
Costa

Odpowiedzi:

513

Właśnie dowiedziałem się, że jest to możliwe przy użyciu jednostek VW. Są to jednostki związane z ustawieniem szerokości rzutni. Istnieją pewne wady, takie jak brak starszej obsługi przeglądarki, ale jest to zdecydowanie coś, co należy poważnie rozważyć. Ponadto nadal możesz zapewnić rezerwy dla starszych przeglądarek, takich jak:

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

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

DMTintner
źródło
30
Dałbym 2 ups za ten. Rozwiązania CSS dla wygranej!
Mihkel L.
34
Porada profesjonalisty: możesz zapobiec zbyt małemu rozmiarowi tekstu i odzyskać kontrolę, wykonując font-size:calc(100% + 2vw);podobne czynności. To trochę min-font-size. Obsługa przeglądarki calcjest podobna do vw.
Prinzhorn
116
Głosowałem, ale teraz zastanawiam się, czy to faktycznie odpowiada na pierwotne pytanie. Rozumiem, że długość tekstu jest dynamiczna i chcesz zmienić rozmiar czcionki, aby zawsze pasował do szerokości twojego div(200px). Jak to rozwiązuje ten problem?
Floremin
26
Zgadzam się z sentymentem @ Floremina. Skaluje WSZYSTKIE rozmiary czcionek na podstawie szerokości / wysokości widoku, a nie kontenera szerokości / wysokości tekstu.
MickJuice,
24
@Floremin ma rację, to nie dotyczy pytania. Oblicza to rozmiar czcionki jako funkcję szerokości pojemnika, a nie funkcję długości łańcucha, ponieważ odnosi się do szerokości pojemnika
henry
113

CSS3 obsługuje nowe wymiary względem portu widoku. Ale to nie działa w Androidzie <4.4

  1. 3,2 vw = 3,2% szerokości rzutni
  2. 3,2vh = 3,2% wysokości rzutni
  3. 3.2vmin = Mniejszy z 3.2vw lub 3.2vh
  4. 3.2vmax = Większa z 3.2vw lub 3.2vh

    body
    {
        font-size: 3.2vw;
    }

patrz css-tricks.com / .... a także spójrz na caniuse.com / ....

lub

Użyj zapytania o media. Najprostszym sposobem jest użycie wymiarów w% lub em. Wystarczy zmienić podstawowy rozmiar czcionki, wszystko się zmieni.

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

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


h5{
    font-size: 1.4em;
}

Użyj wymiarów w % lub em . Wystarczy zmienić podstawowy rozmiar czcionki, wszystko się zmieni. W poprzednim można po prostu zmienić czcionkę ciała, a nie h1 za każdym razem, lub pozwolić, aby podstawowy rozmiar czcionki był domyślny dla urządzenia i spoczywał w nich

zobacz kyleschaeffer.com / ...., aby uzyskać więcej informacji na temat em, px i%

aWebDeveloper
źródło
12
Pytanie dotyczyło skalowania względem kontenera, a nie całej rzutni.
Arnaud Weil
6
... a pytania dotyczyły skalowania na podstawie liczby znaków
Bravo,
14

Jedynym sposobem byłoby prawdopodobnie ustawienie różnych szerokości dla różnych rozmiarów ekranu, ale takie podejście jest dość niedokładne i powinieneś użyć rozwiązania 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
źródło
12

Wiem, że zastanawiam się od dawna martwe pytanie, ale miałem to samo pytanie i chciałem coś dodać. Proszę, nie zbanuj mnie za to, uważam, że było to wystarczająco ważne, aby uzasadnić tę odpowiedź, w razie potrzeby usunę ją. @Joseph Silber się myli, kodowanie wszystkich możliwości jest realnym sposobem na zrobienie tego. Powodem jest to, że tak naprawdę nie ma nieskończonych możliwości. Technicznie są, ale 99% odwiedzających będzie korzystało ze standardowej rozdzielczości. Jest to podwójnie prawdziwe w przypadku urządzeń mobilnych (główny powód elastycznego projektowania stron internetowych), ponieważ większość mobilnych systemów operacyjnych uruchamia aplikacje na pełnym ekranie bez zmiany rozmiaru okna.

Ponadto wysokość jest praktycznie nieistotna ze względu na pasek przewijania (do tego stopnia, że ​​od razu opuszczałbym stronę internetową, która miała więcej niż 4 lub 5 stóp długości, ale w większości jest to prawda), więc musisz się tylko martwić o szerokość. I tak naprawdę, jedyne szerokości, które musisz zakodować to: 240, 320, 480 (dla starszych iThings), 640, 800, 1024, 1280, 1440, 1600, 1920, 2048, 2560. Nawet nie zawracaj sobie głowy 4k, zbyt mocno rozleje twoje zdjęcia, a rozmiar 2560 rozciągnięty do 100% szerokości wygląda dobrze na monitorze 4k (przetestowałem to). Nie przejmuj się także 720 (720x480), jak sugerował poprzedni plakat. Jest to rozdzielczość używana prawie wyłącznie przez aparaty cyfrowe, a nawet wtedy jest bardzo rzadka.

Jeśli ktoś używa egzotycznej rozdzielczości, prawie każdy renderer wykonany w ciągu ostatnich 15 lat zaokrągli w dół, więc jeśli ktoś ma szerokość ekranu, powiedzmy. 1100, ładuje regułę 1024 CSS, twoja strona nie powinna się zepsuć. To sprawia, że ​​rozliczanie się z egzotycznych rozdzielczości nie jest konieczne, a próba stworzenia responsywnej reguły jest niepotrzebna, a pomysł, że musisz kodować każdą możliwą konfigurację piksel po pikselu, jest absurdalny, chyba że ktoś używa przeglądarki internetowej tak przestarzałej, że Twoja witryna prawdopodobnie nie załaduje się na i tak wszystko.

użytkownik 281058
źródło
1
A teraz 375 i 414 dla iPhone'a
6/6
Potencjalnie jeszcze łatwiej, jeśli używasz SASS lub Compass i wchodzisz w funkcje. Funkcja może wykonać całą pracę CSS za Ciebie; napisz-raz-użyj-wielu.
cjbarth
wysokość nie ma większego znaczenia, dopóki nie
obrócisz
Nie ma to jednak nic wspólnego z szerokością kontenera - z czego istnieją nieskończone możliwości.
mcheah
8

Dla porównania rozwiązanie inne niż CSS:

Poniżej znajduje się część JS, która zmienia rozmiar czcionki w zależności od długości tekstu w kontenerze.

Codepen z nieco zmodyfikowanym kodem, ale taki sam pomysł jak poniżej:

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

Dla mnie wywołuję tę funkcję, gdy użytkownik dokonuje wyboru w menu rozwijanym, a następnie div w moim menu jest zapełniany (w tym miejscu pojawia się tekst dynamiczny).

    scaleFontSize("my_container_div");

Ponadto używam także elips CSS („...”), aby obciąć jeszcze dłużej tekst, tak jak poniżej:

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

Ostatecznie:

  • Krótki tekst: np. „JABŁKA”

    W pełni renderowane, ładne duże litery.

  • Długi tekst: np. „JABŁKA I POMARAŃCZE”

    Pobiera zmniejszone o 70%, dzięki powyższej funkcji skalowania JS.

  • Super długi tekst: np. „JABŁKA I POMARAŃCZE I BANAN ...”

    Pobiera zmniejszone o 70% ORAZ zostaje obcięte za pomocą elips „…”, dzięki powyższej funkcji skalowania JS wraz z regułą CSS.

Możesz także zbadać grę z odstępami między literami CSS, aby zawęzić tekst przy zachowaniu tego samego rozmiaru czcionki.

MarsAndBack
źródło
głosował za odrzuceniem, ponieważ użytkownik prosi o rozwiązanie czysto CSS
AnotherLongUsername
2

Jak wielu wspomniało w komentarzach do posta @ DMTinter, OP pytał o liczbę („ilość”) zmieniających się znaków. Pytał także o CSS, ale jak wskazał @Alexander, „nie jest to możliwe tylko z CSS”. O ile mogę powiedzieć, wydaje się to w tej chwili prawdą, więc wydaje się również logiczne, że ludzie chcieliby wiedzieć następną najlepszą rzecz.

Nie jestem z tego szczególnie dumny, ale działa. Wydaje się, że jest to zbyt duża ilość kodu, aby to osiągnąć. To jest rdzeń:

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

Oto JS Bin: http://jsbin.com/pidavon/edit?html,css,js,console,output
Proszę zasugerować możliwe ulepszenia (nie jestem zainteresowany wykorzystaniem płótna do pomiaru tekstu ... wydaje się jak za dużo narzutu (?)).

Dzięki @Pete za funkcję MeasureText: https://stackoverflow.com/a/4032497/442665

jbobbins
źródło
2

To rozwiązanie może również pomóc:

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

To działało dla mnie dobrze!

Gaurav Krishn
źródło
Jak to uwzględnia zawijanie wyrazów?
Leif Neland,
2
calc(42px + (60 - 42) * (100vw - 768px) / (1440 - 768));

użyj tego równania.

Dla czegokolwiek większego lub mniejszego niż 1440 i 768 możesz albo nadać mu wartość statyczną, albo zastosować to samo podejście.

Wadą rozwiązania vw jest to, że nie można ustawić współczynnika skali, powiedzmy, że 5vw przy rozdzielczości ekranu 1440 może skończyć się czcionką o wielkości 60px, czcionką pomysłu, ale kiedy zmniejszysz szerokość okna do 768, może to skończyć się 12 pikseli, a nie minimum, którego chcesz. Dzięki takiemu podejściu możesz ustawić górną i dolną granicę, a czcionka będzie się skalować między nimi.

Shuwei
źródło
-2

Utwórz tabelę odnośników, która oblicza rozmiar czcionki na podstawie długości ciągu wewnątrz <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';
}

Dostosuj i dostrój wszystkie parametry za pomocą testu empirycznego.

Pozwól mi o tym zadzwonić
źródło
Testowanie empiryczne parametrów jest zasadniczo wyszukiwaniem binarnym o złożoności czasowej: O (log n).
Let Me Tink About It
W rzeczywistości zapomniałeś wywołać tę funkcję, a do jej długości należy uzyskać dostęp za pomocą jej właściwości.
lukk
@lukk: Dzięki za opinie. Naprawiono to teraz.
Let Me Tink About It