Когда бывает нужен calc()

Перевод статьи Use Cases For Css Calc с сайта vincentp.me, опубликовано на css-live.ru с разрешения автора — Винсента Пикеринга

Цитата из твиттера:

Винсент Пикеринг:
— С каждым днём нахожу всё больше применений для calc(). Он действительно полезный

Гарри Робертс:
— Напишешь о некоторых из них?

Безусловно, Гарри, вот основные вещи, для которых я применяю функцию Calc сегодня:

Вертикальное центрирование

Если вам известна высота элемента, то при помощи CSS Calc можно в два счёта позиционировать элемент по вертикали, не нарушая адаптивность дизайна.

С помощью простого уравнения:

calc( 50vh – 1/2 высота элемента)

50vh — всегда составляет половину высоты области просмотра, так что позиционируем элемент ровно по середине экрана. Но это не абсолютный центр, поскольку мы не учли высоту объекта. Для конечного результата нужно отнять половину высоты объекта от 50vh.

See the Pen Calc() — Vertical Centre by Максим (@psywalker) on CodePen.

100% резиновая ширина рядом с фиксированным элементом

С таким применением calc я сталкиваюсь чаще всего, например, в макетах с основной областью и сайдбаром. Когда речь идёт об адаптивном дизайне, и нужно, чтобы одна область заполняла доступное пространство, а другая была фиксированной ширины (и могла бы регулироваться медиазапросами для лучшей гибкости).

Ширина элемента 1 — нашего гибкого контейнера, легко вычисляется при помощи следующей формулы:

calc( 100% — ширина элемента 2)

А если вы к тому же используете border-box, то добавление границ, внутренних отступов и т.д. уже будет учитываться в 100% ширине и соответственно подстраиваться.

Позиционирование фона с правой стороны

Крис Койер уже рассказывал об этом решении, но если вы пропустили, то я упомяну о нём, поскольку иногда оно может пригодиться.

Иногда возникает желание разместить фоновое изображение не точно в правом нижнем углу контейнера, а возле него. Поскольку позиционирование фона отсчитывается от верхнего левого угла, то для добавления внутренних отступов нужны другие обходные пути, либо дополнительные контейнеры.

C Calc это решается просто:

calc(100% — желаемый padding)

Так в примере ниже с помощью calc мы сначала позиционируем изображение в правый нижний угол, а после смещаем его на 50px влево и 20px вверх, эмулируя padding.

See the Pen CSS Calc — Background positioning from the right by Максим (@psywalker) on CodePen.

(Прим. перев.: в модуле фонов и границ 3 уровня свойство background-position позволяет указывать отступы от любого края, напр. right 30px bottom 20px. На момент написания статьи Криса Койера, на которую ссылается автор, это еще недостаточно поддерживалось, но на сегодня она лучше, чем поддержка самой calc).

Равномерное распределение нескольких контейнеров во внешнем контейнере 100% ширины, с учётом «поправочек»

Довольно частое дизайнерское решение — обёрточный контейнер с несколькими контейнерами внутри. Внутренние контейнеры распределятся равномерно, поскольку будут процентной ширины от внешнего контейнера. При таком сценарии вы, наверное, прописали бы каждому контейнеру width:33%; и дело сделано. Но порой для этих контейнеров нужна дополнительная гибкость. Например, если у каждого бокса вы хотите видеть границу, то вам придётся также учитывать и это.

Calc снова выручает!

width: calc(100% / число боксов – суммарный размер margin);

Теперь три бокса внутри родительского контейнера будут распределены равномерно с учётом дополнительных поправочек (напр. границ) для каждого бокса.

100% резиновая ширина с учётом отрицательных внешних отступов

Иногда нам хочется, чтобы дочерний элемент был 100% ширины от своего контейнера с отрицательным внешним отступом. С этим приходится помучиться, потому что ширина 100% не учитывает отрицательных отступов и отбрасывает их при расчете, но, к счастью, calc может выручить:

width:calc(100% + ширина margin);

Чтобы учесть отрицательное значение, мы просто делаем ширину чуть больше 100%.

See the Pen Calc() — Flud Width, with negative margins by Максим (@psywalker) on CodePen.

Модульная сетка, сделанная на скорую руку

Эта чисто экспериментальный прием и, конечно, она не рекомендуется для реальных проектов, но если вам нужно быстро набросать пример или показать принцип работы чего-либо вашим коллегам, то с calc можно быстро создать зачаток модульной сетки в пару строк:

width:calc (100% / общее количество колонок на ряды*колонки, которые нужно охватить)

.col-1 { width:calc(100% /5*1); }

.col-2 { width:calc(100% /5*2); }

.col-3 { width:calc(100% /5*3); }

И т.д...

See the Pen Calc() — Quick and Dirty Grid System by Максим (@psywalker) on CodePen.

А у вас есть еще какой-нибудь прием, что я упустил?

P.S. Это тоже может быть интересно:

17 Комментарии

  1. Игорь Лесневский

    Дизайнеры очень любят такой прием, когда на всех макетах content-область имеет фиксированные внешние или внутренние отступы внутри родителя и ВНЕЗАПНО (!) на каком-нибудь макете какой-нибудь несчастный блок игнорирует эти отступы и занимает собой все пространство по ширине. А дальше все снова идет с этими отступами. Втык себе, за то, что пропустил сразу — это понятно, втык дизайнеру — это тоже. Однако ради одного блока нарушать логику каркаса нет никого желанию, и именно тут выручает calc(); Сдвигаем блок влева отрицательным маргином, и через calc() высчитываем 100% + ширина отступа. Таким образом удается решить эту маленькую проблему.
    А вообще обидно, что IE8 не поддерживает calc() :-( Может хоть полифилы есть

    1. Игорь Лесневский

      Собрал фидл для наглядности — http://jsfiddle.net/wy2q5mht/

      1. Guron-kun

        http://jsfiddle.net/wy2q5mht/1/
        ИМХО прелесть calc() в том что браузер посчитает то что невозможно (или долго, нужно и неинтересно) считать самому.

        В приведенном вами примере calc() не нужен. Измененный фидл http://jsfiddle.net/wy2q5mht/1/

        Тот же результат, работает в ie8. А calc() не нужен т.к. размеры отступа известны и незачем усложнять стили.

        1. Игорь Лесневский

          хм.. где-то у меня это как-то не получилось, видимо и отложилось тогда, что только через calc() можно решить проблему) спасибо, так лучше

  2. Алексей

    http://htmlforum.ru/index.php?showtopic=54094

    Вот кстати, тему открывал на форуме, как раз с помощью calc разделительная линия, состоящая из двух линий, удобно располагается по середине.

  3. Сергей

    Я использую calc(), когда нужно выстроить инлайновые блоки и максимально сократить код.
    http://jsfiddle.net/webirus/dvwazx5y/
    Раньше, css выглядел бы так:

    ul li {
    width: 25%; // делим контейнер на 4 блока
    margin-left: -0.25em; // убираем дурацкий отступ между инлайновыми блоками
    }

    Теперь всё упрощается одной строкой:

    ul li {
    width: calc(100% / 4 - 0.25em);
    }

    Этот метод хорош, когда маленький отступ между инлайновыми блоками не критичен и его можно не фиксить.
    Если же нужно убрать и его, то в принципе, можно обойтись и без calc().

    1. Максим Усачев (Автор записи)

      Кстати, на счёт отступов между инлайн-блоками как раз недалеко есть хорошая статейка, но думаю вы её уже знаете;)

      А что касается вашего способа убрать отступы при помощи отрицательного margin’а, я, если честно, не одобряю это дело. Эта магия очень опасна, и может причинить боль. В вышеприведённой статейке описываются причины (См. заголовок «Вариант 1 — margin-left»):)

      1. Сергей

        Спасибо.
        Не видел статейку, но чувствую, что весьма полезная для моего метода).
        В принципе, ничего жуткого, если честно, не вижу в отрицательном маргине, по тестам довольно неплохо себя ведет. Главное не забывать про первый элемент списка (без отрицательного маргина).
        И еще смотрю циферки почему-то разнятся.
        Потестирую чуть больше. -.36em в статье и -0.25em у меня, которых казалось вполне достаточно.

        1. SelenIT

          Циферки разнятся, потому что ширина пробела разнится между шрифтами.

  4. Константин

    А почему нельзя в реальных проектах использовать?

  5. Тахир

    Господа, а вот в этом примере
    http://codepen.io/vipickering/pen/meEoyp
    зачем float:left используется, если display:inline-block ???
    Флот лефт же не нужен тут!

    1. Родион

      Скорее уж display: inline-block не нужен — с ним появляются дополнительные боковые отступы инлайнового элемента.

      1. Тахир

        Тогда зачем объявление display:inline-block и float:left вместе? Тут inline-block не нужен тогда, это лишняя строка.

        1. SelenIT

          Да, похоже, у автора оригинала здесь ошибка. Действительно, display тут не нужен, float его перебивает. Скорее всего случайно осталось от предыдущих экспериментов (напр. долго выбирал, чем разместить блоки по горизонтали, и забыл убрать лишнее).

  6. Ольга

    Скажите пожалуйста, никто не наблюдал, что в сафари calc не работает? Я пыталась его использовать для центрирования absolute блока, но в сафари ничего не работало(

    1. SelenIT

      А о какой версии Сафари речь? Если верить caniuse, calc стал там поддерживаться c 6-й версии с префиксом и с 7-й — без. В многострадальной 5.1, да, не работает, но ей сегодня никто и не пользуется.

      1. Ольга

        Да про сафари 5.1 как раз я и говорила. Спасибо за ответ

Оставить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Получать новые комментарии по электронной почте. Вы можете подписаться без комментирования.