Мы часто думаем о фоновых изображениях как о текстуре или чем-то, что обеспечивает контраст для разборчивого контента — другими словами, не совсем о контенте. Если бы это был контент, вы, вероятно, все равно потянулись бы к <img>, доступности и тому подобному.
Но бывают случаи, когда position или scale фонового изображения могут находиться где-то между полюсами содержания и оформления. Контекст решает, верно? Если мы изменим положение фонового изображения, оно может передать немного больше контекста или опыта.
Как же так? Давайте посмотрим на несколько примеров, которые я видел.
Когда мы начнем, я предупрежу, что в этих демонстрациях существует тонкая грань между изображениями, используемыми для украшения, и изображениями, используемыми в качестве контента. Разница имеет последствия для доступности, когда фоны не объявляются программами чтения с экрана. Если ваше изображение действительно является изображением, то, возможно, рассмотрите тег <img> с правильным альтернативным текстом. И пока мы говорим о доступности, неплохо было бы также учитывать предпочтения пользователя в отношении движения.
Покажи мне больше!
У Криса Койера есть эта аккуратная небольшая демонстрация, сделанная несколько лет назад.
Демонстрация очень удобна во многих отношениях, потому что это аккуратный подход к отображению рекламы в контенте. У вас есть коммерческое предложение и заманчивое изображение в дополнение к нему.
Могу поспорить, что большим ограничением для большинства объявлений является ограниченное пространство. Я не знаю, приходилось ли вам когда-нибудь размещать рекламу на странице, но я обычно прошу рекламодателя предоставить изображение, которое соответствует точным размерам в пикселях, чтобы актив соответствовал пространству.
Но демонстрация Криса решает проблему пространства. Наведите курсор на изображение и наблюдайте, как оно перемещается и масштабируется. Пользователь на самом деле получает больше контекста для продукта, чем если бы изображение было в исходном положении. Это беспроигрышный вариант, верно? Рекламодатель может создать привлекательное изображение без ущерба для контекста. Между тем, пользователь получает дополнительную ценность от вновь открываемых частей изображения.
Если вы посмотрите на разметку демо, вы заметите, что это в значительной степени то, что вы ожидаете. Вот сокращенная версия:
Мы, вероятно, могли бы немного поспорить о семантике, но это не главное. У нас есть контейнер со связанным <div> для фонового изображения и еще один <div> для хранения контента.
Что касается стиля, важные элементы здесь:
Неплохо, правда? Мы задаем контейнеру некоторые размеры и устанавливаем на него фоновое изображение, которое не повторяется и располагается у нижнего левого края.
Настоящий трюк с JavaScript. Мы будем использовать это, чтобы получить положение мыши и смещение контейнера, а затем преобразовать это значение в соответствующий масштаб, чтобы установить background-position. Во-первых, давайте послушаем движения мыши над элементом .container:
Отсюда мы можем использовать свойства offsetX и offsetY контейнера. Но мы не будем использовать эти значения напрямую, так как значение для координаты X меньше, чем нужно, а координата Y больше. Нам придется немного поиграть, чтобы найти константу, которую мы можем использовать в качестве множителя.
Это немного на ощупь, но я обнаружил, что 1,32 и 0,455 идеально подходят для координат X и Y соответственно. Мы умножаем смещения на эти значения, добавляем к результату единицу пикселей, а затем применяем ее к значениям background-position.
Наконец, мы также можем сбросить фоновые позиции обратно к исходным, если пользователь покидает контейнер изображения.
Рисуем большую картину
Без сомнения, вы были в каком-то интернет-магазине одежды или где-то еще и сталкивались со старой функцией увеличения при наведении.
Этот паттерн существует уже целую вечность (Дилан Уинн-Браун поделился своим подходом еще в 2016 году), но это всего лишь свидетельство (надеюсь) его полезности. Пользователь получает больше контекста, когда увеличивает масштаб и получает лучшее представление о вышивке свитера или о том, что у вас есть.
В этом есть две части: контейнер и лупа. Контейнер — это единственное, что нам нужно в разметке, так как мы будем внедрять элемент лупы во время взаимодействия с пользователем. Итак, вот наш HTML!
<div class="container"></div>
В CSS мы создадим переменные width и height для хранения размеров самой лупы. Затем мы придадим этому .container форму и фоновое изображение:
Есть некоторые вещи, которые мы уже знаем о лупе еще до того, как увидим ее, и мы можем определить эти стили заранее, в частности, ранее определенные переменные для width и height .maginifier:
Это абсолютно позиционированный маленький квадрат, который использует тот же файл фонового изображения, что и .container. Обратите внимание, что функция calc используется здесь исключительно для преобразования безразмерного значения переменной в пиксели. Не стесняйтесь организовывать это так, как считаете нужным, чтобы исключить повторения в вашем коде.
Теперь давайте обратимся к JavaScript, который объединяет все это. Сначала нам нужно получить доступ к переменной CSS, определенной ранее. Мы будем использовать это в нескольких местах позже. Затем нам нужно получить положение мыши в контейнере, потому что это значение, которое мы будем использовать для фонового положения лупы.
То, что нам нужно, это в основном прослушиватель событий mousemove в .container. Затем мы будем использовать свойство event.pageX или event.pageY, чтобы получить координату X или Y мыши. Но чтобы получить точное относительное положение мыши на элементе, нам нужно вычесть положение родительского элемента из положения мыши, которое мы получаем из JavaScript выше. «Простым» способом сделать это является использование метода getBoundingClientRect(), который возвращает размер элемента и его положение относительно окна просмотра.
Сначала мы создадим div лупы. Далее мы создадим функцию mousemove и добавим ее в контейнер изображения. В этой функции мы присвоим лупе атрибут класса. Мы также рассчитаем положение мыши и дадим лупе значения слева и сверху, которые мы рассчитали ранее.
Давайте продолжим и создадим лупу, когда услышим событие mousemove в .container:
Теперь нам нужно убедиться, что у него есть имя класса, которое мы можем применить к CSS:
Лупа располагается снаружи контейнера. Мы собираемся сделать это простым и накладывать его поверх контейнера вместо того, чтобы перемещать мышь. Мы будем использовать операторы if для установки положения лупы только в том случае, если значения X и Y больше или равны нулю и меньше ширины или высоты контейнера. Это должно держать его в рамках. Просто не забудьте вычесть ширину и высоту лупы из значений X и Y.
И последнее, но не менее важное… нам нужно немного поиграть с фоновым изображением лупы. Все дело в том, что пользователь получает БОЛЬШОЕ представление о фоновом изображении в зависимости от того, где происходит наведение. Итак, давайте определим лупу, которую мы можем использовать для увеличения масштаба. Затем мы определим переменные для ширины и высоты фонового изображения, чтобы у нас было что-то, на чем можно основывать этот масштаб, и установим все эти значения в стилях .magnifier:
Давайте возьмем координаты X и Y изображения лупы и применим их к background-position элемента .magnifier. Как и раньше с положением лупы, нам нужно вычесть ширину и высоту лупы из значений X и Y, используя переменные CSS.
Ссылка на демонстрацию.
Сделайте это кинематографичным
Вы видели эффект Кена Бернса? Это классическая и вечная вещь, когда изображение больше, чем контейнер, в котором оно находится, а затем как бы скользит и масштабируется медленно, как слизняк. Кажется, что почти каждый документальный фильм в мире использует его для неподвижных изображений. Если у вас есть Apple TV, то вы наверняка видели его на заставке.
На CodePen есть множество примеров, если вы хотите получить представление получше.
Вы увидите, что есть несколько способов приблизить изображение. Некоторые используют JavaScript. Другие на 100% CSS. Я уверен, что подходы JavaScript хороши для некоторых случаев использования, но если цель состоит в том, чтобы просто тонко масштабировать изображение, CSS идеально подходит.
Мы могли бы немного оживить ситуацию, используя несколько фонов, а не один. Или, что еще лучше, если мы расширим правила, чтобы использовать элементы вместо фоновых изображений, мы можем применить одну и ту же анимацию ко всем фонам и использовать animation-delay, чтобы улучшить эффект.
Смотреть пример на CodePen.
Конечно, есть много способов сделать это! Он, безусловно, может быть оптимизирован с помощью переменных Sass и / или CSS. Черт возьми, может быть, вы сможете сделать это с помощью одного <div>, если да, поделитесь этим в комментариях!
Бонус: Сделаем это захватывающим
Я не знаю, есть ли что-нибудь круче, чем pen Сары Драснер “Happy Halloween” ... и это из 2016 года! Это отличный пример того, как накладывается фон и перемещается с разной скоростью, создавая почти кинематографическое впечатление. Боже мой, как это круто!
GSAP является основным драйвером, но я полагаю, что мы могли бы создать сокращенную версию, которая просто переводит каждый фоновый слой слева направо с разной скоростью. Не так круто, конечно, но, безусловно, базовый опыт. Необходимо убедиться, что начало и конец каждого фонового изображения совпадают, чтобы оно плавно повторялось при повторении анимации.
На этом пока все! Довольно изящно, что мы можем использовать фон не только для текстуры и контраста. Я абсолютно уверен, что есть масса других умных взаимодействий, которые мы можем применить к фоновым изображениям.
Перевод статьи "Moving Backgrounds".