- Оригинальный адрес:Font-size: An Unexpectedly Complex CSS Property
- Оригинальный автор:Manish Goregaokar
- Перевод с:Программа перевода самородков
- Постоянная ссылка на эту статью:GitHub.com/rare earth/gold-no…
- Переводчик:zephyrJS
- Корректор:bambooom,Colafornia
font-size
плохое свойство CSS
Вероятно, это свойство известно каждому, кто когда-либо писал CSS. Это везде.
но это такжеоченьсложности.
«Это просто число, — скажете вы, — насколько оно может быть сложным?»
Я тоже так думал, пока не начал над этим работатьstylo.
Стило — этоServoсистема стилей интегрирована в проект Firefox. Эта система стилей отвечает за синтаксический анализ CSS, определение того, какие правила применяются к каким элементам, выполнение этих правил через каскад и, наконец, вычисление и назначение стилей различным элементам в дереве. Это происходит не только при загрузке страницы, но и при срабатывании различных событий (включая манипуляции с DOM) и составляет значительную часть загрузки страницы и времени взаимодействия.
Использование сервоприводаRust, и использует параллельные функции безопасности Rust во многих местах, стили являются одним из них. У Stylo есть потенциал привнести эти методы ускорения в Firefox, а также безопасность кода, обеспечиваемую более безопасным системным языком.
В любом случае, что касается системы стилей, я думаю, что размер шрифта — самое сложное свойство, с которым приходится иметь дело. Некоторые свойства могут быть более сложными, когда речь идет о макете или рендеринге, но размер шрифта, вероятно, является самым сложным свойством в стилях.
Я надеюсь, что эта статья может дать представление о веб-встречекак сложно это становитсяидеи, а также служить документацией для некоторых сложных вопросов. В этом посте я также попытаюсь объяснить, как работает система стилей.
OK. Давайте посмотрим, насколько сложен размер шрифта.
Основание
Синтаксис этого свойства очень прост. Вы можете указать его как:
- значение длины (
12px
,15pt
,13em
,4in
,8rem
) - процентное значение (
50%
) - Смешивая вышеизложенное, используйте calc для вычисления (
calc(12px + 4em + 20%)
) - абсолютные ключевые слова (
medium
,small
,large
,x-large
, так далее) - Относительные ключевые слова (
larger
,smaller
)
Первые три использования распространены с длинными свойствами CSS. Нет исключения для синтаксиса.
Следующие два интересны. По сути, абсолютные ключевые слова отображаются на различные значения пикселей и совпадают<font size=foo>
Результат (например,size=3
эквивалентноfont-size: medium
). они сопоставляются среальная стоимостьЭто не так просто, я расскажу об этом в следующей статье.
Относительные ключевые слова в основном масштабируются вверх или вниз. Механика масштабирования также сложна, но она изменилась. Я также расскажу об этом далее.
эм и бэр единицы
первый:em
Блок. Может быть указано как значение в em или rem в любом свойстве CSS, основанном на длине.
5em
Означает «5-кратный размер шрифта, примененный к элементу».5rem
означает "в 5 раз больше размера шрифта корневого элемента"
Это означает, что размер шрифта нужно вычислить перед всеми остальными свойствами (ну, не совсем так, но об этом мы еще поговорим!), чтобы его можно было использовать в это время.
вы также можетеfont-size
используется вem
Блок. В данном случае он относится котецРазмер шрифта элемента вычисляется не на основе его собственного размера шрифта.
минимальный размер шрифта
Браузеры позволяют вам установить «минимальный» размер шрифта в своих настройках, текст никогда не будет меньше этого размера шрифта. Это полезно для людей, которым трудно читать мелкий шрифт.
Однако это не влияет на свойство font-size в единицах em. Поэтому, если вы используете минимальный размер шрифта,<div style="font-size: 1px; height: 1em; background-color: red">
Будет небольшая высота (это видно по цвету), но размер текста будет ограничен минимальным размером.
На практике это означает, что вам нужно отслеживатьдваОтдельно вычисляемое значение размера шрифта. Одно из значений используется для определения размера шрифта реального текста (например, для вычисленияem
Блок. ), а другое значение используется, когда системе стилей необходимо знать размер шрифта.
но включаетruby(отметка сбоку), это становится более сложным. В идеограммах (обычно относящихся к кандзи и основанным на кандзи кандзи и хангыль) иногда бывает полезно выразить произношение каждого символа пиньинь, чтобы помочь читателям, незнакомым с кандзи, который называется «рубиновым» (это называется «» на японскомвибрирующее имя"). Поскольку эти слова являются идеографическими, учащийся нередко знает произношение слова, но не знает, как его написать. Например, желая показатьденьКнига, вам нужно добавить хирагана に ほ ん с рубином на японском языке (произносится как «нихон» на японском языке).
Как видите, шрифт рубинового текста для пиньиньской части меньше (обычно 50% размера шрифта основного текста1). минимальный размер шрифтаподчинятьсяэто и убедитесь, что приложение ruby50%
размер шрифта, минимальный размер шрифта ruby - это исходный минимальный размер шрифта50%
. Это позволяет избежатьденьКнига(когда верхнее и нижнее поля имеют одинаковый размер), это будет выглядеть некрасиво.
текст становится больше
Firefox позволяет масштабировать текст только при увеличении. Если у вас возникли проблемы с чтением мелкого шрифта, приятно иметь возможность увеличивать текст на странице без необходимости увеличивать всю страницу (это означает, что вам нужно много прокручивать).
В этом примере другие настройкиem
Свойства агрегата такжехочуувеличенный. В конце концов, они должны быть относительно размера шрифта текста (и, вероятно, иметь какое-то отношение к тексту), поэтому, если этот размер изменился, они должны измениться вместе с ним.
(Конечно, этот аргумент относится и к минимальному размеру шрифта. Но я не знаю, почему не применяется минимальный размер шрифта.)
На самом деле это легко сделать. При расчете абсолютных размеров шрифта (включая ключевые слова) они соответственно масштабируются, если включено масштабирование текста. Другие работают как обычно.
<svg:text>
Элементы отключают масштабирование текста, что также вызывает некоторые довольно сложные проблемы.
Интерлюдия: как работает система стилей
Прежде чем двигаться дальше, стоит дать обзор того, как работает система стилей.
Система стилей отвечает за то, чтобы взять код CSS и дерево DOM и назначить вычисляемые стили каждому элементу.
Здесь «указанный» и «вычисленный» — не одно и то же. «указанные» стили — это стили, указанные в CSS, а вычисляемые стили — это те, которые присоединены к элементу, отправлены в макет и унаследованы от элемента. Указанные стили могут вычислять разные значения при применении к разным элементам.
так что когда тыуточнитьохватыватьwidth: 5em
, можно вычислитьwidth: 80px
. Вычисленное значение обычно является результатом очистки указанного значения.
Система стилей сначала анализирует CSS, обычно создавая набор правил, содержащих объявления (объявления, такие какwidth: 20%;
; то есть имя атрибута и указанное значение)
Затем он просматривает дерево в порядке сверху вниз (в Stylo это происходит параллельно), определяя, какие объявления применяются к каждому элементу и в каком порядке они выполняются — одни объявления имеют приоритет над другими. Затем он вычисляет каждое соответствующее объявление на основе стиля элемента (родительский стиль и другая информация) и сохраняет это значение в «вычисляемом стиле» элемента.
Чтобы избежать дублирования работы, Gecko и Servo сделали здесь много оптимизаций.2. Существует фильтр Блума для быстрой проверки того, применяется ли к поддереву глубокий селектор потомков. Существует «дерево правил», используемое для кэширования идентифицированных объявлений. На вычисляемые стили часто ссылаются, подсчитывают и совместно используют (поскольку состояние по умолчанию наследуется от родительских стилей или стилей по умолчанию).
В общем, так работает система стилей.
ключевое значение
Ну, тут все усложняется.
помни, что я сказалfont-size: medium
Будет ли это отображаться на какое-то значение?
Итак, на что он сопоставляется?
Ну, оказывается, это зависит от шрифта. Для следующего HTML:
<span style="font: medium monospace">text</span>
<span style="font: medium sans-serif">text</span>
можно получить(codepen), чтобы увидеть результаты.
Первый из них вычисляет размер шрифта 13 пикселей, а второй имеет размер шрифта 16 пикселей. Вы можете получить ответ из окна Compute Styles в devtools или использоватьgetComputedStyle()
также.
ядуматьПричина этого заключается в том, что моноширинные шрифты, как правило, шире, в то время как размер шрифта по умолчанию (средний) уменьшен, чтобы они выглядели одинаковой ширины, а также изменяются размеры шрифтов всех других ключевых слов. Окончательный результат становится таким:
Firefox и Servo имеют одинматрицаЗначение ключевого слова, используемого для вычисления всех абсолютных размеров шрифта на основе «базового размера» (то есть вычисленного значения font-size: medium ). На самом деле, Firefox имееттри столаЧтобы поддержать некоторые устаревшие случаи, такие как странный режим (сервопривод не добавил поддержку этих трех таблиц). Мы основаны на языке и шрифтах при запросе «базового размера» в других частях браузера.
Подождите, какое это имеет отношение к языку? Как язык влияет на размер шрифта?
На самом деле базовый размер зависит от семейства шрифтов.а такжеязык, вы можете настроить его.
И Firefox, и Chrome (используя расширение) фактически позволяют вам установить, какие шрифты используются для каждого языка,и размер шрифта по умолчанию (базовый).
Это не так неясно, как можно подумать. Для нелатинских шрифтов шрифт по умолчанию часто уродлив. Я установил отдельный шрифт, который может отображать красивые лигатуры деванагари.
Точно так же некоторые сценарии намного сложнее латиницы. Шрифт по умолчанию, который я установил для Devanagari, — 18 вместо 16. Я начал изучать китайский язык и установил размер шрифта 18. Глифы кандзи могут быть довольно сложными, и мне до сих пор трудно их выучить (и распознать). Более крупные шрифты более полезны для их изучения.
В целом, это не слишком усложняет ситуацию. Это означает, что семейство шрифтов необходимо вычислять перед размером шрифта, который необходимо вычислять перед большинством других свойств. Языки доступны через HTMLlang
свойство для установки, так как оно является наследуемым, Firefox внутренне рассматривает его как свойство CSS и должен быть оценен как можно раньше.
Пока что не так уж плохо.
Теперь произошло нечто неожиданное. Это отношение к языку и семьеполагатьсяможноунаследовал.
Смотреть,div
Какой размер шрифта внутри?
<div style="font-size: medium; font-family: sans-serif;"> <!-- base size 16 -->
font size is 16px
<div style="font-family: monospace"> <!-- base size 13 -->
font size is ??
</div>
</div>
Для наследуемых свойств CSS3, если вычисленное значение родителя равно16px
, и у дочернего элемента не указано другое значение, то дочерний элемент унаследует это16px
ценность . Дочерним элементам не нужно заботиться о том, чтобы родительский элементоткудаполучить это расчетное значение.
Сейчас,font-size
"унаследовал" а13px
ценность . Вы можете получить это отсюда (codepen), чтобы увидеть результат:
По сути, если вычисленное значение исходит из ключевого слова, размер шрифта будет пересчитан с семейством шрифтов и языком в ключевом слове независимо от семейства шрифтов или изменений языка.
Причина этого в том, что если вы этого не сделаете, разные размеры шрифта не будут работать. Размер шрифта по умолчаниюmedium
, поэтому корневой элемент в основном получаетfont-size: medium
И другие элементы наследуют это объявление. Если вы измените его на моноширинный шрифт или используете в документе другой язык, вам потребуется пересчитать размер шрифта.
Не только это. это даже проходитОтносительная единицаНаследование (кроме IE).
<div style="font-size: medium; font-family: sans-serif;"> <!-- base size 16 -->
font size is 16px
<div style="font-size: 0.9em"> <!-- could also be font-size: 50%-->
font size is 14.4px (16 * 0.9)
<div style="font-family: monospace"> <!-- base size 13 -->
font size is 11.7px! (13 * 0.9)
</div>
</div>
</div>
(codepen)
<div style="border: 1px solid black; display: inline-block; padding: 15px;">
<div style="font-size: medium; font-family: sans-serif;">font size is 16px
<div style="font-size: 0.9em">font size is 14.4px (16 * 0.9)
<div style="font-family: monospace">font size is 11.7px! (13 * 0.9)</div>
</div>
</div>
</div>
Поэтому, когда мы наследуем от второго div, на самом деле наследуется0.9*medium
, вместо14.4px
.
Другой способ взглянуть на это состоит в том, что всякий раз, когда меняется семейство шрифтов или язык, вы должны пересчитывать размер шрифта, как если бы язык и семейство не менялись.
Firefox использует обе стратегии. Первоначальная система стилей Gecko справилась с этим, фактически вернувшись к вершине дерева и пересчитав размер шрифта, как если бы язык и семейство были разными. Я подозреваю, что это неэффективно, но дерево правил, кажется, делает его немного более эффективным.
С другой стороны, во время вычислений Servo сохраняет некоторые дополнительные данные, которые копируются в дочерние элементы. По сути, то, что сохраняется, эквивалентно: «Да, этот шрифт вычисляется по ключевому слову. Ключевое словоmedium
, а затем мы применили к нему коэффициент 0,9. "4
В обоих случаях это приводит ко всемразноеСложность размера шрифта усугубляется тем, что таким образом их необходимо тщательно охранять.
В серво,наиболееситуация черезпользовательская каскадная функция размера шрифтаиметь дело с.
Larger/smaller
я упоминал ранееfont-size: larger
/smaller
масштабируется, но соответствующее значение масштаба еще не указано.
согласно сТехнические характеристики, если текущий размер шрифта соответствует значению абсолютного размера ключевого слова (средний, крупный и т. д.), следует выбрать предыдущее или следующее значение размера ключевого слова.
Если оно находится между двумя абсолютными значениями ключевого словамежду, затем найдите точку того же масштаба между первыми двумя или двумя последними измерениями.
Конечно, это должно хорошо справляться со странным наследованием размеров шрифта ключевых слов, упомянутым ранее. В модели геккона это не так сложно, потому что геккон все равно пересчитывает. В модулях Servo мы храним рядlarger
/smaller
вместо того, чтобы просто хранить относительную единицу.
Кроме того, при вычислении этого значения во время масштабирования текста масштабирование должно быть немасштабировано, затем найдено в таблице, а затем повторно масштабировано.
В общем, куча сложностей мало окупилась — получается, что только Gecko действительно следовал спецификации! Другие браузерные движки просто используют простое масштабирование.
так что мое решениеэто удалить это поведение из Gecko. Этот процесс упрощен.
MathML
MathML поддерживается в Firefox и Safari. В наши дни он мало используется в Интернете, но он существует.
MathML также имеет свои сложности, когда дело доходит до размеров шрифта. особенноscriptminsize
,scriptlevel
а такжеscriptsizemultiplier
.
Например, в MathML числитель, знаменатель или литеральный надстрочный индекс в 0,71 раза больше размера шрифта внешнего текста. Это связано с тем, что элементы MathML по умолчаниюscriptsizemultiplier
равно 0,71, а уровень сценария для этих конкретных элементов по умолчанию равен+1
.
в принципе,scriptlevel=+1
означает "размер шрифта, умноженный наscriptsizemultiplier
",а такжеscriptlevel=-1
используется для устранения этого эффекта. Это можно сделать с помощьюmstyle
установить на элементscriptlevel
спецификация атрибута. Вы также можете пройтиscriptsizemultiplier
чтобы настроить (унаследованный) множитель наscriptminsize
для настройки минимального значения.
Например:
<math><msup>
<mi>text</mi>
<mn>small superscript</mn>
</msup></math><br>
<math>
text
<mstyle scriptlevel=+1>
small
<mstyle scriptlevel=+1>
smaller
<mstyle scriptlevel=-1>
small again
</mstyle>
</mstyle>
</mstyle>
</math>
Выглядит это так (нужно использовать Firefox, чтобы увидеть отрендеренную версию, Safari тоже поддерживает MathML, но не очень хорошо):
(codepen)
Так что это не так уж и плохо. какscriptlevel
странныйem
Блок. Ничего страшного, мы уже знаем, как с ними бороться.
а такжеscriptminsize
. Это позволяет вамдляscriptlevel
изменения, вызванныеУстановите минимальный размер шрифта.
это означает,scriptminsize
обеспечитscriptlevel
не приведет к появлению шрифта меньше минимального размера, но будет игнорировать намеренно указанныйem
Единицы и значения пикселей.
Здесь было введено немного тонкой сложности, и теперьscriptlevel
пострадалfont-size
Как наследование является еще одним фактором. К счастью, внутри Firefox/Servo,scriptlevel
(так же какscriptminsize
а такжеscriptsizemultiplier
) также обрабатывается как свойство CSS, что означает, что мы можем обрабатывать его, используя ту же структуру, что и семейство шрифтов и язык — свойства скрипта вычисляются до того, как установлен размер шрифта, если он установленscriptlevel
, размер шрифта принудительно пересчитывается, даже если сам размер шрифта не задан.
Интерлюдия: свойства ранней и поздней обработки
В Servo способ обработки зависимостей свойств состоит в том, чтобы иметь набор «ранних» свойств и набор «поздних» свойств (разрешая зависимости от более ранних свойств). Мы делаем два поиска для объявления, один раз для ранних свойств и один раз для поздних свойств. Однако теперь у нас есть довольно сложный набор зависимостей, где размер шрифта должен рассчитываться после свойств языка, семейства шрифтов и скрипта, но до всего остального, связанного с длиной. Кроме того, из-за другой сложности шрифта, о которой я не говорил, семейство шрифтов должно вычисляться после всех других ранних свойств.
Способ, которым мы подходим к этой проблеме, находится в ранних вычисленияхИзвлечь размер шрифта и семейство шрифтов,доОбрабатывать его после завершения раннего расчета.
На этом этапе мы сначалаОбработка отключения масштабирования текста, а затем обработатьСложность семейства шрифтов.
потомРассчитать семейство шрифтов. Если указан размер шрифта, тоРасчет. Если не указано, но указано семейство шрифтов, язык или уровень сценария, тоПринудительное вычисление как наследование, чтобы справиться со всеми ограничениями.
Почему scriptminsize становится таким сложным
В отличие от других «минимальных размеров шрифта», когда размер шрифта ограничен параметром scriptminsize, используйте в любом свойствеem
Единицы будут использовать фиксированное значение для расчета длины, а не значение «если не зажато», если размер шрифта ограничен параметром scriptminsize. Таким образом, на первый взгляд обработка этого кажется простой; когда требуется масштабирование из-за уровня сценария, учитывается только минимальный размер шрифта scriptminsize.
Как обычно все не так просто 😀:
<math>
<mstyle scriptminsize="10px" scriptsizemultiplier="0.75" style="font-size:20px">
20px
<mstyle scriptlevel="+1">
15px
<mstyle scriptlevel="+1">
11.25px
<mstyle scriptlevel="+1">
would be 8.4375, but is clamped at 10px
<mstyle scriptlevel="+1">
would be 6.328125, but is clamped at 10px
<mstyle scriptlevel="-1">
This is not 10px/0.75=13.3, rather it is still clamped at 10px
<mstyle scriptlevel="-1">
This is not 10px/0.75=13.3, rather it is still clamped at 10px
<mstyle scriptlevel="-1">
This is 11.25px again
<mstyle scriptlevel="-1">
This is 15px again
</mstyle>
</mstyle>
</mstyle>
</mstyle>
</mstyle>
</mstyle>
</mstyle>
</mstyle>
</mstyle>
</math>
(codepen)
В принципе, если вы продолжаете увеличивать уровень несколько раз после достижения минимального размера шрифта, а затем вычитаете один уровень, немедленного вычисления не происходит.min size / multiplier
значения. Это делает его асимметричным, если коэффициент мультипликатора не меняется, чистый уровень равен+5
должны быть связаны с чистым уровнем+6 -1
элементы имеют одинаковый размер шрифта.
Итак, что происходит, так это то, что уровень скрипта рассчитывается на основе размера шрифтакак будто scriptminsize никогда не применялся, и мы используем этот размер только в том случае, если размер скрипта больше минимального размера.
Это не только отслеживание уровня скрипта, но и изменение множителя. Таким образом, это в конечном итоге создастдругое значение размера шрифта для наследования.
В общем, теперь у нас естьЧетыреСуществуют разные концепции унаследованного размера шрифта:
- Основной размер шрифта, используемый стилем
- «Фактический» размер шрифта, т. е. основной размер шрифта, но ограниченный минимальным
- (только в сервоприводах) размер «ключевого слова», т. е. размер, сохраненный как ключ и отношение (если оно получено из ключа)
- «Церцифический» размер; как в мире сценарий никогда не существовал.
Еще одна сложность заключается в том, что после этого случая все еще должна работать правильно:
<math>
<mstyle scriptminsize="10px" scriptsizemultiplier="0.75" style="font-size: 5px">
5px
<mstyle scriptlevel="-1">
6.666px
</mstyle>
</mstyle>
</math>
(codepen)
Если он уже меньше, чем scriptminsize, уменьшение уровня скрипта (для увеличения размера шрифта) не следует ограничивать, так как позже это сделает его слишком большим.
В основном это означает, что scriptminsize следует использовать только тогда, когда уровень сценария соответствует значению, превышающему минимальный размер шрифта сценария.
В Servo вся обработка MathMLЭта замечательная функция, в которой больше комментариев, чем кодаи некоторый код функций рядом с ним работает отлично.
Вот что вам нужно знать.font-size
Это на самом деле довольно сложно. Многие онлайн-платформы скрывают такие сложности, но с ними очень интересно столкнуться.
(Вероятно, менее весело, когда мне приходится их реализовывать. 😂)
Спасибо mystor, mgattozzi, bstrie и projektir за рецензирование черновиков этого поста.
- Интересно, что в Firefox это значение составляет 50% для всех ruby, когда язык тайваньско-китайский.Кроме(30% в данном случае). Это связано с тем, что на Тайване используется фонетическая письменность бопомофо, и каждый китайский иероглиф может быть представлен тремя иероглифами бопомофо. Таким образом, можно выбрать разумный минимальный размер, чтобы рубин никогда не превышал текст ниже. С другой стороны, в пиньине может быть до 6 букв, а в японской хирагане может быть до (я думаю) 5, и соответствующее «без переполнения» сделает текст слишком маленьким. Так что не проблема поставить их на слово, вместо этого мы предпочитаем использовать более крупный размер шрифта для лучшей читабельности. Кроме того, рубин Bopomofo обычно размещается рядом с текстом, а не сверху, поэтому 30% работает лучше. (h/t @upsuper указал на это)↩
- Другие браузерные движки имеют другие оптимизации, но я о них пока не знаю.↩
- Некоторые свойства наследуются, а некоторые «сбрасываются». Например,
font-family
Унаследовано - если не указано иное. ноtransform
Нет, если вы примените преобразование к элементу, но его дочерние элементы не наследуют это свойство.↩ - это не может быть обработано
calc
s, это то, что мне нужно решить. В дополнение к отношению также сохраняется абсолютное смещение.↩
Программа перевода самородковэто сообщество, которое переводит высококачественные технические статьи из Интернета сНаггетсДелитесь статьями на английском языке на . Охват контентаAndroid,iOS,внешний интерфейс,задняя часть,блокчейн,товар,дизайн,искусственный интеллектЕсли вы хотите видеть более качественные переводы, пожалуйста, продолжайте обращать вниманиеПрограмма перевода самородков,официальный Вейбо,Знай колонку.