Как сделать степень в css
Математические функции в CSS
Например, не получится сделать значение на основе пикселей, зависящее от единиц вьюпорта. Вот этот пример работать не будет (это SCSS):
Компилятор будет ругаться на несочетаемые единицы.
calc() сможет сложить пиксели и единицы вьюпорта. Это позволит сделать плавающий размер шрифта, который будет зависеть от ширины окна браузера. Препроцессоры так не умеют.
Таким образом, главное преимущество математических функций в CSS — динамичность значений благодаря способности сочетать абсолютные и относительные единицы измерения.
Ещё важно помнить, что при использовании препроцессоров CSS-функции могут конфликтовать с препроцессорными. Например, если в SCSS или в Less написать такое:
компилятор будет ругаться на несовместимые единицы, потому что сработает функция из препроцессора.
Чтобы препроцессоры при компиляции не пытались выполнить CSS-функции, в SCSS предлагается писать имя функции с заглавной буквы:
Подробнее об этом можно почитать в статье Аны Тюдор When Sass and New CSS Features Collide.
В LESS поможет оборачивание кавычками:
min(), max()
Функция min() возвращает минимальное из переданных значений, max() — максимальное. При использовании процентов или относительных единиц выбираемое значение будет динамическим и будет зависеть от внешних условий. Например:
Если поресайзить окно с примером, можно увидеть как это работает.
Функция min() будет выбирать подходящее значение учитывая ширину окна в данный момент.
Этот код не делает ничего особенного, что не умел бы CSS без математических функций: точно такое же поведение можно получить задав width и max-width :
Оба варианта для сравнения:
Порастягивайте демо, чтобы увидеть, что разницы в поведении блоков нет.
На первый взгляд, min() и max() не делают ничего интересного, но если подумать, как много мест в CSS, где можно управлять диапазоном значений?
Это доступно только для ширины и высоты:
и их аналогов, привязанных к направлению письма:
Если попытаться реализовать подобное на JS, пришлось бы отслеживать ресайз окна, получать вычисленное значение, и при превышении заданного порога, фиксировать значение на определённом уровне. При использовании min() и max() браузер всё делает сам: отслеживает изменение значений и, при необходимости, фиксирует их — нам нужно просто выбрать функцию и задать диапазон значений.
Это будет работать во всех свойствах, которые используют размеры, в том числе в тенях, градиентах и прочем. Пример с box-shadow :
Экспериментируя с функциями min() и max() можно заметить, что они дают возможность управлять или минимальным значением, или максимальным, но нельзя контролировать и то, и другое одновременно. Хотя совершенно логичным выглядит желание, например, задать размер шрифта, который будет расти в диапазоне от минимального значения до максимального и не выходить за эти значения.
Для такого есть ещё одна функция:
clamp()
И вычисляет значение вот таким образом:
Проще всего её понимать представляя среднее значение ( VAL ) как желаемое, которое ограничено минимальным и максимальным значениями. Например, этот код
Аналогичный подход часто используется при разработке адаптивных сайтов: мы задаём минимальное и максимальное значения ширины страницы, позволяя ей тянуться и сжиматься в заданных пределах, например, в диапазоне от 320px до 1200px :
Используя clamp() это можно записать в одну строчку:
Оба блока ведут себя совершенно одинаково, разница только в возможностях этих подходов: clamp() позволяет добавить умную динамику значений в любое свойство, не только в размеры блоков. Мне нравится идея использовать clamp() для адаптивных шрифтов, почитать про это можно в статье Linearly Scale font-size with CSS clamp() Based on the Viewport.
Функция позволяет производить математические операции:
В отличие от препроцессорных вычислений, calc() позволяет сочетать любые совместимые значения. Например, можно вычесть пиксели из процентов:
Внутри calc() можно использовать кастомные свойства, и это делает вычисления в CSS гораздо мощнее препроцессорных. Например, на calc() и кастомных свойствах можно без каких-либо скриптов сделать простой генератор цветовых схем:
По клику на цвет в CSS меняется значение CSS-переменной, и вся палитра пересчитывается.
Рассчёт оттенка ( hue из HSL) делается таким образом:
И затем оттенок используется для формирования цвета в формате HSL:
Конечно, подобные вещи удобнее и логичнее делать на JS, демо просто показывает, что CSS достаточно мощный, чтобы уметь такое.
Примеры использования
Cохранение логики рассчётов
Например, если нужна ширина в 1/12 от общей, можно высчитать значение и записать его в стили:
Но так непонятно что это за число. Станет немного понятнее, если логику рассчёта положить рядом в комментарии:
Так сразу понятно, что элемент занимает 1/12 ширины родителя, и не нужно поддерживать комментарии в актуальном состоянии.
Управление размерами элементов
Например, есть карточка с картинкой, картинка ужимается под ширину колонки с текстом:
Как растянуть картинку на ширину карточки не привязываясь к размерам карточки? С помощью calc() :
Можно ещё немного улучшить код, используя кастомные свойства:
Так сохранится логика рассчётов, 1rem становится не магическим числом, а именованной переменной, и по самому коду будет понятно, что ширина картинки увеличивается на два паддинга, а потом сдвигается влево на один. Можно примерно понять что делает этот код даже не глядя на страницу в браузере.
Ещё это будет полезно для инпутов. Допустим, нужно, чтобы инпут тянулся на всю ширину родителя, оставляя 40 пикселей справа. Вариант с фиксированной шириной не подходит для адаптивного дизайна. Если просто задать ширину 100% и марджин, блок растянется на всю ширину и сжиматься не будет. С этой задачей прекрасно справится calc() :
Текстовое поле всегда будет отодвинуто от края на 40px (+ паддинг) независимо от размера родительского элемента.
Адаптивная типографика
С помощью calc() можно примешивать единицы вьюпорта к обычному размеру шрифта, тогда при увеличении размеров экрана будет расти и шрифт:
Порастягивайте демо, чтобы увидеть как размер окна влияет на размер шрифта:
Почитать об этом больше можно тут или тут.
Управление размерами фона
С помощью calc() можно задать размер фоновому изображению, комбинируя фиксированные единицы и проценты. Например, чтобы фон всегда отступал от краёв на определённое значение:
Полосатые поля показывают прозрачные области вокруг разноцветного градиента.
Используя этот же подход можно делать вырезанные углы квадратной формы:
В отличие от версии с коническими градиентами, этот вариант будет работать во всех браузерах. Способ был предложен Ильёй Стрельциным.
Также можно рисовать линейными градиентами полосы заданной ширины:
Вычисление цветов и шагов градиента
Иногда для экспериментов нужен полосатый градиент. Чтобы не считать параметры руками, их можно вычислять с помощью calc() на основе кастомных свойств. Вот так задаются параметры:
А вот так потом высчитывается оттенок:
Редактируя переменные можно менять параметры градиента без необходимости пересчитывать вручную шаги или переписывать весь градиент.
Правда, при таком автоматическим вычислении оттенков могут получаться не очень красивые цвета, но для экспериментов вполне пойдёт.
Область применения cacl() гораздо шире перечисленных примеров. В некоторых случаях, если значения не должны меняться динамически, с подобными задачами справятся и препроцессоры, но если должны, например, при изменении кастомных свойств или размера окна, — без calc() не обойтись.
Нюансы
При использовании calc() нужно помнить о некоторых тонкостях:
calc() умеет производить рассчёты только для совместимых единиц. Например, можно сложить пиксели с процентами или единицами вьюпорта, градусы с радианами и вычесть миллисекунды из секунд, но вот сложить секунды с пикселями или градусы с единицами вьюпорта ожидаемо не получится, потому что непонятно в каких единицах ожидается результат.
У меня была слегка безумная идея привязать градусы градиента к ширине вьюпорта (и вращать градиент растягивая окно браузера), но я не придумала как это можно реализовать, и не уверена, что это в принципе возможно без JS;
Светлое будущее?
В спецификации есть интересный момент: утверждается, что внутри calc() в качестве значений можно использовать содержимое атрибутов, да и в принципе можно использовать атрибуты как значения CSS-свойств.
От обычного использования attr() в качестве содержимого псевдоэелемента это отличается указанием типа содержимого:
Или единиц измерения:
Значение после запятой — запасное, на случай, если не удастся получить или распарсить значение атрибута.
Поначалу эта конструкция показалась мне странной: зачем класть данные в атрибуты, а потом ещё и типизировать их в CSS, если можно сразу положить нужное в кастомные свойства?
Но в твиттере мне быстро накидали примеров, когда это было бы действительно удобно. Например, получая размеры из атрибутов было бы удобно делать адаптивные картинки и фреймы. У меня получилось сделать адаптивное видео, используя кастомные свойства, но для этого приходится дублировать размеры в инлайновых стилях. Если бы можно было считывать значения из атрибутов, без дублирования можно было бы обойтись.
На момент написания статьи это не поддерживается ни одним браузером, но есть некоторая надежда, что однажды это заработает, потому что подобное использование атрибутов описано в спецификации свойства, которое помогло бы управлять соотношением сторон: aspect-ratio. Там есть такой пример:
И вот это было бы очень круто, потому что избавило бы разработчиков от необходимости городить странные конструкции для решения той же задачи. Почитать про aspect-ratio можно в статье Рэйчел Эндрю Designing An Aspect Ratio Unit For CSS.
Поддержка браузерами
При необходимости проверить поддержку функций и кастомных свойств можно воспользоваться @supports (также учитывая поддержку браузерами для него):
CSS: полное руководство по функции calc()
Автор статьи, перевод которой мы сегодня публикуем, хочет рассказать обо всём, что стоит знать об этой весьма полезной функции.
Функция calc() и значения CSS-свойств
Единственное место, где можно использовать функцию calc() — это значения CSS-свойств. Взгляните на следующие примеры, в которых мы, используя эту функцию, задаём значения различных свойств.
Функцию calc() можно применять и для установки любой отдельной части свойства:
Эта функция может даже быть частью другой функции, которая отвечает за формирование части некоего свойства! Например, здесь calc() используется для настройки позиций изменения цвета градиента:
Функция calc() — это средство для работы с числовыми свойствами
Обратите внимание на то, что во всех вышеприведённых примерах мы используем функцию calc() при работе с числовыми свойствами. Мы ещё поговорим о некоторых особенностях работы с числовыми свойствами (они связаны с тем, что иногда не требуется использование единиц измерения). Сейчас же отметим, что данная функция предназначена для выполнения операций с числами, а не со строками или с чем-то ещё.
Эта функция умеет работать и с числами, применяемыми без указания единиц измерения:
Её можно использовать и для вычисления углов:
Данную функцию можно применять и в тех случаях, когда в передаваемом ей выражении никаких вычислений не выполняется:
Функцию calc() нельзя применять в медиа-запросах
Хотя эта функция предназначена для установки значений CSS-свойств, она, к сожалению, не работает в медиа-запросах:
Если когда-то подобные конструкции окажутся работоспособными — это будет очень хорошо, так как это позволит создавать взаимоисключающие медиа-запросы, выглядящие весьма логично (например — такие, которые показаны выше).
Использование разных единиц измерения в одном выражении
Это выражение читается так: «Ширина равна ширине элемента, из которой вычитается 20 пикселей».
Вот ещё пара примеров использования значений, выраженных в разных единицах измерения:
Эти выражения, вероятно, можно подвергнуть препроцессингу, так как в них смешаны значения, единицы измерения которых не связаны с чем-либо, определяемым во время работы страницы в браузере.
Сравнение calc() с вычислениями, обрабатываемыми препроцессорами
Здесь могут производиться вычисления с указанием единиц измерения, тут можно складывать величины, выраженные в одних и тех же единицах измерения, можно умножать некие величины на значения, единицы измерения которых не указаны. Но выполнять вычисления со значениями, выраженными в разных единицах измерения, здесь нельзя. На подобные вычисления накладываются ограничения, напоминающие ограничения calc() (например, числа, на которые что-то умножают или делят, должны представлять собой значения без единиц измерения).
Раскрытие смысла используемых в CSS числовых значений
Такой подход может оказаться полезным в чём-то вроде некоего самописного CSS-API:
Математические операторы функции calc()
Обратите внимание на то, что использование некорректных значений приводит к тому, что конкретное объявление также становится некорректным.
При делении ( / ) нужно, чтобы у второго числа не была бы указана единица измерения
При умножении ( * ) у одного из чисел не должна быть указана единица измерения:
О важности пробелов
Пробелы, используемые в выражениях, важны в операциях сложения и вычитания:
При умножении и делении пробелы вокруг операторов не требуются. Но я полагаю, что можно порекомендовать использовать пробелы и с этими операторами — ради повышения читабельности кода, и ради того, чтобы не забывать о пробелах и при вводе выражений, использующих сложение и вычитание.
Пробелы, отделяющие скобки calc() от выражения, никакой роли не играют. Выражение, при желании, можно даже выделить, перенеся на новую строку:
Правда, тут стоит проявлять осторожность. Между именем функции ( calc ) и первой открывающей скобкой пробелов быть не должно:
Вложенные конструкции: calc(calc())
Кроме того, в данном примере не нужны и скобки, так как при вычислении представленных здесь выражений применяются правила определения приоритета операторов. Деление и умножение выполняются перед сложением и вычитанием. В результате код можно переписать так:
Но в том случае, если кажется, что дополнительные скобки позволяет сделать код понятнее, их вполне можно использовать. Кроме того, если без скобок, основываясь лишь на приоритете операторов, выражение будет вычисляться неправильно, то такое выражение нуждается в скобках:
Пользовательские CSS-свойства и calc()
Уверен, несложно представить себе набор CSS-стилей, в котором множество настроек выполняется в одном месте с помощью установки значений пользовательских CSS-свойств. Эти значения потом будут использоваться во всём CSS-коде.
Пользовательские свойства, кроме того, могут ссылаться друг на друга (обратите внимание на то, что calc() тут не используется). Полученные значения могут использоваться для установки значений других CSS-свойств (а вот тут уже без calc() не обойтись).
Источником пользовательских свойств может служить HTML-код. Иногда это может оказаться крайне полезным. Например, в Splitting.js к словам и символам так добавляются индексы.
Назначение единиц измерения пользовательским свойствам после объявления этих свойств
Предположим, мы находимся в ситуации, когда в пользовательское свойство имеет смысл записать число без единиц измерения, или в ситуации, когда подобное число удобно будет, перед реальным использованием, как-то преобразовать, не пользуясь единицами измерениями. В подобных случаях пользовательскому свойству можно назначить значение без указания единиц измерения. Когда нужно будет преобразовать это число в новое, выраженное в неких единицах измерения, его можно будет умножить на 1 с указанием нужных единиц измерения:
Работа с цветами
Нельзя комбинировать calc() и attr()
CSS-функция attr() может казаться весьма привлекательной. И правда: берёшь значение атрибута из HTML, а потом его используешь. Но…
Я сказал здесь об этом из-за того, что у кого-нибудь может возникнуть желание попытаться вытащить из HTML-кода с помощью attr() некое число и использовать его в вычислениях:
Правда, хорошо то, что это особого значения не имеет, так как пользовательские свойства в HTML отлично подходят для решения подобных задач:
Браузерные инструменты
Инструменты разработчика браузера обычно показывают выражения с calc() так, как они описаны в исходном CSS-коде.
Инструменты разработчика Firefox, вкладка Rules
Инструменты разработчика Chrome, вкладка Computed
Браузерная поддержка
У функции calc() существует немало известных проблем, но от них страдают лишь старые браузеры. На Caniuse можно найти описание 13 таких проблем. Вот некоторые из них:
Примеры из жизни
Математика разметки с помощью CSS: разбираемся с calc
За последние годы верстка в интернете развилась из фиксированных дизайнов к адаптивным. Причем, в стилях могут использоваться сразу несколько видов единиц измерений (проценты, em или px). Дизайнерам и разработчикам следует понимать, как это работает. Но было бы удобно оперировать (складыва/вычитать) единицами разной размерности в одном и том же выражении.
Для этого отлично подходит calc. При ее всей мощности, то, как ее можно применять, лучше продемонстрировать на примерах.
Vertical Flush Margins
Например, возьмем шикарную фотографию водопада от Stian Klo. Это изображение сдвинуто с отступом в 2rem вправо. Теперь его сделаем адаптивным, установив ширину в 50% от ширины родительского элемента:
Нам нужно, чтобы вертикальный зазор увеличивался, визуально подчеркивая изображение негативным пространством под ним. Проблема в том, что адаптивность абзацев означает, что они будут “ползать” под картинкой по мере сужения (link):
Есть много способов решить эту проблему, и одним из самых простых будет так, чтобы:
у абзацев рядом с картинкой был левый отступ 50% плюс 2rem.
Используя calc, это будет (link):
calc же позволяет комбинировать разные системы измерения, делая отсуп фиксированным, а картинку — адаптивной.
Full-Width Elements In Padded Containers
Рассмотрим следующий пример — полноширинный элемент (например, картинка) над контентом с внутренним отступом (padding):
Проблема заключается в том, что padding элемента также смещает контент внутрь (link):
Это можно исправить путем вычисления ширины с помощью calc:
Операции
calc поддерживает основные арифметические операции (сложение (+), вычитание (-), умножение ( * ) и деление (/)). Важно помнить о том, что необходимо обрамлять операнды сложения и вычитания пробелами с двух сторон, а между calc и открывающей скобкой ничего не должно быть. Так что в такой форме это будет работать:
Тому есть простое объяснение: какое-либо число со знаком минус перед ним будет трактоваться, как отрицательное значение.
Возможности и ограничения
Все современные браузеры поддерживают calc для длины в CSS. Теоретически, calc может быть применим в любом месте, где встречаются операции с числами, что дает несколько интересных применений:
Выражаю огромную благодарность Ana Tudor за проведение этих исследований; больше информации о поддержке calc браузерами вы можете найти на caniuse.com
calc так же может быть применяться для вычисления color stops в градиентах.