CSS murni untuk membuat font-size responsif berdasarkan jumlah karakter yang dinamis

298

Saya tahu ini bisa diselesaikan dengan cukup mudah dengan Javascript, tapi saya hanya tertarik dengan solusi CSS murni.

Saya ingin cara untuk mengubah ukuran teks secara dinamis sehingga selalu cocok dengan div tetap. Berikut ini markup sampel:

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

Saya berpikir bahwa mungkin ini bisa dilakukan dengan menentukan lebar wadah di ems, dan mendapatkan ukuran font untuk mewarisi nilai itu?

DMTintner
sumber
1
Wow, tunggu. The menspesifikasikan dari widthdalam emhal s berjalan di sekitar jalan lain. Itu widthyang tergantung pada font-size. @ JosephSilber Itulah yang saya pikirkan.
Ana
1
Saya ingin tahu tentang pertanyaan ini. Apa drive untuk menggunakan solusi css murni alih-alih menulis fungsi javascript sederhana?
Austin Mullins
22
Drive ini semata-mata karena masalahnya ada dan solusi CSS murni akan luar biasa. Pikirkan tentang kemungkinan menerapkan hanya beberapa gaya dan mengetahui bahwa konten dinamis Anda tidak akan pernah merusak desain.
DMTintner
4
Untuk berjaga-jaga jika ada yang menemukan pertanyaan ini dan tidak keberatan menggunakan JS, berikut adalah plugin untuk melakukannya fittextjs.com
DMTintner
2
fitText memiliki batasan. Misalnya saya hanya ingin menjalankannya untuk layar kecil, melebihi lebar 500px atau lebih, saya tidak ingin judul saya meledak lagi. Ini membutuhkan penulisan lebih banyak JavaScript. Pemisahan masalah terurai sangat cepat ketika Anda menggunakan JavaScript untuk tata letak. Tidak pernah hanya satu liner cepat.
Costa

Jawaban:

513

Saya baru tahu bahwa ini mungkin menggunakan unit VW. Mereka adalah unit yang terkait dengan pengaturan lebar viewport. Ada beberapa kelemahan, seperti kurangnya dukungan browser yang lama, tetapi ini jelas sesuatu yang perlu dipertimbangkan untuk digunakan. Plus Anda masih dapat memberikan fallback untuk browser lama seperti:

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

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

DMTintner
sumber
30
Akan memberikan 2 up untuk yang satu ini. Solusi CSS untuk menang!
Mihkel L.
34
Kiat pro: Anda dapat mencegah teks menjadi terlalu kecil dan mendapatkan kontrol kembali dengan melakukan font-size:calc(100% + 2vw);atau serupa. Ini agak min-font-size. Dukungan browser untuk calcmirip dengan vw.
Prinzhorn
116
Terpilih, tetapi sekarang saya bertanya-tanya apakah ini benar-benar menjawab pertanyaan awal. Pemahaman saya adalah bahwa panjang teks Anda dinamis dan Anda ingin mengubah ukuran font agar selalu sesuai dengan lebar div(200px) Anda. Bagaimana ini mengatasi masalah itu?
Floremin
26
Saya setuju dengan sentimen @ Floremin. Ini skala SEMUA ukuran font berdasarkan lebar / tinggi view-port, bukan wadah lebar / tinggi teks.
MickJuice
24
@Floremin benar, ini tidak menjawab pertanyaan. Ini menghitung ukuran font sebagai fungsi dari lebar kontainer, bukan sebagai fungsi dari panjang string yang terkait dengan lebar kontainer
henry
113

CSS3 mendukung dimensi baru yang relatif untuk melihat port. Tapi ini tidak berfungsi di android <4.4

  1. 3.2vw = 3.2% dari lebar viewport
  2. 3.2vh = 3.2% dari ketinggian viewport
  3. 3.2vmin = Lebih kecil dari 3.2vw atau 3.2vh
  4. 3.2vmax = Lebih besar dari 3.2vw atau 3.2vh

    body
    {
        font-size: 3.2vw;
    }

lihat css-tricks.com / .... dan lihat juga caniuse.com / ....

atau

Gunakan kueri media. Cara paling sederhana adalah menggunakan dimensi dalam% atau em. Cukup ubah ukuran font dasar semuanya akan berubah.

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

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


h5{
    font-size: 1.4em;
}

Gunakan dimensi dalam % atau em . Cukup ubah ukuran font dasar semuanya akan berubah. Dalam yang sebelumnya Anda hanya bisa mengubah font tubuh dan tidak h1 setiap kali atau membiarkan ukuran font dasar ke default perangkat dan sisanya semua dalam em

lihat kyleschaeffer.com / .... untuk info lebih lanjut tentang em, px dan%

aWebDeveloper
sumber
12
Pertanyaannya adalah tentang penskalaan relatif ke wadah, bukan ke seluruh viewport.
Arnaud Weil
6
... dan pertanyaannya adalah tentang penskalaan berdasarkan jumlah karakter
Bravo
14

Satu-satunya cara mungkin adalah dengan mengatur lebar yang berbeda untuk ukuran layar yang berbeda, tetapi pendekatan ini cukup menguras dan Anda harus menggunakan solusi 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
sumber
12

Saya tahu saya mengolah pertanyaan yang sudah lama mati, tetapi saya memiliki pertanyaan yang sama dan saya ingin menambahkan sesuatu. Tolong jangan larangan saya untuk ini, saya merasa cukup penting untuk membenarkan jawaban ini, saya akan menghapus jika diperlukan. @ Joseph Silber salah, pengkodean semua kemungkinan sebenarnya adalah cara yang layak untuk melakukan ini. Alasannya adalah karena sebenarnya tidak ada kemungkinan tak terbatas. Ya, secara teknis ada, tetapi 99% pengunjung Anda akan menggunakan resolusi standar. Ini berlaku ganda untuk ponsel (alasan utama desain web responsif) karena sebagian besar OS seluler menjalankan aplikasi layar penuh tanpa mengubah ukuran jendela.

Selain itu, ketinggian cukup banyak tidak relevan karena scrollbar (pada suatu titik, saya akan segera meninggalkan halaman web yang panjangnya lebih dari 4 atau 5 kaki, tetapi ini sebagian besar berlaku), jadi Anda hanya perlu khawatir tentang lebar. Dan sungguh, satu-satunya lebar yang Anda perlu kode adalah sebagai berikut: 240, 320, 480 (untuk iThings yang lebih tua), 640, 800, 1024, 1280, 1440, 1600, 1920, 2048, 2560. Bahkan tidak perlu repot untuk 4k, itu akan menggembungkan gambar Anda terlalu banyak dan ukuran 2560 melebar hingga 100% lebar terlihat baik-baik saja pada monitor 4k (saya sudah menguji ini). Juga, jangan repot-repot dengan 720 (720x480) seperti yang disarankan oleh poster sebelumnya. Sebuah resolusi yang digunakan hampir secara eksklusif oleh kamera digital, dan itupun sangat jarang.

Jika seseorang menggunakan resolusi eksotis, hampir semua penyaji yang dibuat dalam 15 tahun terakhir akan dibulatkan ke bawah, jadi jika lebar layar seseorang adalah, katakanlah. 1100, ini akan memuat aturan CSS 1024, situs Anda tidak boleh rusak. Ini menjadikan akuntansi untuk resolusi eksotis dengan mencoba membuat aturan responsif yang tidak perlu, dan gagasan bahwa Anda perlu kode untuk setiap kemungkinan pengaturan piksel demi piksel adalah konyol, kecuali jika seseorang menggunakan browser web yang sudah usang sehingga situs Anda mungkin tidak akan memuat pada bagaimanapun juga.

pengguna281058
sumber
1
Dan sekarang 375 dan 414 untuk iPhone
6/6
Berpotensi lebih mudah jika menggunakan SASS atau Kompas dan masuk ke fungsi. Suatu fungsi dapat melakukan semua yang berfungsi untuk Anda; tulis-sekali-pakai-banyak.
cjbarth
tinggi hampir tidak relevan sampai Anda menghidupkan perangkat 90º di sisinya, yaitu
Carvo Loco
Ini tidak ada hubungannya dengan lebar wadah - yang ada kemungkinan mudah tak terbatas.
mcheah
8

Untuk referensi, solusi non-CSS:

Di bawah ini adalah beberapa JS yang mengubah ukuran font tergantung pada panjang teks dalam sebuah wadah.

Codepen dengan kode yang sedikit dimodifikasi, tetapi ide yang sama seperti di bawah ini:

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

Bagi saya, saya memanggil fungsi ini ketika pengguna membuat pilihan dalam drop-down, dan kemudian div di menu saya akan diisi (ini adalah di mana saya memiliki teks dinamis terjadi).

    scaleFontSize("my_container_div");

Selain itu, saya juga menggunakan CSS elips ("...") untuk memotong teks yang lebih panjang lagi , seperti:

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

Jadi, pada akhirnya:

  • Teks singkat: mis. "APLIKASI"

    Sepenuhnya diterjemahkan, surat-surat besar yang bagus.

  • Teks panjang: mis. "APPLES & ORANGES"

    Mendapat penurunan 70%, melalui fungsi penskalaan JS di atas.

  • Teks super panjang: mis. "APPLES & ORANGES & BANAN ..."

    Mendapat penurunan 70% DAN akan terpotong dengan elips "...", melalui fungsi penskalaan JS di atas bersama dengan aturan CSS.

Anda juga dapat menjelajahi bermain dengan spasi huruf CSS untuk membuat teks lebih sempit dengan tetap menjaga ukuran font yang sama.

MarsAndBack
sumber
ditolak karena pengguna meminta solusi CSS murni
AnotherLongUsername
2

Seperti banyak disebutkan dalam komentar untuk posting @ DMTinter, OP bertanya tentang jumlah ("jumlah") karakter yang berubah. Dia juga bertanya tentang CSS, tetapi seperti yang ditunjukkan @Alexander, "itu tidak mungkin hanya dengan CSS". Sejauh yang saya tahu, itu tampaknya benar pada saat ini, jadi juga masuk akal jika orang ingin mengetahui hal terbaik berikutnya.

Saya tidak terlalu bangga dengan ini, tetapi itu berhasil. Sepertinya terlalu banyak kode untuk mencapainya. Inilah intinya:

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

Berikut ini adalah JS Bin: http://jsbin.com/pidavon/edit?html,css, js ,console ,output
Sarankan perbaikan yang mungkin untuk itu (Saya tidak benar-benar tertarik menggunakan kanvas untuk mengukur teks ... tampaknya seperti terlalu banyak overhead (?)).

Terima kasih kepada @Pete untuk fungsi mengukurText: https://stackoverflow.com/a/4032497/442665

jbobbins
sumber
2

Solusi ini juga dapat membantu:

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

Itu bekerja dengan baik untuk saya!

Gaurav Krishn
sumber
Bagaimana ini memperhitungkan kata-kata?
Leif Neland
2
calc(42px + (60 - 42) * (100vw - 768px) / (1440 - 768));

gunakan persamaan ini.

Untuk apa pun yang lebih besar atau lebih kecil dari 1440 dan 768, Anda bisa memberikannya nilai statis, atau menerapkan pendekatan yang sama.

Kekurangan dengan solusi vw adalah bahwa Anda tidak dapat mengatur rasio skala, katakanlah 5vw pada resolusi layar 1440 mungkin berakhir menjadi ukuran font 60px, ukuran font ide Anda, tetapi ketika Anda mengecilkan lebar jendela ke 768, itu mungkin berakhir menjadi 12px, bukan minimal yang Anda inginkan. Dengan pendekatan ini, Anda dapat mengatur batas atas dan batas bawah Anda, dan font akan mengatur skala di antaranya.

Shuwei
sumber
-2

Buat tabel pencarian yang menghitung ukuran font berdasarkan panjang string di dalam Anda <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';
}

Sesuaikan dan sesuaikan semua parameter dengan uji empiris.

Biarkan Saya Tink Tentang Ini
sumber
Pengujian empiris untuk parameter pada dasarnya adalah pencarian biner dengan kompleksitas waktu: O (log n).
Let Me Tink About It
Anda sebenarnya lupa memanggil fungsi ini, juga panjang array harus diakses dengan propertinya.
lukk
@ Lukuk: Terima kasih atas umpan baliknya. Perbaiki sekarang.
Let Me Tink About It