Размер шрифта REM не регулируется ниже произвольного порога

В Safari 12.0.2 и Chrome 71.0.3578.98 на Mac Mojave 10.14.2 при установке font-size с использованием rem единиц фактический размер не будет меньше 9px.

См. этот пример:

https://codepen.io/stephenjwatkins/pen/OrbGxL

Отображаемый размер шрифта

Размер шрифта моего браузера установлен по умолчанию (16px) с минимальным размером шрифта, установленным на 6px:

Настройки шрифта браузера

Установка text-size-adjust на none не влияет на проблему. Firefox правильно отображает размер.

Единственное, что я нашел для решения проблемы, это установить font-size: 0; в родительский элемент. Например, если вы добавите font-size: 0; к .container, будет отображаться правильный размер шрифта.

Кто-нибудь знает, почему он не соблюдает размер rem ниже определенного порога?


person Stephen Watkins    schedule 19.12.2018    source источник
comment
Когда вы добавляете префикс поставщика -webkit-text-size-adjust: none, все еще нет любви?   -  person Chris W.    schedule 19.12.2018
comment
Все еще нет любви к поставщику с префиксом -webkit-text-size-adjust: none;.   -  person Stephen Watkins    schedule 19.12.2018
comment
это известная функция, я постараюсь найти повторяющийся вопрос   -  person Temani Afif    schedule 19.12.2018
comment
Хорошо @Темани Афиф. Дай мне знать.   -  person Stephen Watkins    schedule 20.12.2018
comment
не могу найти :/ попробую позже   -  person Temani Afif    schedule 20.12.2018
comment
Я считаю, что это дубликат stackoverflow.com /questions/21302069/ но я не могу закрыть голосование из-за награды.   -  person zzzzBov    schedule 02.01.2019
comment
Еще один похожий вопрос: stackoverflow.com/questions/41578321/   -  person skyline3000    schedule 02.01.2019
comment
Помимо интереса к причудам браузера, есть ли причина, по которой вы хотите, чтобы текст был меньше 9 пикселей? Я полагаю, что ограничение существует как функция, предотвращающая неразборчивость текста, потому что все, что меньше, не читается на практике. Если вам это нужно по какой-то причине, кажется, что использование javascript для установки значений px - ваш единственный выход.   -  person jmcgriz    schedule 02.01.2019
comment
Используйте некоторые хаки, такие как @media all и (-webkit-min-device-pixel-ratio:0) и (min-resolution: .001dpcm) { .text {font-size: 6px;} } см. больше на browserhacks.com   -  person iazaran    schedule 02.01.2019
comment
Это не дубликат stackoverflow.com/ вопросы/21302069/. Минимальный размер шрифта в браузере установлен на 6px, но он не соответствует rem единицам. Например, я могу установить размер шрифта 6px, если я явно использую px, но не меньше 6px, как и ожидалось. Это другая проблема.   -  person Stephen Watkins    schedule 03.01.2019


Ответы (1)


Chrome и его механизм рендеринга Blink, похоже, имеют некоторые неочевидные правила масштабирования шрифтов. Мне неизвестна какая-либо официальная всеобъемлющая документация, поэтому давайте перейдем к источнику.

(Обратите внимание, что я не являюсь экспертом по внутреннему устройству Chromium в целом или рендереру Blink в частности. Я просто просматривал исходный код и размышлял о наиболее вероятных ответах на поставленные вопросы.)

Мне кажется, что движок обращается к класс FontBuilder во время перерисовки. Этот класс имеет различные методы отправки, которые передают DOM, масштабирование и другие важные факторы в метод, который кажется решающим: /WebKit/Source/core/css/FontSize.cpp" rel="noreferrer">FontSize :: getComputedSizeFromSpecifiedSize. В этом методе мы видим несколько пикантных комментариев, касающихся поднятых вами вопросов:

<сильный>1. Почему установка font-size: 0; для родительского элемента исправляет ситуацию?

  // Text with a 0px font size should not be visible and therefore needs to be
  // exempt from minimum font size rules. Acid3 relies on this for pixel-perfect
  // rendering. This is also compatible with other browsers that have minimum
  // font size settings (e.g. Firefox).

<сильный>2. Почему не учитывается размер rem ниже определенного порога?

  // We support two types of minimum font size. The first is a hard override
  // that applies to all fonts. This is "minSize." The second type of minimum
  // font size is a "smart minimum" that is applied only when the Web page can't
  // know what size it really asked for, e.g., when it uses logical sizes like
  // "small" or expresses the font-size as a percentage of the user's default
  // font setting.

  // With the smart minimum, we never want to get smaller than the minimum font
  // size to keep fonts readable. However we always allow the page to set an
  // explicit pixel size that is smaller, since sites will mis-render otherwise
  // (e.g., http://www.gamespot.com with a 9px minimum).

<сильный>3. Для любопытных, каковы эти минимальные значения в относительных единицах (например, x-small)?

// Strict mode table matches MacIE and Mozilla's settings exactly.
static const int strictFontSizeTable[fontSizeTableMax - fontSizeTableMin +
                                     1][totalKeywords] = {
    {9, 9, 9, 9, 11, 14, 18, 27},    {9, 9, 9, 10, 12, 15, 20, 30},
    {9, 9, 10, 11, 13, 17, 22, 33},  {9, 9, 10, 12, 14, 18, 24, 36},
    {9, 10, 12, 13, 16, 20, 26, 39},  // fixed font default (13)
    {9, 10, 12, 14, 17, 21, 28, 42}, {9, 10, 13, 15, 18, 23, 30, 45},
    {9, 10, 13, 16, 18, 24, 32, 48}  // proportional font default (16)
};
// HTML       1      2      3      4      5      6      7
// CSS  xxs   xs     s      m      l     xl     xxl
//                          |
//                      user pref

Интересно и немного в стороне, что класс FontBuilder отправляет в TextAutosizer::computeAutosizedFontSize для масштабирования размера шрифта. Этот метод использует жестко закодированные значения и переменный коэффициент масштабирования:

  // Somewhat arbitrary "pleasant" font size.
  const float pleasantSize = 16;
  // Multiply fonts that the page author has specified to be larger than
  // pleasantSize by less and less, until huge fonts are not increased at all.
  // For specifiedSize between 0 and pleasantSize we directly apply the
  // multiplier; hence for specifiedSize == pleasantSize, computedSize will be
  // multiplier * pleasantSize. For greater specifiedSizes we want to
  // gradually fade out the multiplier, so for every 1px increase in
  // specifiedSize beyond pleasantSize we will only increase computedSize
  // by gradientAfterPleasantSize px until we meet the
  // computedSize = specifiedSize line, after which we stay on that line (so
  // then every 1px increase in specifiedSize increases computedSize by 1px).
  const float gradientAfterPleasantSize = 0.5;

Из этих фактов мы видим, что существует большое количество жестко закодированных значений пикселей, причем 9 и 16 обычно разбросаны по соответствующему коду. Эти жесткие коды, наличие нескольких правил для уменьшения шрифта до предела с возможностью переопределения с использованием размера шрифта — все это, похоже, соответствует наблюдениям и предполагает, что он ведет себя так, как задумано, хотя и не обязательно интуитивно.


Кроме того, я обнаружил, что самый последний комментарий, опубликованный в ошибке Chrome #319623 очень похоже на ваш отчет.

Возможно, связано: при использовании относительных единиц в теге html значения на основе rem, определенные в другом месте, будут иметь нижнюю границу 9 пикселей.

См. CodePen: http://codepen.io/larrybotha/pen/wKYYXE.

Обходной путь: абсолютная единица в html, единица em в теле. рем везде.

Возможно, будет разумно наблюдать за этой ошибкой для дальнейшего развития, хотя, возможно, и не затаив дыхание. Последнее обновление было в 2015 году.

person bishop    schedule 02.01.2019
comment
Хорошее исследование и запись. Хотя я не могу сказать, что полностью понял логику Blink, основываясь на проблеме и коде, которым вы здесь поделились, я согласен с вашим выводом. - person Stephen Watkins; 04.01.2019
comment
Рад, что помог, @StephenWatkins. Я надеюсь, что этот анализ, по крайней мере, находится на приблизительном уровне, но я бы хотел, чтобы мне позвонил эксперт по Chrome: мне все это кажется немного хакерским. - person bishop; 04.01.2019
comment
Обходной путь работает только для размеров шрифта в тексте. К сожалению, нет, если вы используете rem для контейнеров, таких как div для ширины/высоты... - person Robin Wieruch; 27.05.2019
comment
Ранее в этом году в Chrome 73 возникли проблемы, связанные с минимальным размером шрифта и единицами rem. В результате Chrome теперь допускает минимальный размер шрифта, равный нулю, и они также изменили пользовательский интерфейс настроек. Но если вы установите для минимального размера шрифта значение, отличное от нуля, ваши рем-единицы могут стать огромными. Пользовательский интерфейс прыгает с нуля до 6 пикселей как доступные минимальные размеры, ничего между ними. Я тоже хотел бы, чтобы эксперт Chrome объяснил это более подробно. - person jamess; 07.09.2019