Эффект расплывающихся чернил на CSS и jQuery

Недавно я наткнулся на несколько веб-сайтов на которых присутствовали эффекты с чернилами в качестве перехода. Сначала я подумал, что для их работы они используют HTML canvas (для обеспечения прозрачности), но затем я проверил исходный код и выяснил, что они не используют обычное видео.

Сложность

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

Процесс создания такого эффекта очень прост:

Для начала, вам понадобиться видео с эффектом заливки и прозрачной областью. Далее, экспортируйте это видео в формате "PNG sequence" (PNG последовательность). Я использовал After Effects для экспорта последовательности (убедитесь что также экспортируете альфа-канал).

after effects эффект чернил

Так как наше видео состоит из 25 кадров, соответственно у нас получилось 25 PNG изображений. Мы создали видео размером 640x360px длительностью в 1 секунду и частотой кадров, равной 25.

after effects создание проекта

Теперь самая утомительная часть: вам нужно создать PNG спрайт, в котором будут находиться все кадры в одной строке. Мы сделали это вручную при помощи Photoshop, объединили все кадры в одно изображение размером 16000×360px.

png спрайт эффекта чернил

Для того, чтобы сделать из последовательности - "видео", нам нужно просто перевести PNG спрайт, а также использовать функцию steps(), чтобы определить количество кадров.

Настало время перейти к коду!

Создание структуры

HTML структура состоит из 3 основных элементов: main.cd-main-content для основного контента страницы, div.cd-modal для модального окна и div.cd-transition-layer для слоя с переходом.

<main class="cd-main-content">
	<div class="center">
		<h1>Ink Transition Effect</h1>
		<a href="#0" class="cd-btn cd-modal-trigger">Start Effect</a>
	</div>
</main> <!-- .cd-main-content -->
 
<div class="cd-modal">
	<div class="modal-content">
		<h1>My Modal Content</h1>
		
		<p>
			Lorem ipsum dolor sit amet, consectetur adipisicing elit. 
			Ad modi repellendus, optio eveniet eligendi molestiae? 
			Fugiat, temporibus! 
		</p>
	</div> <!-- .modal-content -->
 
	<a href="#0" class="modal-close">Close</a>
</div> <!-- .cd-modal -->
 
<div class="cd-transition-layer"> 
	<div class="bg-layer"></div>
</div> <!-- .cd-transition-layer -->

Добавление стилей

Окно .cd-modal имеет свойства initially, visibility: hidden, height: 100% и width: 100% и фиксированную позицию.
Когда пользователь нажимает на a.cd-modal-trigger, значение видимости меняется на visible и прозрачность становится 1 (используя класс .visible).

.cd-modal {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 3;
  height: 100%;
  width: 100%;
  opacity: 0;
  visibility: hidden;
}
.cd-modal.visible {
  opacity: 1;
  visibility: visible;
}

Элемент div.cd-transition-layer используется для создания эффекта перехода чернил: он имеет свойства visibility: hidden, height: 100% и width: 100% и фиксированную позицию.

.cd-transition-layer {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 2;
  height: 100%;
  width: 100%;
  opacity: 0;
  visibility: hidden;
  overflow: hidden;
}

Дочерний элемент div.bg-layer содержит ссылку на спрайтовое изображение ink.png и устанавливает его в качестве фона, а также имеет свойства background-size: 100%, height: 100% и width: 2500% (спрайт ink.png состоит из 25 кадров); значения left/top/translate устанавливаются таким образом, чтобы на начальном этапе, первый кадр спрайта ink.png находился внутри div.cd-transition-layer:

.cd-transition-layer .bg-layer {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translateY(-50%) translateX(-2%);
  height: 100%;
  width: 2500%;
  background: url(../img/ink.png) no-repeat 0 0;
  background-size: 100% 100%;
}

Для центрирования элемента внутри родителя, используем:

position: absolute;
left: 50%;
top: 50%;
transform: translateY(-50%) translateX(-50%);

В нашем случае, нам нужно центрировать первый кадр спрайта ink.png, а так как ширина div.bg-layer в 25 раз больше его родительского элемента, мы используем translateX(-(50/25)%).

Для создания анимации чернил, мы меняем значение перехода div.bg-layer; мы определили правило ключевых кадров cd-sequence:

@keyframes cd-sequence {
  0% {
    transform: translateY(-50%) translateX(-2%);
  }
  100% {
    transform: translateY(-50%) translateX(-98%);
  }
}

Таким образом, в конце анимации последний кадр спрайта ink.png центрируется внутри элемента div.cd-transition-layer.

Так как у нас есть 25 кадров, чтобы показать последний кадр, вам нужно перевести .bg-layer на -100% * (25 – 1) = -96%; а затем центрировать его внутри своего родительского элемента (убрать -2%).

Когда пользователь нажимает на a.cd-modal-trigger, класс .visible добавляется к .cd-transition-layer для его отображения, класс .opening служит для анимации чернил.

.cd-transition-layer.visible {
  opacity: 1;
  visibility: visible;
}
.cd-transition-layer.opening .bg-layer {
  animation: cd-sprite 0.8s steps(24);
  animation-fill-mode: forwards;
}

Обратите внимание, что мы использовали функцию steps(): так как мы не хотим, чтобы значение перехода непрерывно изменялось, поэтому мы будем менять его через фиксированные шаги, чтобы показать один кадр за один раз.

Обработка событий

Мы используем jQuery для добавления/удаления класса при нажатии на a.cd-modal-trigger и .modal-close для открытия/закрытия модального окна.

Кроме того, мы меняем размеры .bg-layer, для того, чтобы изменить пропорции PNG кадров. В файле style.css, мы установили высоту и ширину .bg-layer таким образом, чтобы каждый кадр имел высоту и ширину, равную области просмотра. Viewport и кадры могут иметь различное соотношение сторон.

var frameProportion = 1.78, //соотношение png кадров
	frames = 25, //количество png кадров
	resize = false;
 
//установка параметров transitionBackground
setLayerDimensions();
$(window).on('resize', function(){
	if( !resize ) {
		resize = true;
		(!window.requestAnimationFrame) ? setTimeout(setLayerDimensions, 300) : window.requestAnimationFrame(setLayerDimensions);
	}
});
 
function setLayerDimensions() {
	var windowWidth = $(window).width(),
		windowHeight = $(window).height(),
		layerHeight, layerWidth;
 
	if( windowWidth/windowHeight > frameProportion ) {
		layerWidth = windowWidth;
		layerHeight = layerWidth/frameProportion;
	} else {
		layerHeight = windowHeight;
		layerWidth = layerHeight*frameProportion;
	}
 
	transitionBackground.css({
		'width': layerWidth*frames+'px',
		'height': layerHeight+'px',
	});
 
	resize = false;
}
ДЕМО СКАЧАТЬ

 

Перевод статьи Ink Transition Effect

Тэги: transitionanimate

Вход

Уважаемый пользователь! Мы обнаружили, что вы используете AdBlock и вынуждены скрыть часть материалов на нашем сайте. Siteacademy существует и развивается за счет доходов от рекламы. Просим внести наш сайт в список исключений или отключить Блокировщик рекламы на нашем сайте.