- Отзывчивый размер шрифта
- Коротко о viewport-зависимых единицах
- Задача
- Путь к решению
- Используем Sass/SCSS
- Расширяем возможности нашей функции
- Результат
- CSS: полное руководство по функции calc()
- Функция calc() и значения CSS-свойств
- Функция calc() — это средство для работы с числовыми свойствами
- Функцию calc() нельзя применять в медиа-запросах
- Использование разных единиц измерения в одном выражении
- Сравнение calc() с вычислениями, обрабатываемыми препроцессорами
- Раскрытие смысла используемых в CSS числовых значений
- Математические операторы функции calc()
- О важности пробелов
- Вложенные конструкции: calc(calc())
- Пользовательские CSS-свойства и calc()
- Назначение единиц измерения пользовательским свойствам после объявления этих свойств
- Работа с цветами
- Нельзя комбинировать calc() и attr()
- Браузерные инструменты
- Браузерная поддержка
- Примеры из жизни
Отзывчивый размер шрифта
Уверен, что никому не нужно объяснять почему сайты должны быть гибкими и адаптивными. Все используют проценты и медиа-запросы в своей верстке. Сейчас это уже стандарт.
Но типографика до недавнего времени не была столь гибкой. Все что мы могли — изменять размеры шрифта от брейкпоинта к брейкпоинту. В таком случае мы получали скорее адаптивную типографику нежели отзывчивую. Для каждого медиа-запроса нужно задавать свои значения. Можно конечно использовать компонентный подход с относительными размерами шрифта, что может существенно ускорить процесс редактирования, но принципиально это ничего не меняет. При перемещении компонента в другое место нужно будет опять пробегать по всем медиа запросам и подставлять новые значения.
Но потом появились они — vw, vh, vmin, vmax — единицы измерения, которые базируются на viewport. У нас появился шанс на отзывчивую типографику.
Коротко о viewport-зависимых единицах
100vw равно ширине (100vh — высоте) экрана в пикселях (или будет приведено к другим величинам если использовать в calc()). 100vmax — равно большему из пары высота/ширина, 100vmin — меньшему. Сразу же начали появляться рецепты использования этих чудо величин в типографике.
Но в таком виде их сложно контролировать. Иногда попадались рецепты с использованием каких-то магических процентных величин. Но меня не устраивал вариант разбираться откуда они, а потом считать или подбирать вручную их для получения нужных мне размеров в моих условиях.
Задача
Хотелось иметь универсальный рецепт, который позволял бы задавать минимальное и максимальное значения для размера шрифта, да еще и привязать эти цифры к конкретным размерам viewport. Например, при ширине экрана в 480px иметь ровно 16px, а при 1280px — 24px.
Путь к решению
Вспомнив курс школьной математики пришел к выводу что моя задача не что иное, как уравнение прямой проходящей через 2 точки. Первая точка — меньшая ширины экрана и размер шрифта на ней, вторая — бОльшая ширина и соответствующий ей размер шрифта.
На оси X — ширина окна браузера, на оси Y — наш размер шрифта. Получаем уравнение с двумя неизвестными:
y — наш неизвестный размер шрифта, x — текущий размер экрана. x1 — минимальное значение шрифта, x2 — максимальное значение шрифта. y1 и y2 минимальное и максимальные значение ширины экрана соответственно.
А теперь самое интересное: имея CSS функцию calc() и текущее значение вьюпорта благодаря vw можно получить динамический размер шрифта:
Эту формулу уже можно использовать в чистом CSS. Только нужно помнить, что при операциях умножения/деления хотя бы один из аргументов должен быть без единиц измерения, а при сложение/вычитании — оба с единицами. Подставив наши значения получим рабочий вариант (обратите внимание на использование единиц измерения):
Единицы измерений можно использовать любые, главное, чтобы они совпадали. Тоже самое, только в rem:
Используем Sass/SCSS
Имея под рукой такой инструмент как Sass можно большую часть вычислений спрятать от браузера.
Для этого больше подойдет следующее уравнение прямой:
Коеффициенты k и b можно получить из уравнения прямой по двум точкам:
В случае, если мы хотим иметь возможность использовать не только px но и другие единицы измерений, можно передавать их одним из параметров:
Для защиты от неверно введенных данных, можно обрезать единицы измерений при получении данных. Для этого можно использовать функцию strip-unit или взять ее из библиотеки bourbon:
Расширяем возможности нашей функции
Функцию для вычисления размера шрифта мы имеем. Теперь на ее основе можно создать миксин, который можно расширять как угодно.
Например, мы хотим фолбек для старых браузеров:
Теперь можно в качестве фолбека передавать оптимальный размер шрифта на случай, когда vw не поддерживается.
Можно ограничить размеры шрифта нашим минимальным и/или максимальным значением:
Теперь при ширине экрана меньше 480px шрифт всегда будет 16px, после 480 он станет резиновым, а после 1280px всегда будет 24px.
Результат
Мы получили базовую функцию, которая выполняет весь основной функционал:
Для ее расширения использовались миксины, с помощью которых можно сделать фоллбеки, ограничения, конвертацию единиц измерения и многое другое. Поиграться со всем этим можно на codepen. Если Вы не хотите использовать Sass здесь вы найдете способ вычислений на чистом CSS.
Источник
CSS: полное руководство по функции calc()
В CSS есть особая функция calc() , применяемая для выполнения простых вычислений. Вот пример её использования:
Здесь с CSS-кодом, в котором используется calc() , можно поэкспериментировать.
Автор статьи, перевод которой мы сегодня публикуем, хочет рассказать обо всём, что стоит знать об этой весьма полезной функции.
Функция calc() и значения CSS-свойств
Единственное место, где можно использовать функцию calc() — это значения CSS-свойств. Взгляните на следующие примеры, в которых мы, используя эту функцию, задаём значения различных свойств.
Функцию calc() можно применять и для установки любой отдельной части свойства:
Эта функция может даже быть частью другой функции, которая отвечает за формирование части некоего свойства! Например, здесь calc() используется для настройки позиций изменения цвета градиента:
Функция calc() — это средство для работы с числовыми свойствами
Обратите внимание на то, что во всех вышеприведённых примерах мы используем функцию calc() при работе с числовыми свойствами. Мы ещё поговорим о некоторых особенностях работы с числовыми свойствами (они связаны с тем, что иногда не требуется использование единиц измерения). Сейчас же отметим, что данная функция предназначена для выполнения операций с числами, а не со строками или с чем-то ещё.
Существует множество единиц измерения, которые можно применять в CSS для указания размеров элементов и их частей: px , % , em , rem , in , mm , cm , pt , pc , ex , ch , vh , vw , vmin , vmax . Все эти единицы измерения можно использовать с функцией calc() .
Эта функция умеет работать и с числами, применяемыми без указания единиц измерения:
Её можно использовать и для вычисления углов:
Данную функцию можно применять и в тех случаях, когда в передаваемом ей выражении никаких вычислений не выполняется:
Функцию calc() нельзя применять в медиа-запросах
Хотя эта функция предназначена для установки значений CSS-свойств, она, к сожалению, не работает в медиа-запросах:
Если когда-то подобные конструкции окажутся работоспособными — это будет очень хорошо, так как это позволит создавать взаимоисключающие медиа-запросы, выглядящие весьма логично (например — такие, которые показаны выше).
Использование разных единиц измерения в одном выражении
Допустимость использования разных единиц измерения в одном выражении, вероятно, можно назвать самой ценной возможностью calc() . Подобное применяется почти в каждом из вышеприведённых примеров. Вот, просто для того, чтобы обратить на это ваше внимание, ещё один пример, в котором показано использование различных единиц измерения:
Это выражение читается так: «Ширина равна ширине элемента, из которой вычитается 20 пикселей».
В ситуации, когда ширина элемента может меняться, совершенно невозможно заранее вычислить нужное значение, пользуясь только показателями, выраженными в пикселях. Другими словами, нельзя провести препроцессинг calc() , используя что-то вроде Sass и пытаясь получить что-то вроде полифилла. Да делать этого и не нужно, учитывая то, что calc() очень хорошо поддерживают браузеры. Смысл тут в том, что подобные вычисления, в которых смешивают значения, выраженные в разных единицах измерения, должны быть произведены в браузере (во время «выполнения» страницы). А именно в возможности выполнения таких вычислений и заключается основная ценность calc() .
Вот ещё пара примеров использования значений, выраженных в разных единицах измерения:
Эти выражения, вероятно, можно подвергнуть препроцессингу, так как в них смешаны значения, единицы измерения которых не связаны с чем-либо, определяемым во время работы страницы в браузере.
Сравнение calc() с вычислениями, обрабатываемыми препроцессорами
Мы только что сказали о том, что самая полезная возможность calc() не поддаётся препроцессингу. Но препроцессинг даёт разработчику некоторые возможности, совпадающие с возможностями calc() . Например, при использовании Sass тоже можно вычислять значения свойств:
Здесь могут производиться вычисления с указанием единиц измерения, тут можно складывать величины, выраженные в одних и тех же единицах измерения, можно умножать некие величины на значения, единицы измерения которых не указаны. Но выполнять вычисления со значениями, выраженными в разных единицах измерения, здесь нельзя. На подобные вычисления накладываются ограничения, напоминающие ограничения calc() (например, числа, на которые что-то умножают или делят, должны представлять собой значения без единиц измерения).
Раскрытие смысла используемых в CSS числовых значений
Даже если не пользоваться возможностями, которые достижимы лишь с помощью calc() , эту функцию можно применить для раскрытия смысла применяемых в CSS значений. Предположим, нужно, чтобы значение некоего свойства составляло бы в точности 1/7 ширины элемента:
Такой подход может оказаться полезным в чём-то вроде некоего самописного CSS-API:
Математические операторы функции calc()
В выражениях, вычисляемых с помощью calc() , можно использовать операторы + , — , * и / . Но в их применении есть некоторые особенности.
При сложении ( + ) и вычитании ( — ) необходимо использовать значения с указанными единицами измерения
Обратите внимание на то, что использование некорректных значений приводит к тому, что конкретное объявление также становится некорректным.
При делении ( / ) нужно, чтобы у второго числа не была бы указана единица измерения
При умножении ( * ) у одного из чисел не должна быть указана единица измерения:
О важности пробелов
Пробелы, используемые в выражениях, важны в операциях сложения и вычитания:
Тут вполне можно использовать и отрицательные числа (например — в конструкции вроде calc(5vw — -5px) ), но это — пример ситуации, в которой пробелы не только необходимы, но ещё и полезны в плане понятности выражений.
Таб Аткинс сказал мне, что причина, по которой операторы сложения и вычитания должны выделяться пробелами, на самом деле, заключается в особенностях парсинга выражений. Не могу сказать, что я в полной мере это понял, но, например, парсер обрабатывает выражение 2px-3px как число 2 с единицей измерения px-3px . А столь странная единица измерения точно никому не понадобится. При парсинге выражений с оператором сложения возникают свои проблемы. Например, парсер может принять этот оператор за часть синтаксической конструкции, используемой при описании чисел. Я подумал было, что пробел нужен для правильной обработки синтаксиса пользовательских свойств ( — ), но это не так.
При умножении и делении пробелы вокруг операторов не требуются. Но я полагаю, что можно порекомендовать использовать пробелы и с этими операторами — ради повышения читабельности кода, и ради того, чтобы не забывать о пробелах и при вводе выражений, использующих сложение и вычитание.
Пробелы, отделяющие скобки calc() от выражения, никакой роли не играют. Выражение, при желании, можно даже выделить, перенеся на новую строку:
Правда, тут стоит проявлять осторожность. Между именем функции ( calc ) и первой открывающей скобкой пробелов быть не должно:
Вложенные конструкции: calc(calc())
Работая с функцией calc() , можно использовать вложенные конструкции, но в этом нет реальной необходимости. Это аналогично использованию скобок без calc :
Нет смысла строить вложенные конструкции из функций calc() , так как то же самое можно переписать, используя лишь скобки:
Кроме того, в данном примере не нужны и скобки, так как при вычислении представленных здесь выражений применяются правила определения приоритета операторов. Деление и умножение выполняются перед сложением и вычитанием. В результате код можно переписать так:
Но в том случае, если кажется, что дополнительные скобки позволяет сделать код понятнее, их вполне можно использовать. Кроме того, если без скобок, основываясь лишь на приоритете операторов, выражение будет вычисляться неправильно, то такое выражение нуждается в скобках:
Пользовательские CSS-свойства и calc()
Мы уже узнали об одной из замечательных возможностей calc() , о вычислениях, в которых используются значения с разными единицами измерениями. Ещё одна интереснейшая возможность этой функции заключается в том, как её можно применять с пользовательскими CSS-свойствами. Пользовательским свойствам могут быть назначены значения, которые можно использовать в вычислениях:
Уверен, несложно представить себе набор CSS-стилей, в котором множество настроек выполняется в одном месте с помощью установки значений пользовательских CSS-свойств. Эти значения потом будут использоваться во всём CSS-коде.
Пользовательские свойства, кроме того, могут ссылаться друг на друга (обратите внимание на то, что calc() тут не используется). Полученные значения могут использоваться для установки значений других CSS-свойств (а вот тут уже без calc() не обойтись).
Кому-то это может показаться не очень удобным, так как при обращении к пользовательскому свойству нужно помнить о calc() . Но я считаю это интересным с точки зрения читабельности кода.
Источником пользовательских свойств может служить HTML-код. Иногда это может оказаться крайне полезным. Например, в Splitting.js к словам и символам так добавляются индексы.
Назначение единиц измерения пользовательским свойствам после объявления этих свойств
Предположим, мы находимся в ситуации, когда в пользовательское свойство имеет смысл записать число без единиц измерения, или в ситуации, когда подобное число удобно будет, перед реальным использованием, как-то преобразовать, не пользуясь единицами измерениями. В подобных случаях пользовательскому свойству можно назначить значение без указания единиц измерения. Когда нужно будет преобразовать это число в новое, выраженное в неких единицах измерения, его можно будет умножить на 1 с указанием нужных единиц измерения:
Работа с цветами
При описании цветов с использованием форматов, таких, как RGB и HSL, используются числа. С этими числами можно поработать в calc() . Например, можно задать некие базовые HSL-значения, а потом менять их так, как нужно (вот пример):
Нельзя комбинировать calc() и attr()
CSS-функция attr() может казаться весьма привлекательной. И правда: берёшь значение атрибута из HTML, а потом его используешь. Но…
К сожалению, эта функция не понимает «типов» значений. В результате attr() подходит лишь для работы со строками и для установки с её помощью CSS-свойства content . То есть — такая конструкция оказывается вполне рабочей:
Я сказал здесь об этом из-за того, что у кого-нибудь может возникнуть желание попытаться вытащить из HTML-кода с помощью attr() некое число и использовать его в вычислениях:
Правда, хорошо то, что это особого значения не имеет, так как пользовательские свойства в HTML отлично подходят для решения подобных задач:
Браузерные инструменты
Инструменты разработчика браузера обычно показывают выражения с calc() так, как они описаны в исходном CSS-коде.
Инструменты разработчика Firefox, вкладка Rules
Если нужно узнать о том, что вычислит функция calc() , можно обратиться к вкладке Computed (такую вкладку можно найти в инструментах разработчиков всех известных мне браузеров). Там и будет показано значение, вычисленное calc() .
Инструменты разработчика Chrome, вкладка Computed
Браузерная поддержка
Здесь можно узнать о поддержке функции calc() браузерами. Если говорить о современных браузерах, то уровень поддержки calc() составляет более 97%. Если же нужно поддерживать довольно старые браузеры (вроде IE 8 или Firefox 3.6), тогда обычно поступают так: добавляют перед свойством, для вычисления значения которого используется calc() , такое же свойство, значение которого задаётся в формате, который понятен старым браузерам:
У функции calc() существует немало известных проблем, но от них страдают лишь старые браузеры. На Caniuse можно найти описание 13 таких проблем. Вот некоторые из них:
- Браузер Firefox ниже 59 версии не поддерживает calc() в функциях, используемых для задания цвета. Например: color: hsl(calc(60 * 2), 100%, 50%) .
- IE 9-11 не отрендерит тень, заданную свойством box-shadow , в том случае, если для определения любого из значений используется calc() .
- Ни IE 9-11, ни Edge не поддерживают конструкцию вида width: calc() в применении к ячейкам таблиц.
Примеры из жизни
Я спросил у нескольких разработчиков, применяющих CSS, о том, когда они в последний раз использовали функцию calc() . Их ответы составили небольшую подборку, которая поможет всем желающим узнать о том, как другие программисты применяют calc() в своей повседневной работе.
- Я использовал calc() для создания вспомогательного класса для управления полями: .full-bleed < width: 100vw; margin-left: calc(50% — 50vw); >. Могу сказать, что calc() входит в мой топ-3 самых полезных возможностей CSS.
- Я пользовался этой функцией для выделения пространства под неподвижный «подвал» страницы.
- Я применял calc() для гибкой настройки шрифтов и параметров текста. А именно, вычислял свойство font-size , основываясь на параметрах области просмотра. Но свойством font-size это не ограничилось — я применял calc() и для вывода значения свойства line-height . (Обратите внимание на то, что если вы используете calc() для динамической настройки шрифтов, и при этом применяете единицы измерения области просмотра, задействуйте единицы измерения, в которых используются rem или em . Это позволит пользователю управлять размерами шрифта, уменьшая или увеличивая масштаб).
- Мне чрезвычайно нравится возможность применения пользовательского свойства, описывающего ширину содержимого. Им можно пользоваться для настройки расстояния между элементами. Например — так: .margin < width: calc( (100vw — var(--content-width)) / 2); >.
- Я пользовался calc() для создания кросс-браузерного компонента для вывода текста, в котором первая заглавная буква используется как украшение. Вот часть стиля этого компонента: .drop-cap < --drop-cap-lines: 3; font-size: calc(1em * var(--drop-cap-lines) * var(--body-line-height)); >.
- Я применял эту функцию для того, чтобы некоторые изображения на странице статьи выходили бы за пределы своих контейнеров.
- Я использовал её для того чтобы правильно расположить на странице элемент, комбинируя эту функцию со свойством padding и применяя единицы измерения vw/vh .
- Я применяю calc() для обхода ограничений background-position . В особенности это касается ограничений на настройку позиций изменения цвета в градиентах. Например, это можно описать так: «расположить позицию изменения цвета, не доходя 0.75em до низа».
Уважаемые читатели! Пользуетесь ли вы CSS-функцией calc() ?
Источник