Чистый CSS, чтобы сделать размер шрифта отзывчивым на основе динамического количества символов


298

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

Мне нужен способ динамического изменения размера текста, чтобы он всегда помещался в фиксированный элемент div. Вот пример разметки:

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

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


1
Вау, подожди. Задание widthin- emов происходит наоборот. Это то, widthчто зависит от font-size. @JosephSilber Это именно то, что я думал.
Ана

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

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

4
На всякий случай, если кто-нибудь наткнется на этот вопрос и не возражает против использования JS, вот плагин для этого fittextjs.com
DMTintner

2
FitText имеет ограничения. Например, я хочу использовать его только для небольших экранов, шириной более 500 пикселей или около того, я не хочу, чтобы мои заголовки больше взрывались. Это требует написания большего количества JavaScript. Разделение интересов очень быстро нарушается, когда вы используете JavaScript для разметки. Это никогда не просто быстрый лайнер.
Коста

Ответы:


514

Я только что узнал, что это возможно при использовании блоков VW. Это единицы измерения, связанные с настройкой ширины области просмотра. Есть некоторые недостатки, такие как отсутствие поддержки устаревших браузеров, но это определенно то, что стоит серьезно рассмотреть. Кроме того, вы все еще можете предоставить запасные варианты для старых браузеров, например:

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

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


30
Даст 2 взлёта за это. CSS решения для победы!
Михкель Л.

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

116
Проголосовал, но теперь мне интересно, если это действительно отвечает на оригинальный вопрос. Насколько я понимаю, длина вашего текста является динамической, и вы хотите изменить размер шрифта, чтобы он всегда соответствовал ширине вашего div(200 пикселей). Как это решает эту проблему?
Флоремин

26
Я согласен с настроением @ Floremin. Это масштабирует ВСЕ размеры шрифта на основе ширины / высоты порта просмотра, а не контейнера ширины / высоты текста.
MickJuice

24
@ Флоремин прав, это не решает вопрос. Это вычисляет размер шрифта как функцию ширины контейнера, а не как функцию длины строки, поскольку это относится к ширине контейнера
Генри

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

см. 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. Даже не беспокойтесь 4k, он будет слишком раздувать ваши изображения, а размер 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%";
    }
}

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

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

Итак, в конечном итоге:

  • Краткий текст: например, "ЯБЛОКИ"

    Полностью отрисованные, красивые большие буквы.

  • Полный текст: например, "ЯБЛОКИ И ОРАНЖЕВЫЕ"

    Уменьшается на 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
Пожалуйста, предложите возможные улучшения (я не очень заинтересован в использовании canvas для измерения текста ... кажется как слишком много накладных расходов (?)).

Спасибо @Pete за функцию measureText: 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 может в конечном итоге иметь размер шрифта 60 пикселей, ваш размер шрифта, но при уменьшении ширины окна до 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.