Пособие для начинающих по позиционированию фона в CSS

Перевод статьи A Primer To Background Positioning In CSS с сайта blogs.adobe.com, автор — Сара Суэйдан.

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

У элемента может быть более одного фонового изображения. Если вы хотите применить более одного фонового изображения, то можете представить их в виде разделённого запятыми списка значений для свойства background-image. Свойство background-position используется для указания позиции фонового изображения, и это свойство стоит рассмотреть поглубже, т.к. его различные возможные значения приводят к разным результатам, некоторые из которых могут оказаться для вас в новинку, если вы не очень хорошо разбираетесь в CSS.

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

Фоновое изображение позиционируется внутри того, что называется «областью позиционирования фона» элемента. Эта область позиционирования фона, как ясно из названия, указывает область, внутри которой будет позиционироваться фон, и у нее есть система координат, используемая для работы с позиционированием.

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

Области боксовой модели CSS

У элемента в CSS определены три области, называемые боксами: border box (бокс по границы включительно), padding box (бокс по отступу) и content box (бокс по содержимому). border box – область элемента, которая включает всю его внутреннюю часть плюс область, которую занимают сами границы.

Padding box – область элемента, исключающая границу, но включающая контент элемента и окружающие его отступы – указанные при помощи свойства padding.

Content box – область, созданная контентом элемента, исключающая любые отступы и границы.

box-areas-700x562-3 Области бокса элемента. Изображение взято из CSS-справочника на Codrops, статья про свойство background-origin.

Есть также четвёртая область — «margin box», включающая элемент и его внешние поля, которые указываются при помощи свойства margin.

Когда вы назначаете элементу фон в виде изображения или сплошного цвета, то по умолчанию он закрашивает всю область границы элемента. (Можно изменить это поведение при помощи свойства background-origin, но мы вернёмся к нему в ближайшее время.)

Чтобы указать, где именно внутри области позиционирования будет находиться фоновое изображение, этой области необходима система координат, используемая для преобразования в неё значений background-position. Прежде чем двигаться дальше, давайте повнимательнее рассмотрим эту систему координат.

Система координат элемента

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

У HTML-элемента есть система координат в CSS. У SVG-элементов, напротив, нет похожей системы координат, поскольку они не регламентируются концепцией боксовой модели.

Начальная точка системы координат в CSS расположена в левом верхнем углу элемента.

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

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

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

Например, предположим у вас есть фоновое изображение, применённое к элементу, и вы не задали ему повторение (поэтому применяется только один экземпляр этого изображения). Исходной позицией фонового изображения внутри системы координат будет начальная точка системы координат padding box. Поэтому верхний левый угол изображения позиционируется в верхнем левом углу внутреннего отступа элемента. (См. живой пример ниже.)

К элементу применена полупрозрачная граница в 20px. Заметьте, как изображение позиционируется в верхнем левом углу внутреннего отступа элемента.

Изображение любезно предоставлено Freepik.com

Используя свойство background-position, о котором мы поговорим в этой статье, мы можем изменять позицию изображения внутри этой системы координат.

Но как упоминалось ранее, мы можем изменить область позиционирования фона, и это, в свою очередь, изменит начальную точку, используемую для позиционирования изображения внутри области фона элемента.

Изменение области позиционирования фона и системы координат при помощи background-origin

Свойство background-origin применяется, чтобы изменить начальную точку системы координат, используемую, чтобы позиционировать фоновое изображение в области позиционирования фона.

Оно принимает одно из трёх значений: padding-box  (значение по умолчанию), content-box и border-box.

В зависимости от выбора области позиционирования фона, соответствующей точке отсчета для фона — начальная точка системы координат, установленной для этой области — изменится, и начальное (по умолчанию) положение фонового изображения тоже.

Следующий живой пример показывает разные исходные точки фона/области позиционирования в действии.

Смотрите пример Сары Суэйден (@SaraSoueidan) «Разные значения background-origin» на CodePen.

Для каждой области позиционирования фона, указанной при помощи background-origin, система координат будет сдвигаться, чтобы покрыть эту область.

Затем, в этой системе координат можно указать положение фонового изображения, используя свойство background-position.

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

Позиционирование фоновых изображений при помощи background-position

В прошлом разделе мы видели, как фоновое изображение по умолчанию позиционируется в левом верхнем углу области позиционирования. Это связано с тем, что по умолчанию значение  свойства background-position равно 0% 0%.

По умолчанию для background-position используются процентное значение. В background-position можно подставлять либо процентное, либо абсолютное значение, которые указывают смещение изображения от одного из четырёх краёв области позиционирования (вверх, право, низ, лево)

offset-edges-and-system-1 Углы смещения элемента и система координат в CSS.

В дополнение к процентным и абсолютным значениям, для смещения можно использовать ещё и пять ключевых слов: top, rightbottomleft и center.

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

background-position: top left;
background-position: 50px 30%;
background-position: top 25%;
background-position: right 10px bottom 20px;
background-position: center center
background-position: 10px 20px;
background-position: 5em 2em;
background-position: 75% 50%;

Если вы укажите только одно значение, то второе будет считаться, как center. Если укажите два значения, то первое будет определять смещение от левого угла — т.е. горизонтальную позицию, а второе – смещение вниз от верхнего угла — вертикальную позицию.

background-position: 10% 50%; /* смещение на 10% вправо, и 50% вниз от верха */
background-position: top; /* идентично `top center` */
background-position: 50px; /* идентично `50px center` */

Можно смешивать и сочетать значения, комбинируя длину с процентами и/или ключевыми словами. Заметьте, что пару ключевых слов можно поменять местами, тогда как комбинацию ключевого слова и длины либо процентов — нельзя. Поэтому center left — правильная запись, а 50% left  — нет, она должна выглядеть так: left 50%. При комбинировании ключевого слова и длины или процентного значения, первое значение всегда отвечает за горизонтальное смещение, а второе — за вертикальное.

Собственно говоря, ключевое слово – это сокращённая запись для определённых процентных значений. Точнее сказать: top — смещение 0% от верхнего края, bottom — смещение 100% от верхнего края, left — смещение  0%  от левого края, right — смещение 100%  от левого края, а center — смещение 50% в том направлении (горизонтальном или вертикальном), к которому оно применяется.

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

Как работают абсолютные значения background-position

При указании значения в абсолютных единицах, вы смещаете верхний угол фонового изображения на указанное число. Другими словами, изображение передвинется так, чтобы его верхний левый угол позиционировался на указанные в значении background-position смещения.

Лучший способ объяснить и понять это – показать наглядно, поэтому здесь представлено два примера абсолютных значений позиции фона и то, как браузеры реализуют позиционирование фонового изображения при помощи абсолютных значений. Элементу в этих двух примерах задан размер 100px на 80px.

absolute-position-illustration-700x367-1Позиционирование фонового изображения при помощи абсолютных значений.

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

negative-absolute-offset-illustration-700x516-1Пример, показывающий смещение изображения при помощи отрицательного значения.

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

Как работают процентные значения background-position

В отличие от значения смещения в абсолютных единицах длины, которое двигает верхний левый угол элемента на указанное расстояние, процентное значение выравнивает точку в X% от левого (для горизонтальной составляющей) или верхнего (для вертикальной) края изображения с точкой в X% от левого (для горизонтальной) или верхнего (для вертикальной) края контейнера.

Например, процентное значение 0% 0% выровняет точку 0% 0% изображении с точкой 0% 0%  в системе координат области позиционирования фона. Значение 50% 75% свойства background-position выровняет точку, которая находится в 50% от левого и в 75%  от верхнего края изображения с точкой, которая расположена на 50% 75% в области позиционирования фона.

И снова, лучше объяснит наглядный пример. Заметьте, как указанное значение background-position используется, чтобы получить точку этих координат внутри изображения, а затем выравнивает эту точку с точкой в тех же координатах в области позиционирования.

percentage-values-illustration-700x345Позиционирование фонового изображения при помощи процентных значений..

Как и с абсолютными единицами длины, можно указать процентное смещение в отрицательных значениях, и они передвинут фоновое изображение на указанное значение в противоположенном направлении на соответствующей оси. Поэтому значения -10% -30% сместят изображение на 10% влево от левого края и на 30% вверх.

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

Смотрите пример Сары Суэйден (@SaraSoueidan) «background-position Example#2» на CodePen.

Позиционирование в предыдущих двух примерах делается относительно верхнего и левого краёв. Теперь давайте посмотрим, как можно объединить ключевые слова вместе с численными значениями смещения (процентами или абсолютными единицами), чтобы позиционировать изображения вдоль области позиционирования фона относительно любого из четырёх краёв элемента.

Смещение относительно любого края

В примерах из предыдущих двух разделов мы указывали смещения и видели, как они используются, чтобы переместить изображение относительно верхнего и левого края — т.е. поведение по умолчанию для одного или двух значений background-position.

Когда мы объединяем в четырёхзначный синтаксис ключевые слова для смещения с численными значениями, мы также можем сместить фоновое изображение от правого и нижнего краёв области позиционирования.

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

Например, в следующем примере используется четырёхзначный синтаксис:

background-position: top 1em right 3em; /* фоновое изображение позиционируется на 1em вниз от верхнего угла и на 3em влево от правого угла */

background-position: right 1em bottom 1em; /* фоновое изображение позиционируется на 1em вверх от нижнего угла и 1em влево от правого угла */

background-position: left 20px bottom 50px;

Если указано три из четырёх значений, четвёртое значение приравнивается к нулю.

При использовании четырёхзначного синтаксиса следует кое-что помнить: когда приведено три или четыре значения, тогда каждое процентное значение или длина представляют смещение и должны идти за ключевым словом, указывающим край, от которого должно смещаться фоновое изображение. Например, background-position: bottom 10px right 20px представляет вертикальное смещение на 10px вверх от нижнего края и горизонтальное смещение на 20px влево от правого края. Если указано три значения, недостающее смещение приравнивается к нулю. Если вы укажите два численных смещения и одно ключевое слово, то такое значение будет неверным и браузер использует 0% 0% — значение по умолчанию.

Чтобы лучше это понять, поиграйтесь со значениями свойства background-position в следующем живом примере. Для лучшего понимания фоновое изображение сначала позиционируется так, чтобы оно смещалось на 0 пикселей от нижнего и 2em от правого края.

Это особенно полезно, когда вам нужно по умолчанию позиционировать изображение на расстояние от правого и нижнего краёв, что сделает эту задачу намного легче, чем вынужденное высчитывание относительных смещений от верхнего и левого углов.

Установка размеров, повторение, обрезка изображений и многое другое!

Помните, что можно к элементу можно применять множественные фоновые изображения. Для каждого фонового изображения (представленных в виде списка изображений, разделённого запятыми в background-image) можно указать соответствующую фоновую позицию; множественные позиции также разделяются запятыми.

В общем, есть девять CSS-свойств, которые управляют раскладкой, позиционированием, определением размеров и закрашиванием фоновых изображений, включая сокращённое свойство background, которое используется для установки и сброса других сокращённых свойств. Каждое свойство позволяет делать что-нибудь одно, а вместе они дают нам отличный контроль над тем, как применять фоновые изображения к любому элементу в HTML.

Кроме того, теперь, помимо основных свойств для фона, есть и дополнительные свойства, которые позволяют применять к фоновым изображениям эффекты наложения, похожие на эффекты, доступные в редакторах типа Photoshop — в частности, свойство background-blend-mode. Если вам интересно изучить всё о наложении в CSS, то можете прочитать об этом в этой статье.

Я надеюсь, что эта статья оказалась для вас полезной. Спасибо за чтение.

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

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

  1. Ринат

    Ошибка во второй картинке (где background-position: 50px(horizontal offset) 30px(vertical offset);): Как работают абсолютные значения background-position.

    1. SelenIT

      Можете уточнить, где именно ошибка? По-моему, всё корректно (на горизонтальной оси отметка 50px, на вертикальной — 30px). В оригинале статьи так же…

  2. Ринат

    Вопрос исчерпан, прошу извинить, все правильно. Стрелки смутили (точнее их направление). Немного сбивает с толку такая визуализация расстояний (стрелка смотрит вниз и кажется, что первое значение не горизонтальное а вертикальное)

  3. Алексей

    Если честно, столкнулся с тем, что несмотря на то, что алгоритм заполнения фон, довольно интересный, его применение в синтаксисе, мне показалось совсем не интуитивным, поэтому хотелось бы отметить это подробней.
    Возьмём такой, не замысловатый пример:

    background: radial-gradient(#f2f780, #254821 70%, #ffaecd 100%) 130% 0% / 200% 100%;

    Вроде, без особого труда ясно, что через слэш представлены значения background-position / background-size (перечислены значения по координатам X и Y), давайте посмотрим как они работают во взаимодействии при различных значениях.
    Отмечу, что радиальный градиент идёт по-умолчанию из центра (что легко меняется), то есть, из точки 50% 50%. Для простоты менять не будем. В нашем случае, по оси X размер градиента 200%, и центр исхождения световых слоёв будет находится посередине, то есть, на 100% по горизонтальной координате, центр — на краю левой стороны экрана. При этом градиент, по-умолчанию, идёт до дальнего угла изображения, в случае, когда градиент расположен по центру, до 100% края градиента доходят его углы в равной степени. По горизонтали и по вертикали градиент заканчивается задолго до 100% своего исхождения что видно на иллюстрации. Градиент как бы обрезается горизонтальными и вертикальными рамками, вписывается в прямоугольное окно и только в углах виден весь его спектр. Поскольку точка исхождения находится посередине, то левые и правые стороны находятся на одинаковом расстоянии от центра, поэтому «новый градиент» начинается с того же фона, на котором заканчивается текущий. Этими плитками заполняется виртуальное пространство.
    В этой статье очень хорошо описан принцип расположения фоновых изображений: точка 70% изображения и видимой части экрана (браузера) совпадёт. Такой, довольно интересный принцип позволяет плавно сдвигать изображения так, чтоб 0% — изображение прижато к левому краю, 100% — к правому (точно такой же принцип может быть применён и для верха/низа). В результате 50% изображение будет в середине, 30%/70% — пропорционально ближе к левой/правой части экрана соответственно.
    Тем не менее, нужно понять, как это принцип применяется, в частности, в таком, как оказалось не простом случае, как радиальный градиент.
    В случае, когда градиент меньше размер экрана, он ведёт себя так, как описано в статье — перемещается влево/вправо по описанному выше алгоритму, свободные участки же заполняются другими градиентами.
    Когда backgrond-size составляет 100%, то, понимая приведённый выше алгоритм лёгко понять, что background-position просто не работает, поскольку любая точка изображения совпадает с аналогичной точкой экрана, а поскольку любое позиционирование фона, это синхронизация изображения и экрана в определённой точке, то, поскольку все точки уже синхронизированы, то и перемещаться просто нечему (в случае когда backgrond-size равен 100% только по определённой координате, то изображение, соответственно не двигается по этой координате, но может двигаться по другой).
    Понимание, что 100% экрана — это окно, а изображение попадает в это окно синхронизируясь с ним в точке указанной в background-position, можно понять и случаи когда фоновое изображение больше чем экран, а также как позиционируются точки большие, чем 100%.
    Ну, во-первых, установим в указаном выше примере для background значения 100% 0% / 200% 100%, то есть, по оси X у нас background-size: 200%, а background-position: 100%. Что мы видим? Окончание горизонтальной части градиента совпадает с концом экрана (то есть самая левая точка градиента, совпадает с самой левой точкой экрана). При этом видно, что градиент больше размера экрана, и, поскольку больше он в два раза (200%), то середина градиента находится ровно в начале экрана, на его левой стороне. Нам понадобилось бы два экрана, чтоб отобразить градиент целиком, второй (виртуальный) экран должен расположиться слева.
    Итак, берём точку 100% у изображения, синхронизируем её с аналогичной точкой экрана(в данном случае 100%), а дальше уже в единицах измерения экрана отмеряем видимую часть.
    Так что же будет если background-position окажется больше 100%?
    Рассмотрим, как раз случай данный в самом начале: 130% 0% / 200% 100%. Нас понятно интересуют значения по X, 200% размер градиента, 130 — позиционирование.
    Что означает эта запись? размер градиента, понятна, равен двум экранам. И, внимание, точка, находящаяся на 130% градиента, совпадает со 130% точкой экрана. То есть, точка синхронизации уходит за размеры экрана и расположена на виртуальном экране справа.
    Что получается? Берём точку 130% от 200-процентного градиента, это 260%. Эта точка совпадает со 130% точкой экрана. Соответственно убираем 30% виртуального экрана, у нас получается 230% это правый край экрана 130% левый край. Размер градиента — 200%, значит начнётся экран с угасания градиента на 130% точке (центр-то на 100%) дойдёт до 200% перейдёт в следующий градиент (градиенты идут последовательно один за другим заполняя виртуальное пространство, отображаясь там куда мы «притащим» наш экран), так вот в 200% точке один градиент кончится и начнётся другой, который пройдёт к центру ровно 30% экрана.
    Вот, пожалуй, и всё — так они и заполняются :-)

    1. Алексей

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

      background: radial-gradient(#f2f780, #254821 70%, #ffaecd 100%) 130% calc(20% + 2em) / 200% 100%;

      Ведь выяснилось же, что фон при background-size: 100% не сдвигается, потому как экран и изображения синхронизированы в каждой точке. Поэтому кажется, что в точке 20% + 2em всё будет тоже самое.
      Но на деле, background-size: 100%, а background-position: calc(20% + 2em) у нас всё по горизонтальной координате сдвигается вниз на 2em.
      В данном случае 20% ни на что ни влияют, мы можем поставить любое значение или вообще убрать calc и поставить 2em, ничего не изменится. Когда стоит значение без процентов, не изменится сдвиг, и если мы background-size поставим 200%.
      Получается у нас как бы два измерения: позиционирование (это я так назвал подгонку фона под проценты экрана), измеряемое в процентах и зависит от background-size и абсолютные значения, которые ни от чего не зависят.
      В принципе, в этом просматривается довольно стройная логика и возможности конкретного сдвига и тонкой подстройки в соответствии с экраном. Но в тоже время когда и то, и другое используется в одной и той же настройке, эта логика, на мой взгляд, не вполне прозрачна…

      1. SelenIT

        Возможно, удобнее будет рассматривать проценты в background-position как проценты от разницы между размером блока и размером фона — так сказать, «от оставшегося доступного места» (и считать их от левого верхнего угла блока до левого верхнего угла фона). Результат тот же, но так может быть нагляднее. Тогда сразу видно, что при background-size:100% любое количество процентов от «доступного места» равно нулю, поэтому и не влияет на общую сумму в calc(). А при background-size больше 100% эта разница оказывается отрицательной, и проценты от нее, соответственно, тоже — поэтому с положительным значением в процентах фон тогда смещается за край контейнера наружу.

        1. Алексей

          Тут ещё есть вот какой момент, когда мы ТАК, двигаем градиент, у нас может получиться как в первом шарике вот этой иллюстрации — градиент «не дотягивается» до края шара, поскольку «прямоугольник мозаики» его обрезает. Можно, наверное, делать и через background-size (хотя зачем там calc, впрочем с ним, пожалуй, нагляднее). Но так вообще, подобный синтаксис, без комментариев разработчика, в некотором роде, вносит некоторую путаницу, когда стараешься его понять, и выяснить, что вообще за что отвечает. Создаётся впечатление, что эти 50% что-то решают (а они ничего не решают, пока background-size: 100%, то является значением по-умолчанию). И центр градиента, вроде как, устанавливается этими 50% calc(50% + 2em), тогда как градиент они вообще не трогают, а двигают фон. Но ведь можно двигать и градиент! И, возможно, это более точное решение, поскольку меняет именно те параметры, которые отвечают за нужные нам свойства…
          По поводу «оставшегося свободного места» — согласен, довольно интуитивная идея. Двигаем на оставшуюся разницу :)
          Есть фон и есть экран, насколько в процентах сдвигается одно, настолько двигается и другое. А на получившуюся разницу в абсолютных величинах, сдвигается центр фона. Если проведём радиус из центра экрана до синхронизируемой точки, то центр фона будет располагаться на прямой, построенной через эти две точки. Если фон меньше, то и радиус у него меньше чем у экрана, и его центр из исходной точки «не дотягивается» до центра экрана. Если фон = экрану, то центры совпадают. Если радиус фона больше, то центр фона уходит в противоположную сторону.
          Легко увидеть на той же иллюстрации/a>, установив значения (после градиента) в 100% 0% / 200% 100%, то есть, сделав фон в два раза больше экрана. Можно увидеть куда фон «уйдёт». Ну и далее, поигравшись со значениями и усвоить как движется фон, относительно экрана.

          1. Алексей

            Хм, жаль сообщения нельзя редактировать :-) Увидел пару неточностей, но надеюсь, Вы поймёте где о чём идёт речь…

  4. Алексей

    Вот ещё один пример, из статьи, в которой показывается изобилие возможностей градиента,, который хотелось бы разобрать подробнее, дабы внести ясность.
    Нас интересует <a href="https://jsfiddle.net/Launder/d36wL7g2/3/"вот этот мазок (в примере закомментированно всё, к нему не относящееся, а background-size, который, до этого задавался отдельным правилом, в котором перечислялись параметры для каждого градиента через запятую, переехал непосредственно в каждый отдельный градиент, чтоб информация о градиенте не собиралась по разным частям кода).
    Вот значимый для нас код:

    width: 15.75em; height: 1.75em;
    padding: 1em 3em;
    border: solid .375em transparent;
    border-radius: 2.25em;
    background: radial-gradient(at 5% 40%, #0b0b0b, transparent 70%)
    no-repeat 0 75% / 9em 4.5em padding-box;

    Попробуем это прочитать :-)
    Во-первых, обратим внимание на самое последнее – padding-box. Он означает что фон у нас располагается внутри паддингов, но не заходит под границы (как это происходит по-умолчанию). То есть, фон заполняет основное содержимое + отступ от основного содежимого до границ (напомню отсчёт идёт от левого верхнего угла и идёт слева направо, по одной координате, и, сверху вниз по-другой).
    Областью заполнения фона является: по-вертикали высота + вертикальные паддиги, по-горизонтали ширина + горизонтальные паддинги.
    Итого: вертикаль 1.75em + 2*1em = 3.75em, горизонталь 15.75 + 2*3em = 21.75em
    Не совсем правильно, но, наверное, интуитивно верно, сказать, что, в данном случае, этот размер – родительский для нашего градиента – поскольку градиент, в некотором роде самобытен, и располагается относительно данного блока, закрашивая его фон.
    Далее, опять же, смотрим на второй, с хвостовой стороны параметр — это «переехавший» background-size. Размеры составляют 9em по-горизонтали, 4.5em по-вертикали. Вот это уже — «родная» для градиента область, в которой он располагается, эта же область вписывается (через background-position) в ту область, которую я назвал родительской — собственно блок, в котором располагается градиент. Давайте пока вернёмся в наши 9em 4.5em и посмотрим как же именно располагается в ней градиент. Итак, в этой области, он исходит из точки 5% 40% (относительно левого верхнего угла) и размер его таков, чтоб дойти до дальнего угла (максимально заполнив собой область 9em 4.5em).
    Можно сказать, что только в этом дальнем угле градиент доходит до своих 100%, поскольку его область ограничена прямоугольником, размеры которого 9em 4.5em. Равноудалённые по % точки располагаются по эллипсу, центр исхождения (0% градиента) находится в точке 5% 40% (с точки зрения области заполнения), а 100% в самом отдалённом углу. Как не трудно догадаться, это правый нижний угол (100% 100% с точки зрения области заполнения). Все же прочие точки эллипса, соответствующие 100% градиента выходят за пределы области заполнения, отчего они и обрезаются. Чуть меньший % оставляет чуть больше точек «лежащих в области» и так далее. Получается, ни точного размера градиента мы не знаем, ни что же именно оказалось обрезанным. По крайней мере, из исходных данных это не очевидно :-)
    Теперь давайте посмотрим на то, как исходит градиент из центра: at 5% 40%, #0b0b0b, transparent 70% — цвет плавно меняется с #0b0b0b, находящегося в центре исхождения градиента, до прозрачного на 70%, то есть, по сути, после 70%(по радиусам эллипса) градиент никак себя не проявляет, получается он заканчивается на 70%(а не на 100%). Откуда эти 70%?
    Давайте для простоты представим, что у нас не эллипс, а круг, потому что эллипс, в некотором роде, это окружность, с одним радиусом, плавно переходящая в окружность, с другим радиусом. Располагается эллипс таким образом, что один радиус соответствует горизонтальной составляющей, другой — вертикальной. Получается, для определённой стороны эллипс ведёт себя как круг. Чему равно соотношение радиуса, исходящего под углом 45 градусов, и его проекции на горизонтальную или вертикальную плоскость? У нас получается прямоугольный треугольник где гипотенуза — радиус, а катеты — проекции. По теореме Пифагора квадрат гипотенузы, равен сумме квадратов катетов, катеты равны и, если положить их длину как единицу, то сумма их квадратов равна двум, значит длина гипотенузы равна корню из двух (sqrt(2) = 1.4142…). Гипотенуза – это наш радиус в дальний угол эллипса. Проекции, для горизонтальной и вертикальной составляющей, это рамки, ограничивающие область градиента. Проекция короче полного радиуса (находящегося на 100% градиента), и, если проекцию считать единицей, то длина радиуса будет равна sqrt(2). Радиуса у нас два, горизонтальный и вертикальный. Каждый из этих радиусов равен соответствующей проекции умноженной на корень из двух. Горизонтальная проекция — это расстояния от центра градиента до правой стороны, вертикальная — до низа (поскольку радиус считается до дальнего угла, то есть, до правого нижнего). Итак, 100% градиента располагается в точке проекции умноженная на корень из двух. Значит крайние значения градиента для стороны равны 100%/sqrt(2) = 70%(примерно). Получается градиент у нас не обрезается, а «всего лишь» идёт не до дальнего угла, а до дальней стороны (а до дальнего угла, по-факту, не доходит). Изменим значение по-умолчанию (farthest-corner — дальняя сторона), добавив в строку значение farthest-side (дальняя сторона) и изменим значение для прозрачности с 70% до 100% градиента. Поучится radial-gradient(farthest-side at 5% 40%, #0b0b0b, transparent 100%) остальное, всё тоже самое — применив изменения, увидите, что ничего не изменилось (но ИМХО, стало немного понятнее).
    Итак понятно вот что: размер области (9em горизонталь 4.5em вертикаль), точка исхождения в ней 5% горизонталь 40% вертикаль, исходит градиент не равномерно (окружность), а эллипсом, поэтому радиус вертикальной и горизонтально составляющей отличается (а промежуточные радиусы по размеру лежат между ними, то есть точки соответствующие одному % лежат на разных радиусах и образуют эллипс). И по вертикальной и горизонтальной составляющей, градиент доходит до дальней стороны.
    Размеры, в первом приближении ясны, теперь давайте посмотрим, как располагается область градиента, относительно области фона, которую он призван заполнить. Во-первых, в параметрах background’a указано no-repeat, а значит область у нас одна (по-умолчанию кирпичики из областей градиента заполнили бы всё пространство элемента). Параметры background-position: 0 75%. По горизонтали нуль означает что первая точка заполняемой области и первая точка области градиента совпадают. А вот 75% означает, что градиент и блок, в котором он располагается, имеют общую точку: 75% по вертикали блока, совпадает с 75% по вертикали градиента. Размер паддинг-области блока составляет 3.75em по вертикали (напомню, по-умолчанию фон располагается и под границами(border-box), но у нас в параметрах указанно padding-box, поэтому кроме непосредственно области содержимого (которое у нас представлено длинной и высотой) учитываются ещё и отступы (padding), а вот границы игнорируются), в размер градиента по-вертикали составляет 4.5em. Напомню, отсчёт идёт от левого верхнего угла, соответственно 0% по вертикали — верхняя точка, а 100% — нижняя. Получается «синхронизируясь» на 75% обе области (и градиента и фона) уходят на 25% вниз (разница получается (4.5 — 3.75)х25%), и на 75% вверх (разница побольше: (4.5 — 3.75)x75%). Получается если бы точка синхронизации была 100%, то область градиента ещё больше бы сдвинулась вверх, а если 0%, то, наоборот — вниз. А если бы область градиента была меньше области фона, то — наоборот, поскольку, бы в этом случае фон «подтягивал» градиент, а в нашем случае градиент «втискивается» в фон, показывая то, что «ближе». Ближе конец, показываем конец, а начало сдвигается наверх. В результате, не смотря на то, что логика фона такая что «чем больше процент, тем ниже», в нашем случае, происходит обратное, увеличивая процент, мы сдвигаем градиент выше.
    Снова подобьём. Область заполнения фона padding-box, итого размеры 21.75em по-горизонтали, 3.75em по-вертикали. Размеры области градиента 9em по-горизонтали, 4.5em по-вертикали. Градиент не повторяется, то есть, он расположился так, как он расположился и где он закончился, там он закончился :-) А расположился он так, по-горизонтали, начало градиента совпадает с началом блока, а по вертикали градиент немного сдвинут вверх, из-за того, что синхронизировались градиент и фон ближе к концу и того и другого (75%), а поскольку область градиента по вертикали больше, то до начала «отсчёта» у него расстояние тоже больше, вот он и начинается по-вертикали за пределами фона. В самой же области градиента точка исхождения располагается на расстоянии 5% 40% от его верхнего края, и идёт градиент не до дальнего угла, как должен, а до дальних сторон (правой и нижней), поскольку плавно перетекает до прозрачности, которая находится на волшебном расстоянии 70%, которая совпадает с расстоянием до которого градиент «успевает дойти» когда доходит до дальнего угла, дальше он обрезается боковыми гранями, и, если бы не было запрета на повторения градиента, начиналась бы следующая область заполнения градиента, где градиент был бы намного ближе к центру: ведь новый градиент прилегает к текущему стороной, которая ближе к его центру, а значит там градиент успел «пройти» ещё меньше. Поскольку до 100% градиент должен был бы дойти в дальнем углу области, но на 70% становится прозрачным, то мы просто видим эллипс, крайние точки которого доходят до дальних сторон области градиента.
    Вот такая, в принципе, довольно прозрачная логика, по всей видимости, была у автора упомянутой статьи. Ну а что не понятного? Вот область, вот понятные 70% делающие эллипс до дальней стороны, по-горизонтали позиционирование, вообще не вопрос, совпадает с блоком, а по-вертикали, если иметь опыт и «видеть», что когда блок меньше градиента, то при увеличении точки синхронизации, градиент сдвигается «наоборот» вверх, всё в принципе, более-менее ясно. То, что background-size у автора указан отдельным правилом, сразу для всех градиентов – вообще вопрос технический – размеры указаны для всех градиентов по очереди, посчитал каким по счёту следует градиент и применил к нему те параметры, которые в той же очерёдности. Сложного, в общем-то, ничего. С опытом, наверное, подобное «прочитывается» на автомате.
    И тем не менее, для человека, который всё это дело осваивает, понятного нет практически ничего: точка 5% 40% это вообще где? от чего она меряется? а что тогда показывает background-position? почему когда увеличиваешь вертикальное позиционирование градиент сдвигается вверх, а не вниз, когда размер считается сверху вниз? как влияет размер исходного блока? откуда цифра 70% и откуда вообще все цифры? Это подбиралось как-то на глаз или есть в этом какая-то логика? Сплошные вопросы, и, читая синтаксис и, в общем, понимая что он должен означать, может возникнуть слишком много разночтений, чтоб в голове выстроилась стройная картинка, что откуда и зачем. И, действительно, по сути, даже имея, представленную выше картину, расположение градиента у нас довольно туманное. Где именно располагается точка исхождения градиента? Каков размер градиента? Не области где он лежит, а самого градиента, то есть каков размер двух его эллиптических радиусов, горизонтального и вертикального? По сути, без ответов на эти, в общем-то простые вопросы, чёткости в понимании каков градиент, нет, и то, что автор, ввиду опытности, сходу видит как в данной области на такой-то точке будет виден градиент и как его можно сдвинуть, не проясняет его точных параметров. Гипотетически можно предположить, что мы не знаем точных параметров градиента, но знаем область и то, как он в этой области располагается, а также выяснили место, где области координат градиента и блока совпадают, но сильно сомневаюсь, что на практике распространён такой метод доставания левой ногой до правого уха. Если какие-то параметры градиента и считаются, то, радиусы, скорее всего, в первую очередь. Думаю, в данном случае, имеет место просто понимание где может располагаться затемнение и попытка на глаз его обозначить. По крайне мере, никакой информации «почему именно такое и именно там», в статье нет. По всей видимости, разница только в том, что для автора статьи сделать затемнение таким образом – интуитивно, а для человека, не имеющего опыт верстальщика — едва ли.
    Что ж, давайте попробуем это исправить :-)
    Итак требуется найти где относительно блока располагается центр градиента, а также его вертикальный и горизонтальный радиус.
    Для начала, вспомним размеры фоновой области, с учётом того, что у нас padding-box, учитываются контент и паддинги, но не учитываются границы. По-горизонтали 21.75em, по-вертикали 3.75em. «Область градиента» меньше, она хоть и чуть-чуть больше по-вертикали, но зато существенно меньше по-горизонтали. Поскольку по горизонтали нулевая точка фона и градиента совпадают, то мы можем смело отсчитывать 5% от области градиента, там же эта точка будет находится и относительно фона. 5% от 9em составляет 0.45em. По вертикали 75% точка фона, совпадает с 75% точкой градиента, получается точка совпадения отстоит от начала фона на 3.75em x 0.75 = 2.8125em, а градиент начинается выше: 4.5 x 0.75 = 3.375em, при этом выше он на 3.375 — 2.8125 = 0.5625em. Центр исхождения градиента, от этой точки на 40%(от 4.5em) вниз, то есть 4.5 x 0.4 = 1.8em. А поскольку начала градиента по вертикали выше 0.5625em начала фона, то относительно фона центр градиента по-вертикали составляет 1.8em — 0.5625em = 1.2375em.
    Итак точка исхождения градиента от начала фона (с учётом паддингов) 0.45em по-горизонтали, 1.2375em по вертикали. Пока отметим эти значения в абсолютных величиных, потом переведём их и в %. Вообще, способов найти эти координаты, наверное, великое множество, и не факт, что я выбрал самый простой. Можно, например, искать % насколько отодвинута точка от начала фона. Можно как-то «сыграть» на соотношении 3.75 и 4.5 и поискать насколько «отодвинута» «точка градиента 40%» от «точки синхронизации» 75%. Можно, наверное, как-то ещё, но главное тут – понимать, что есть что, а далее, задача решается математикой, элементарной, чуть менее, чем полностью.
    Теперь выясним размер градиента, не некую «область градиента», а размер эллипса, соответствующий 100% градиента, его горизонтальный и вертикальный радиус. У нас градиент «идёт» до дальней стороны (с учётом «преобразованных» 70%). Зная область градиента и смотря на точку исхождения, получается, что по-горизонтали он идёт от точки 5% (0.45em) до 9em, соответственно, горизонтальный радиус получается 9em — 0.45em = 8.55em, по вертикали он идёт от точки 40%, соответственно его размер составляет 60% от области градиента 4.5em, это 2.7em. Больше нам эта пресловутая «область градиента» не нужна – у нас есть точные данные размеров и расположения, а также знание того, что градиент не повторяется, находится там, где расположен и всё.
    Абсолютные размеры известны, пришло время посмотреть и на относительные размеры. А относительно чего располагается градиент? Относительно области фона блока. В результате не будет непонятной «области градиента», будет понятная область фона, на которой располагаются все элементы блока(ну или иного элемента, который мы «раскрашиваем»).
    Для точки исхождения градиента: горизонталь: 0.45em это 2% от 21.75em(горизонтальный размер элемента с учётом паддингов), а 1.2375em по-вертикали, это 33% от 3.75em. Для радиуса: по-горизонтали 8.75em это 40% от 21.75em (примерно), а 2.7em по-вертикали это 72% от 3.75em.
    Итоговый синтаксис в абсолютных единицах:

    radial-gradient(8.55em 2.7em at 0.45em 1.2375em, #0b0b0b, transparent 100%)
    no-repeat padding-box

    В относительных единицах:

    radial-gradient(40% 72% at 2% 33%, #0b0b0b, transparent 100%)
    no-repeat padding-box

    Вот, сравните начальный вариант, и получившийся в абсолютных и относительных единицах.
    Что лично мне нравится в ТАКОЙ записи? Да то, что понятна каждая цифра, вот родительский элемент, вот из этой точки исходит градиент, таков его горизонтальный, таков вертикальный радиус. Это, в общем-то, легко представить, этим удобно можно манипулировать, если же что-то где-то рассчитывается, используются итоговые величины, то есть, результат налицо.
    То, что посчитать бывает не лишним автор в курсе, другой вопрос, что по видимому, подобные, «мазки на глаз», для неё осуществляются глубоко интуитивно, поэтому насчёт синтаксиса она, скорее всего, особо не заморачивается — для неё итак ясно, что на что влияет, и что из этого в итоге может получится. Для неё… Но а теперь – и для нас :)
    Написал этот пост, к статье для начинающих, поскольку когда понимаешь, как это всё работает, можно уже воспринимать СТАТЬЮ, а не заниматься гаданиями «наверное она это имела в виду». Для авторской же статьи наверное, всё это, не так важно, поскольку хоть возможности и описываются синтаксисом, но из самого синтаксиса совсем не очевидны конструкции, которые из него можно соорудить.
    Это как кисть, для того чтоб рисовать, нужно уметь ей пользоваться, но для рисования нужен ещё художественный замысел.
    ЗЫ: Вот ещё вот эта кнопка, из вышеупомянутой статьи, размеры, которой, тоже стали видны из синтаксиса, и <a href="http://codepen.io/thebabydino/pen/wMGJQR"она же с псевдоэлементом тоже причёсанная.
    ЗЫЗЫ: Вот ещё один замечательный пример из книги Влада, который я, в своё время, разобрал подробно. Там другая, интересная для новичков тема – связь фона и анимации.
    В общем, тема фона в CSS на редкость многогранна :)

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

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

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

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