Эффект перехода под растекание чернил на основе CSS-анимации.
Недавно я наткнулся на пару веб-сайтов, использующих растекание чернил как эффекты перехода. Прекрасным примером является веб-сайт Sevenhills. Сначала я подумал, что они используют технику на основе холста HTML (для обеспечения прозрачности), затем я проверил исходный код и обнаружил, что они использовали не видео, а спрайт изображения PNG.
Используя спрайт PNG и функцию времени steps ()
в CSS, мы можем создавать видеоэффекты и использовать их в качестве переходов! В нашем ресурсе мы использовали эту технику для запуска модального окна, но вы также можете использовать его для перехода между двумя разными страницами.
Процесс создания этих эффектов прост, позвольте мне рассказать вам об этом:
Во-первых, вам понадобится видео с эффектом заливки и прозрачной областью. Затем вам нужно экспортировать это видео как последовательность PNG. Мы использовали After Effects для экспорта эпизода (не забудьте также экспортировать альфа-канал).
Поскольку наше видео состоит из 25 кадров, экспортированные ресурсы представляют собой 25 изображений PNG. Чтобы дать вам больше информации о настройках композиции, мы создали видео размером 640x360 пикселей, длительностью 1 секунду и частотой кадров 25.
Наконец, утомительная часть: вам нужно создать спрайт PNG, создав новое изображение, включающее все кадры в одной строке. Мы сделали это вручную с помощью Photoshop и объединили все кадры в одно изображение размером 16000x360 пикселей.
Чтобы превратить последовательность в видео, нам просто нужно перевести спрайт PNG и использовать функцию steps ()
для определения количества кадров.
Теперь перейдем к коду!
Создание структуры
Структура HTML состоит из трех основных элементов:
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
изначально имеет: 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 как фоновое изображение, размер фона: 100%, высоту: 100% и ширину: 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%;
/* our sprite is composed of 25 frames */
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
в 25 раз больше ширины его родительского слоя, мы используем translateX (- (50/25)%)
.
Чтобы создать анимацию рукописного ввода, мы изменяем значение translate
слоя div.bg;
мы определили правило ключевых кадров 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 ()
: это потому, что мы не хотим, чтобы значение translate
изменялось непрерывно, а скорее изменялось через фиксированные шаги, чтобы показывать по одному кадру за раз; количество используемых шагов равно нашим кадрам за вычетом одного.
Обработка событий
Мы использовали jQuery для добавления / удаления классов, когда пользователь щелкает a.cd-modal-trigger
или .modal-close
, чтобы открыть / закрыть модальное окно.
Кроме того, мы меняем размеры .bg-layer
, чтобы не изменять соотношение сторон png-фреймов. В файле style.css мы устанавливаем высоту и ширину .bg-layer
так, чтобы каждый фрейм имел высоту и ширину, равные высоте и ширине области просмотра. Видовой экран и кадры могут иметь другое соотношение сторон, что может исказить отдельный кадр. Чтобы этого не произошло, использовалась функция setLayerDimensions ()
:
var frameProportion = 1.78, //png frame aspect ratio
frames = 25, //number of png frames
resize = false;
//set transitionBackground dimentions
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;
}
Надеюсь, вам понравилось!