Чистий CSS, щоб зробити розмір шрифту чуйним на основі динамічної кількості символів


298

Я знаю, що це можна вирішити досить легко за допомогою Javascript, але мене цікавить лише чисте CSS рішення.

Я хочу спосіб динамічно змінити розмір тексту, щоб він завжди вписувався у фіксований поділ. Ось зразок розмітки:

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

Я думав, що, можливо, це могло бути можливим, вказавши ширину контейнера в емах та отримавши розмір шрифту для успадкування цього значення?


1
Нічого собі, чекай. Визначення речі widthв ems іде навпаки. Це те, widthщо залежить від font-size. @JosephSilber Саме так я подумав.
Ана

1
Мені цікаво це питання. Який привід використовувати чисте рішення css замість написання простої функції JavaScript?
Остін Маллінз

22
Привід відбувається просто тому, що проблема існує, і чисте рішення CSS було б дивним. Подумайте про можливості застосування лише кількох стилів і знайте, що ваш динамічний контент ніколи не порушить дизайн.
DMTintner

4
На всякий випадок, якщо хтось наткнеться на це запитання і не має сенсу
DMTintner

2
fitText має обмеження. Наприклад, я хочу лише запускати його на невеликих екранах, шириною більше ніж 500 пікселів, і я не хочу, щоб мої заголовки більше підірвались. Для цього потрібно писати більше JavaScript. Розділення проблем порушується дуже швидко, коли ви використовуєте JavaScript для компонування. Це ніколи не лише швидкий один лайнер.
Коста

Відповіді:


513

Я щойно з’ясував, що це можливо за допомогою VW блоків. Вони є одиницями, пов'язаними з налаштуванням ширини вікна перегляду. Є деякі недоліки, такі як відсутність застарілої підтримки браузера, але це, безумовно, щось серйозно варто розглянути. Крім того, ви все ще можете забезпечити резервні копії для старих веб-переглядачів, наприклад:

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

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


30
Дав би 2 ups для цього. CSS-рішення на виграш!
Міхкель Л.

34
Порада: ви можете запобігти занадто малому тексту та отримати деякий контроль, виконуючи font-size:calc(100% + 2vw);чи подібні. Це свого роду min-font-size. Підтримка веб-переглядача calcсхожа на vw.
Принцхорн

116
Оновлено, але зараз мені цікаво, чи це насправді відповідає на початкове запитання. Наскільки я розумію, ваша довжина тексту є динамічною, і ви хочете змінити розмір шрифту так, щоб він завжди відповідав ширині div(200 пікселів). Як це вирішує цю проблему?
Флоремін

26
Я згоден з настроями @ Флореміна. Це масштабує ВСІ розміри шрифту на основі ширини / висоти портів перегляду, а не контейнера ширини / висоти тексту.
MickJuice

24
@Floremin має рацію, це не стосується питання. Це обчислює розмір шрифту як функцію ширини контейнера, а не як функцію довжини рядка, оскільки це стосується ширини контейнера
Хенрі

113

CSS3 підтримує нові параметри, що відносяться до порту перегляду. Але це не працює в Android <4.4

  1. 3,2vw = 3,2% ширини вікна перегляду
  2. 3,2vh = 3,2% висоти огляду
  3. 3.2vmin = Менше 3.2vw або 3.2vh
  4. 3.2vmax = Більше 3,2vw або 3,2vh

    body
    {
        font-size: 3.2vw;
    }

див. css-tricks.com / .... а також дивись caniuse.com / ....

або

Використовуйте медіа-запит. Найпростішим способом є використання розмірів у% або em. Просто змініть базовий розмір шрифту, все зміниться.

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

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


h5{
    font-size: 1.4em;
}

Використовуйте розміри у % або em . Просто змініть базовий розмір шрифту, все зміниться. У попередній ви можете просто змінити шрифт корпусу, а не h1 кожен раз, або дозволити розмір базового шрифту за замовчуванням пристрою та залишити все в

подивитися kyleschaeffer.com / .... для отримання додаткової інформації про em, px та%


12
Питання стосувалося масштабування щодо контейнера, а не до всього огляду.
Арно Вейл

6
... а питання стосувались масштабування на основі кількості символів
Браво


14

Можливо, єдиним способом було б встановити різну ширину для різних розмірів екрана, але такий підхід досить неточний, і вам слід використовувати 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

Я знаю, що я переспитую давнє мертве запитання, але у мене було те саме питання, і я хотів щось додати. Будь ласка, не забороняйте мені цього, я вважав, що це досить важливо, щоб виправдати цю відповідь, якщо я вимагаю, я видалю її. @ Джозеф Сілбер помиляється, кодування всіх можливостей насправді є життєздатним способом зробити це. Причина в тому, що насправді не існує нескінченних можливостей. Ну, технічно є, але 99% відвідувачів будуть використовувати стандартну роздільну здатність. Це вдвічі справедливо для мобільних пристроїв (основна причина гнучкості веб-дизайну), оскільки більшість мобільних ОС запускають програми на весь екран без зміни розміру вікна.

Крім того, висота в значній мірі не має значення через смугу прокрутки (до речі, я б одразу залишив веб-сторінку довжиною більше 4 або 5 футів, але це здебільшого справедливо), тому вам потрібно хвилюватися лише про ширину. І дійсно, єдині ширини, які потрібно кодувати, такі: 240, 320, 480 (для старих iThings), 640, 800, 1024, 1280, 1440, 1600, 1920, 2048, 2560. Навіть не турбуйтеся за 4 кб, він занадто сильно роздує ваші зображення, і розмір 2560, розтягнутий на 100% ширину, виглядає просто чудово на моніторі 4k (я це протестував). Крім того, не турбуйтеся 720 (720x480), як запропонував попередній плакат. Її роздільна здатність використовується майже виключно цифровими камерами, і навіть тоді це дуже рідкість.

Якщо хтось використовує екзотичну роздільну здатність, майже будь-який рендерінг, зроблений за останні 15 років, округлиться, тому, якщо чиясь ширина екрана, скажімо, 1100, це завантажує правило 1024 CSS, ваш сайт не повинен порушуватися. Це робить облік екзотичних дозволів, намагаючись створити чуйне правило непотрібним, і думка про те, що потрібно кодувати всі можливі налаштування пікселів за пікселями, є смішною, якщо хтось не використовує веб-браузер настільки застарілий, що ваш сайт, ймовірно, не завантажиться на все одно.


1
А тепер 375 та 414 для iPhone
6/6

Потенційно ще простіше, якщо використовувати SASS або Compass і вступити у функції. Функція може зробити все, що CSS працює для вас; написати-раз-раз-багато-багато.
cjbarth

висота майже не має значення, поки ви не повернете пристрій на 90º на бік, тобто
Carvo Loco

Це не має нічого спільного з шириною контейнера - з якого є легко безмежні можливості.
mcheah

8

Для довідки, не CSS-рішення:

Нижче наводиться деякий JS, який перевстановлює шрифт залежно від довжини тексту в контейнері.

Codepen з трохи модифікованим кодом, але такою ж ідеєю, як нижче:

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

Для мене я називаю цю функцію, коли користувач робить вибір у спадному меню, а потім розділ у моєму меню заповнюється (саме тут у мене виникає динамічний текст).

    scaleFontSize("my_container_div");

Крім того, я також використовую CSS-еліпсиси ("...") для урізання ще більш тривалого тексту, як-от так:

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

Отже, в кінцевому рахунку:

  • Короткий текст: наприклад, "APPLES"

    Повністю винесені, приємні великі літери.

  • Довгий текст: наприклад, "ЗАЯВКИ І ОРАНГИ"

    Отримує масштаб на 70% завдяки вищевказаній функції масштабування JS.

  • Супер довгий текст: наприклад, "ЗАЯВКИ І ОРАНГИ І БАНАН ..."

    Отримує зменшення на 70% І обрізається еліпсами "..." за допомогою вищезгаданої функції масштабування JS разом із правилом CSS.

Ви також можете вивчити гру з інтервалом у форматі CSS, щоб зробити текст вужчим, зберігаючи однаковий розмір шрифту.


проголосував, коли користувач просив чистого CSS-рішення
AnotherLongUsername

2

Як багато хто згадував у коментарях до публікації @ DMTinter, ОП запитувала про кількість змін ("кількість") символів. Він також запитував про CSS, але як зазначав @Alexander, "це неможливо лише для CSS". Наскільки я можу сказати, наразі це здається правдою, тому також здається логічним, що люди хочуть знати наступне найкраще.

Я не особливо пишаюся цим, але це працює. Здається, це надмірна кількість коду для його виконання. Це суть:

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

Ось JS Bin: http://jsbin.com/pidavon/edit?html,css,js,console,output
Будь ласка, запропонуйте можливі вдосконалення (я не дуже зацікавлений у використанні полотна для вимірювання тексту ... здається як занадто великі накладні витрати (?)).

Дякуємо @Pete за функцію ukreText: https://stackoverflow.com/a/4032497/442665


2

Це рішення також може допомогти:

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

Це добре працювало на мене!


Як це враховує обговорення слів?
Лейф Неланд


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

використовувати це рівняння.

Для нічого більшого або меншого, ніж 1440 і 768, ви можете або надати йому статичне значення, або застосувати той самий підхід.

Недолік рішення vw полягає в тому, що ви не можете встановити коефіцієнт масштабу, скажімо, 5vw при роздільній здатності екрана 1440 може скласти 60px розмір шрифту, розмір вашого шрифту ідеї, але коли ви зменшите ширину вікна до 768, це може закінчитися 12px, не мінімальний, який ви хочете. При такому підході ви можете встановити верхню і нижню межу, і шрифт буде масштабуватись між ними.


-2

Створіть таблицю пошуку, яка обчислює розмір шрифту залежно від довжини рядка всередині вашого <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';
}

Налаштуйте та налаштуйте всі параметри емпіричним тестом.


Емпіричне тестування параметрів - це, по суті, двійковий пошук зі складністю у часі: O (log n).
Дозвольте мені подумати про це

Ви фактично забули викликати цю функцію, а також потрібно отримати доступ до довжини масиву з її властивістю.
Lukk

@lukk: Дякую за відгук. Виправлено це зараз.
Дозвольте мені подумати про це
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.