Маски CSS для переходов

CSS

онлайн предварительный просмотр Скачать исходный код

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

Примечание. Имейте в виду, что этот эффект все еще является экспериментальным и поддерживается только современными браузерами (Chrome, Safari и Opera).

CSS Masks

Способ маскирования части элемента выделенным изображением

Рекомендация кандидата W3C

Поддерживаются следующие версии:

настольное приложение

мобильное приложение

допустимыйcaniuse.comСм. подробную поддержку на

Имейте в виду, что Firefox имеет только частичную поддержку (он поддерживает только встроенные элементы маски SVG), поэтому у нас будет запасной вариант. Надеемся, что вскоре CSS-маски будут поддерживаться всеми современными браузерами. Обратите внимание, что мы добавляем Modernizr для проверки поддержки.

Начнем счастливо вместе!

Создайте изображение маски

В этом уроке мы рассмотрим первый пример (Демонстрация 1).

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

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

Для создания карты спрайтов мы будем использовать этовидео. Мы импортировали его в Adobe After Effects, чтобы сократить время видео, удалили белые части и экспортировали в виде последовательности PNG.

Чтобы уменьшить продолжительность до 1,4 секунды (время, которое мы хотим преобразовать), мы будем использовать эффект растяжения времени (Time stretch effect).

Чтобы удалить белую часть, мы будем использовать Keying -> Extract и установим точку белого на 0. На снимке экрана ниже синяя часть — это фон нашего композита, прозрачная часть видео.

Наконец, нас можно сохранить как синтезированную видеопоследовательность PNG, а затем использовать Photoshop илиCSS spriteСоздайте одно изображение:

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

Теперь, когда мы создали изображение маски, давайте просто реализуем HTML-структуру примера карусели.

HTML-структура

Мы создадим простую карусель, чтобы показать эффект маскировки. Наша карусель заполнит экран, и мы добавим несколько стрелок, которые заставят карусель переключаться. Идея состоит в том, чтобы переопределить карусель, а затем изменить z-индекс карусели в конце анимации. Структура карусели следующая:

<div class="page-view">
	<div class="project">
		<div class="text">
			<h1>“All good things are <br> wild & free”</h1>
			<p>Photo by Andreas Rønningen</p>
		</div>
	</div>
	<div class="project">
		<div class="text">
			<h1>“Into the wild”</h1>
			<p>Photo by John Price</p>
		</div>
	</div>
	<div class="project">
		<div class="text">
			<h1>“Is spring coming?”</h1>
			<p>Photo by Thomas Lefebvre</p>
		</div>
	</div>
	<div class="project">
		<div class="text">
			<h1>“Stay curious”</h1>
			<p>Photo by Maria</p>
		</div>
	</div>
	<nav class="arrows">
		<div class="arrow previous">
			<svg viewBox="208.3 352 4.2 6.4">
				<polygon class="st0" points="212.1,357.3 211.5,358 208.7,355.1 211.5,352.3 212.1,353 209.9,355.1"/>
			</svg>
		</div>
		<div class="arrow next">
			<svg viewBox="208.3 352 4.2 6.4">
				<polygon class="st0" points="212.1,357.3 211.5,358 208.7,355.1 211.5,352.3 212.1,353 209.9,355.1"/>
			</svg>
		</div>
	</nav>
</div>

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

Стрелка будет действовать как триггер для следующей или предыдущей анимации и перемещаться по карусели.

Давайте посмотрим на этот стиль.

CSS-стили

В этом разделе мы добавим CSS к нашему эффекту.

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

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

.demo-1 {
	background: url(../img/nature-sprite.png) no-repeat -9999px -9999px;
	background-size: 0;
}

.demo-1 .page-view {
	background: url(../img/nature-sprite-2.png) no-repeat -9999px -9999px;
	background-size: 0;
}

Каждая страница карусели имеет свое фоновое изображение:

.demo-1 .page-view .project:nth-child(1) {
	background-image: url(../img/nature-1.jpg);
}

.demo-1 .page-view .project:nth-child(2) {
	background-image: url(../img/nature-2.jpg);
}

.demo-1 .page-view .project:nth-child(3) {
	background-image: url(../img/nature-3.jpg);
}

.demo-1 .page-view .project:nth-child(4) {
	background-image: url(../img/nature-4.jpg);
}

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

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

Зная, что кадр составляет 100% экрана, а наша анимация содержит 23 изображения, нам нужно установить ширину 23 * 100% = 2300%.

Теперь мы добавляем анимацию CSS с помощью шагов. Мы хотим, чтобы наш спрайт останавливался в начале последнего кадра. Итак, для этого нам нужно на один шаг меньше, чем всего, что составляет 22 шага:

.demo-1 .page-view .project:nth-child(even).hide {
	-webkit-mask: url(../img/nature-sprite.png);
	mask: url(../img/nature-sprite.png);
	-webkit-mask-size: 2300% 100%;
	mask-size: 2300% 100%;
	-webkit-animation: mask-play 1.4s steps(22) forwards;
	animation: mask-play 1.4s steps(22) forwards;
}

.demo-1 .page-view .project:nth-child(odd).hide {
	-webkit-mask: url(../img/nature-sprite-2.png);
	mask: url(../img/nature-sprite-2.png);
	-webkit-mask-size: 7100% 100%;
	mask-size: 7100% 100%;
	-webkit-animation: mask-play 1.4s steps(70) forwards;
	animation: mask-play 1.4s steps(70) forwards;
}

Наконец, мы определяем ключевые кадры анимации:

@-webkit-keyframes mask-play {
  from {
	-webkit-mask-position: 0% 0;
	mask-position: 0% 0;
  }
  to {
	-webkit-mask-position: 100% 0;
	mask-position: 100% 0;
  }
}

@keyframes mask-play {
  from {
	-webkit-mask-position: 0% 0;
	mask-position: 0% 0;
  }
  to {
	-webkit-mask-position: 100% 0;
	mask-position: 100% 0;
  }
}

Теперь у нас есть структура и стиль карусели. Давайте добавим немного движения!

Производительность JavaScript

мы будем использоватьzepto.jsДля этой демонстрации это очень легкая среда JavaScript, похожая на jQuery.

Сначала объявите все переменные, установите продолжительность и элементы.

Затем мы инициализируем событие, получаем текущую и следующую карусели и устанавливаем правильный z-индекс.

function Slider() {
	// Durations
	this.durations = {
		auto: 5000,
		slide: 1400
	};
	// DOM
	this.dom = {
		wrapper: null,
		container: null,
		project: null,
		current: null,
		next: null,
		arrow: null
	};
	// Misc stuff
	this.length = 0;
	this.current = 0;
	this.next = 0;
	this.isAuto = true;
	this.working = false;
	this.dom.wrapper = $('.page-view');
	this.dom.project = this.dom.wrapper.find('.project');
	this.dom.arrow = this.dom.wrapper.find('.arrow');
	this.length = this.dom.project.length;
	this.init();
	this.events();
	this.auto = setInterval(this.updateNext.bind(this), this.durations.auto);
}
/**
 * Set initial z-indexes & get current project
 */
Slider.prototype.init = function () {
	this.dom.project.css('z-index', 10);
	this.dom.current = $(this.dom.project[this.current]);
	this.dom.next = $(this.dom.project[this.current + 1]);
	this.dom.current.css('z-index', 30);
	this.dom.next.css('z-index', 20);
};

Мы слушаем события щелчка по стрелке, и если текущая карусель не задействована в анимации, мы проверяем, был ли щелчок на следующей или предыдущей стрелке. Мы переключаем карусель, регулируя значение «следующей» переменной.

/**
 * Initialize events
 */
Slider.prototype.events = function () {
	var self = this;
	this.dom.arrow.on('click', function () {
		if (self.working)
			return;
		self.processBtn($(this));
	});
};
Slider.prototype.processBtn = function (btn) {
	if (this.isAuto) {
		this.isAuto = false;
		clearInterval(this.auto);
	}
	if (btn.hasClass('next'))
		this.updateNext();
	if (btn.hasClass('previous'))
		this.updatePrevious();
};
/**
 * Update next global index
 */
Slider.prototype.updateNext = function () {
	this.next = (this.current + 1) % this.length;
	this.process();
};
/**
 * Update next global index
 */
Slider.prototype.updatePrevious = function () {
	this.next--;
	if (this.next < 0)
		this.next = this.length - 1;
	this.process();
};

Эта функция является ядром нашей карусельной проекции: мы добавляем класс «hide» в текущую карусель, и когда анимация закончится, мы уменьшаем z-индекс предыдущей карусели и увеличиваем в текущей карусели, затем удаляем класс, скрывающий предыдущую карусель.

/**
 * Process, calculate and switch between slides
 */
Slider.prototype.process = function () {
	var self = this;
	this.working = true;
	this.dom.next = $(this.dom.project[this.next]);
	this.dom.current.css('z-index', 30);
	self.dom.next.css('z-index', 20);
	// Hide current
	this.dom.current.addClass('hide');
	setTimeout(function () {
		self.dom.current.css('z-index', 10);
		self.dom.next.css('z-index', 30);
		self.dom.current.removeClass('hide');
		self.dom.current = self.dom.next;
		self.current = self.next;
		self.working = false;
	}, this.durations.slide);
};

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

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