Как создать плавно изменяющуюся кнопку Play-Pause для HTML5 видео с помощью SVG

Как создать плавно изменяющуюся кнопку Play-Pause для HTML5 видео с помощью SVG

От автора: если внимательно присмотреться к плееру YouTube, можно заметить, что кнопка play не просто переключается на иконку паузы по клику, а плавно и быстро перетекает между двумя состояниями. Сделать это можно с помощью SVG под управлением JavaScript. Сегодня я покажу мою интерпретацию данного UI шаблона.

Создаем целевые состояния для плавного перехода

Основное условие выполнения плавного перехода из одного состояния в другое в SVG – количество вершин в обоих состояниях должно совпадать. Также в SVG нельзя разбить замкнутый элемент и превратить его в два. То есть в случае с кнопкой play в SVG нам придется прятать некоторые вершины состояния паузы (8 или более вершин) в самой кнопке (для которой нужно всего 3 вершины). Также это значит, что кнопка play должна будет состоять из двух отдельных частей, но выглядеть как одно целое.

Я создал треугольник в Adobe Illustrator на листе размером 50 х 50 пикселей. Привязав треугольник к слою, поверх него я создал два отдельных элемента, повторяющих его форму.

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

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50" id="playpause" xmlns:xlink="http://www.w3.org/1999/xlink">
    <title>Play</title>
    <polygon points="12,0 25,11.5 25,39 12,50" id="leftbar" />
    <polygon points="25,11.5 39.7,24.5 41.5,26 39.7,27.4 25,39" id="rightbar" />
</svg>

Каждый polygon нужно анимировать в новое состояние. Перетащив существующие точки и превратив иконку в два вертикальных прямоугольника, результат можно экспортировать и добавить в предыдущий SVG в качестве значений тегов animate. SVG теперь стал таким:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50" id="playpause" xmlns:xlink="http://www.w3.org/1999/xlink">
    <title>Play</title>
    <polygon points="12,0 25,11.5 25,39 12,50" id="leftbar" />
    <polygon points="25,11.5 39.7,24.5 41.5,26 39.7,27.4 25,39" id="rightbar" />
        <animate to="7,3 19,3 19,47 7,47" id="lefttopause" xlink:href="#leftbar" 
attributeName="points" dur=".3s" begin="indefinite" fill="freeze" />
        <animate to="31,3 43,3 43,26 43,47 31,47" id="righttopause" xlink:href="#rightbar" 
attributeName="points" dur=".3s" begin="indefinite" fill="freeze" />
</svg>

В предыдущей статье по SVG морфизму я вас уже познакомил с двумя новыми атрибутами из этого кода. Атрибут begin=»indefinite» запрещает моментальный старт анимации (для теста можете просто удалить этот атрибут). Атрибут fill=»freeze» – то же самое, что animation-direction: forward в CSS (анимация проигрывается один раз и застывает в конечном состоянии). Также теги animate я расположил после полигонов, а не внутри них, а ссылки на анимируемые элементы задал с помощью xlink:href.

После перехода SVG в состояние паузы необходимо вернуть его обратно в режим play. К сожалению, в SVG нет простой инверсии движений, нам придется создать второе целевое состояние:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50" id="playpause" xmlns:xlink="http://www.w3.org/1999/xlink">
    <title>Play</title>
    <polygon points="12,0 25,11.5 25,39 12,50" id="leftbar" />
    <polygon points="25,11.5 39.7,24.5 41.5,26 39.7,27.4 25,39" id="rightbar" />
        <animate to="7,3 19,3 19,47 7,47" id="lefttopause" xlink:href="#leftbar" 
attributeName="points" dur=".3s" begin="indefinite" fill="freeze" />
        <animate to="12,0 25,11.5 25,39 12,50" id="lefttoplay" xlink:href="#leftbar" 
attributeName="points" dur=".3s" begin="indefinite" fill="freeze" />
        <animate to="31,3 43,3 43,26 43,47 31,47" id="righttopause" xlink:href="#rightbar" 
attributeName="points" dur=".3s" begin="indefinite" fill="freeze" />
        <animate to="25,11.5 39.7,24.5 41.5,26 39.7,27.4 25,39" id="righttoplay" 
xlink:href="#rightbar" attributeName="points" dur=".3s" begin="indefinite" fill="freeze" />
</svg>

Каждой анимации я присвоил свой ID (id: lefttopause и lefttoplay).

Расставляем все на места

Для упрощенного доступа SVG помещен в тег button:

<div id="atlanticlight">
    <video controls>
        <source src="atlantic-light.webm">
        <source src="atlantic-light.mp4">
    </video>
    <button>
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50" id="playpause" xmlns:xlink="http://www.w3.org/1999/xlink">
            <title>Play</title>
            <polygon points="12,0 25,11.5 25,39 12,50" id="leftbar" />
            <polygon points="25,11.5 39.7,24.5 41.5,26 39.7,27.4 25,39" id="rightbar" />
                <animate to="7,3 19,3 19,47 7,47" id="lefttopause" xlink:href="#leftbar" 
attributeName="points" dur=".3s" begin="indefinite" fill="freeze" />
                <animate to="12,0 25,11.5 25,39 12,50" id="lefttoplay" xlink:href="#leftbar" 
attributeName="points" dur=".3s" begin="indefinite" fill="freeze" />
                <animate to="31,3 43,3 43,26 43,47 31,47" id="righttopause" xlink:href="#rightbar" 
attributeName="points" dur=".3s" begin="indefinite" fill="freeze" />
                <animate to="25,11.5 39.7,24.5 41.5,26 39.7,27.4 25,39" id="righttoplay" 
xlink:href="#rightbar" attributeName="points" dur=".3s" begin="indefinite" fill="freeze" />
        </svg>
    </button>
</div>

Настройки включают в себя сокрытие SVG по умолчанию. Появляться кнопка будет при помощи JS:

* { box-sizing: border-box; }
#atlanticlight { 
    position: relative;
    font-size: 0; width: 100%; 
}
#atlanticlight, #atlanticlight video, #atlanticlight button { 
    width: 100%; height: auto;
}
#atlanticlight button svg { 
    width: 50%; margin: 0 auto;
    fill: #fff; padding: 3rem;
    transition: .6s opacity;
}
#atlanticlight video, #atlanticlight button { 
    position: absolute; top: 0; 
}
#atlanticlight button { 
    background: transparent; 
    outline: none; border: none;
    cursor: pointer;
}
#playpause { display: none; }
.playing { opacity: 0; }

Свойство transition на теге svg, примененное через класс, заставит кнопку плавно появляться и исчезать. Добавлять и удалять класс мы будем через classList.

Приводим все в движение

Чтобы кнопка play/pause заработала, необходимо определить элементы, с которыми мы будем работать:

var atlanticlight = document.querySelector("#atlanticlight video"),
playpause = document.getElementById("playpause"),
lefttoplay = document.getElementById("lefttoplay"),
righttoplay = document.getElementById("righttoplay"),
lefttopause = document.getElementById("lefttopause"),
righttopause = document.getElementById("righttopause");

Применяя технику прогрессивного улучшения, мы удаляем стандартные кнопки из видео и показываем наш собственный UI:

mountain.removeAttribute("controls");
vidcontrols.style.display = "block";

Теперь необходимо ловить событие клика на кнопку button. Мы не будем отслеживать состояние элемента, мы будем смотреть на состояние видео:

atlanticlight.removeAttribute("controls");
playpause.style.display = "block";
playpause.addEventListener(’click’,function(){
    if (atlanticlight.paused) {
        atlanticlight.play();
        playpause.classList.add("playing");
        lefttopause.beginElement();
        righttopause.beginElement();
    } else { 
        atlanticlight.pause();
        lefttoplay.beginElement();
        righttoplay.beginElement();
        playpause.classList.remove("playing");
    }
},false);

Будущие наработки

Если открыть консоль в Chrome и запустить пример выше, вы получите следующее сообщение: «SVG SMIL анимация (animate, set и т.д.) устарела и будет удалена. Пожалуйста, воспользуйтесь CSS или веб-анимацией.»

К счастью или нет, это правда: в скором времени Chrome полностью откажется от SMIL (язык на основе SVG, который мы до сих пор использовали для анимации) в угоду Web Animations API. К сожалению, в новой спецификации пока что ничего не сказано про морфизм, что ставит этот код в затруднительное положение на довольно долгий промежуток времени. Наш код будет в подвешенном состоянии, пока не будет разработана отдельная JS библиотека, или пока Web Animations API не расширится. На этот переходной период мы можем использовать библиотеку анимации Greensock в качестве фолбэка, более подробно о ней я расскажу в следующей статье.

Источник: http://thenewcode.com/

Редакция: Команда webformyself.

Практика HTML5 и CSS3 с нуля до результата!

Получите бесплатный пошаговый видеокурс по основам адаптивной верстки с полного нуля на HTML5 и CSS3

Получить

Метки:

Комментарии Вконтакте:

Комментарии Facebook:

Добавить комментарий

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

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

Я не робот.

Spam Protection by WP-SpamFree