Анимация ссылок в строке браузера с помощью JavaScript и эмодзи Материал редакции

Перевод материала программиста Мэтью Райфилда.

В закладки
Полное видео — по ссылке

Эмодзи (как и другие символы Юникода) можно использовать в ссылках, но по какой-то причине этого никто не делает. Почему? Сайтам стыдно использовать такие эксцентричные вещи? Или их избегают из страха прогневить богов поисковой оптимизации?

Как бы там ни было, на диаграмме Венна в месте пересечения кругов «Это возможно» и «Никто этого не делает» находится мой энтузиазм. Поэтому я решил исследовать возможности графического оформления ссылок с помощью JavaScript.

Зацикливание

Прежде всего необходимо убедиться, что вы используете стандарт кодирования Юникода UTF-8, иначе эмодзи в коде разместить без труда не удастся. Проверить это можно через заголовок HTTP или тег МЕТА. Скорее всего, у вас всё будет в порядке, но вы можете подробнее изучить этот вопрос.

Чтобы достичь желаемого результата — красующихся на ссылке эмодзи, — нам нужно их зациклить. И в общем-то, всё. Мы создаём цикл, запускаем код и радуемся. Итак, вот наш первый цикл — эмодзи луны с рожицей. Не просто так же создатели эту рожицу придумали?

var f = ['🌑', '🌒', '🌓', '🌔', '🌝', '🌖', '🌗', '🌘']; function loop() { location.hash = f[Math.floor((Date.now()/100)%f.length)]; setTimeout(loop, 50); } loop();

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

Например, часы
var f = ['🕐','🕑','🕒','🕓','🕔','🕕','🕖','🕗','🕘','🕙','🕚','🕛'];

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

var e = ['🏻', '🏼', '🏽', '🏾', '🏿']; function loop() { var s = '', i, m; for (i = 0; i < 10; i ++) { m = Math.floor(e.length * ((Math.sin((Date.now()/100) + i)+1)/2)); s += '👶' + e[m]; } location.hash = s; setTimeout(loop, 50); } loop();

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

Давайте ещё раз взглянем на нашу луну и создадим некое подобие полосы загрузки.

var f = ['🌑', '🌘', '🌗', '🌖', '🌕', '🌔', '🌓', '🌒'], d = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], m = 0; function loop() { var s = '', x = 0; if (!m) { while (d[x] == 4) { x ++; } if (x >= d.length) m = 1; else { d[x] ++; } } else { while (d[x] == 0) { x ++; } if (x >= d.length) m = 0; else { d[x] ++; if (d[x] == 8) d[x] = 0; } } d.forEach(function (n) { s += f[n]; }); location.hash = s; setTimeout(loop, 50); } loop();

Использование прочих символов

Для анимации адресной строки необязательно использовать только эмодзи. Среди множества символов Юникода можно найти те, что подойдут для ваших целей.

Особый интерес представляют псевдографические символы:

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

function loop() { var i, n, s = ''; for (i = 0; i < 10; i++) { n = Math.floor(Math.sin((Date.now()/200) + (i/2)) * 4) + 4; s += String.fromCharCode(0x2581 + n); } window.location.hash = s; setTimeout(loop, 50); } loop();

Она мне так понравилась, что я увековечил её на сайте wavyurl.com.

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

function loop() { var s = '', p; p = Math.floor(((Math.sin(Date.now()/300)+1)/2) * 100); while (p >= 8) { s += '█'; p -= 8; } s += ['⠀','▏','▎','▍','▌','▋','▊','▉'][p]; location.hash = s; setTimeout(loop, 50); }

Индикатор выполнения — это уже практически полезная функция. Что и привело меня к следующему разделу.

Отображение времени видео в адресной строке

В попытке уменьшить бесполезность нашего маленького эксперимента мне в голову пришла идея отобразить прогресс просмотра видео в адресной строке.

Я просто добавил функцию, которая привязывает созданную мной последовательность символов к функции обновления таймера видео! В адресной строке появляется индикатор прогресса просмотра вместе с продолжительностью.

var video; function formatTime(seconds) { var minutes = Math.floor(seconds/60), seconds = Math.floor(seconds - (minutes*60)); return ('0'+minutes).substr(-2) + ':' + ('0'+seconds).substr(-2); } function renderProgressBar() { var s = '', l = 15, p = Math.floor(video.currentTime / video.duration * (l-1)), i; for (i = 0; i < l; i ++) { if (i == p) s +='◯'; else if (i < p) s += '─'; else s += '┄'; } location.hash = '╭'+s+'╮'+formatTime(video.currentTime)+'╱'+formatTime(video.duration); } video = document.getElementById('video'); video.addEventListener('timeupdate', renderProgressBar);

Мне больше нравятся полоса и кружок, но их можно заменить на уже знакомые нам луны.

var e = ['🌑', '🌘', '🌗', '🌖', '🌕'], video; function formatTime(seconds) { var minutes = Math.floor(seconds/60), seconds = Math.floor(seconds - (minutes*60)); return ('0'+minutes).substr(-2) + ':' + ('0'+seconds).substr(-2); } function renderProgressBar() { var s = '', c = 0, l = 10, p = Math.floor(video.currentTime / video.duration * ((l*5)-1)), i; while (p >= 5) { s += e[4]; c ++; p -= 5; } s += e[p]; c ++; while (c < l) { s += e[0]; c ++; } location.hash = s+formatTime(video.currentTime)+'╱'+formatTime(video.duration); } video = document.getElementById('video'); video.addEventListener('timeupdate', renderProgressBar);

Ладно, возможно, этот указатель прогресса просмотра не так уж и полезен. Но я могу представить сценарий, в котором его можно использовать. Например, на YouTube есть функция привязки ссылки на видео к конкретному времени в видео. Было бы здорово иметь ещё и визуальное отображение на ссылке, нет?

Наверняка есть и более полезное применение этой «технологии», до которого я не додумался. Быть может, у вас получится?

И ещё кое-что

Возможно, вас интересует, почему я использовал «location.hash =» вместо более нового и удобного HTML5 History API. Две проблемы: одна решаемая, вторая не очень. Обе вызывают трудности.

Первая проблема заключается в функции History API: она изменяет весь путь URL-адреса, а не только решётку. Поэтому при использовании History API и изменении адреса на «/🌑🌘🌗🌖🌕», он выглядит лучше, чем вместе с решёткой.

Но тогда я должен быть уверен в том, что сервер сможет ответить на «/🌑🌘🌗🌖🌕», иначе пользователь не сможет нормально обновить страницу или управлять изменённой ссылкой. Это сделать сложнее, чем просто использовать «location.hash =», который не требует никаких особых условий сервера.

Вторая проблема оказалась непредвиденной. Когда я проводил тесты, то в двух из трёх браузеров регулировалось количество запросов на History API. При быстром вводе символов для волны в адресной строке Chrome выдавал мне следующую ошибку:

Throttling history state changes to prevent the browser from hanging.

Safari даёт чуть больше информации:

SecurityError: Attempt to use history.pushState() more than 100 times per 30.000000 seconds

Если не превышать этот лимит, то всё в порядке. Но трёх кадров в секунду недостаточно для моих классных анимаций.

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

Всё?

Пока да. Но у меня есть идеи для нескольких игр в адресной строке. И мы ещё даже не начали изучать Брайлевские символы.

Исходники, уродующие адресные строки в формате HTML, есть на моём сайте.

{ "author_name": "Алина Окунева", "author_type": "self", "tags": ["\u044d\u043c\u043e\u0434\u0437\u0438","\u0431\u0440\u0430\u0443\u0437\u0435\u0440\u044b","html"], "comments": 37, "likes": 54, "favorites": 84, "is_advertisement": false, "subsite_label": "dev", "id": 81775, "is_wide": true, "is_ugc": true, "date": "Thu, 05 Sep 2019 17:03:04 +0300", "is_special": false }
0
{ "id": 81775, "author_id": 258318, "diff_limit": 1000, "urls": {"diff":"\/comments\/81775\/get","add":"\/comments\/81775\/add","edit":"\/comments\/edit","remove":"\/admin\/comments\/remove","pin":"\/admin\/comments\/pin","get4edit":"\/comments\/get4edit","complain":"\/comments\/complain","load_more":"\/comments\/loading\/81775"}, "attach_limit": 2, "max_comment_text_length": 5000, "subsite_id": 235819, "last_count_and_date": null }
37 комментариев
Популярные
По порядку
Написать комментарий...
18

Как способ показать что это возможно - прикольно. Но надеюсь никто не додумается делать такое.

Ответить
8

Снежинки на новый год до сих пор делают.

Ответить
0

Я вот надеюсь, что никто из HR которые это увидят не догадается задать это на собеседовании.

Ответить
0

Взял на заметку😊

Ответить
0

Так же надеюсь , что такого не будет, но уверен что разработчики браузеров быстро прикроют эту фичу

Ответить
7

Миллениалы изобрели кастомный javascript в браузере?

Ответить
4

Ящик пандоры открыт

Ответить
3

Юзлесс если у вас spa на хешевом роутинге ну и на мобайле в целом. Вообще все это дрочево по поводу анимированного тайтла (аля Одноклассники) или анимированных фавиконок — полный колхоз.

Статья интересна только в ключе использования 1 апишки браузера. Очень не хочу увидеть что либо подобное на сайтах которые я посещаю.

Ответить
3

Вот такие урлы!

Ответить
0

Надеюсь без регистрации и смс?

Ответить
3

Ура! Снова 2003-й! Осталось изобрести анимированные аватарки.

Ответить
3

Жаль floppy disk из моды вышел. Можно было музычку наложить, чтобы флопик подзуживал в такт анимашки)

Ответить
2

Настолько тупо, что гениально

Ответить
–8

С каких пор фронтендщики стали программистами?

Ответить
–8

Фронтенд в IT это как гуманитарии. Люди, далёкие от программирования. Из дело дизайн и вёрстка. Иногда связь с бэкендом, в котором они ничего не понимают

Ответить
3

Не холивара ради, а интереса для - а кто такой "программист" по вашему?
Скажем, я сделал кривое апи для прекрасно написанного SPA - я программист? Если нет, то что нужно сделать, чтобы получить этот статус?

Ответить
–1

Ты программист, да. Но твой уровень надо проверить на конкретных задачах .

Ответить
2

Фронт уже отжал больше половины логики, вот и бесишься. Ваше дело на бэке только принеси/подай.

Ответить
1

Вот и встретились, один думает, что бэк это принеси/подай, другой что фронтендеры не программисты

Ответить
0

Не я это дерьмо начал, не мне и заканчивать.

Ответить
–2

Ты даже понятия не имеешь что такое бэкенд

Ответить
2

Судя по вашему пренебрежению вы до сих пор пишете на перфокартах? Часто всплывает ненависть к фронтендерам и я не понимаю откуда берется желание, обесценивая чью-то работу, приблизить к элитарности свою профессию. Рынок порешал и им платят много из-за востребованности, да и без фронтендеров апишечки не будут нужны.

Ответить
–1

Рост популярности BaaS решений не даёт им спокойно спать.

Ответить
–1

Так ты же ошибаешься

Ответить
–2

Вроде прикольно, но я жду когда JS умрёт. Вот это по-настоящему киллер фича будет.

Ответить
2

Ок, можешь привыкать к этому заранее закрыв этот сайт

Ответить
0

вам в бекенд надо - там кривые языки если не умирают (perl), то выходят из моды (php, java)

Ответить
0

он твоих внуков переживет )

Ответить
1

Вашьі анимации засоряют history браузера. Пользовательне сможет нажать кнопку 'Назад' в браузере.

Ответить
0

Сможет, кто ж ему помешает. Так можно прогресс назад отмотать.

Ответить
0

Есть такая штука как location.replace/history.replaceState. Так что нет, не засоряют

Ответить
1

Вот так с помощью нехитрых приспособлений...

Ответить
–6

О, статья от недопрогораммиста родом из 2000-х или 90-х, что одно и то же.
"Прежде всего необходимо убедиться, что вы используете стандарт кодирования Юникода UTF-8, иначе эмодзи в коде разместить без труда не удастся. "

Это самое начало и именно в этом проблема.
Не у всех эта кодировка стоит.
Чувак не понимает фундаментальных вещей в программировании. Но ему простительно, он не программист, а фронтендщик

Ответить
0

Если у меня браузер будет что-то подобное показывать-заблокирую жава скрипт нафиг

Ответить
0

И открываться будут только сайты из 2005 года

Ответить
{ "page_type": "article" }

Прямой эфир

[ { "id": 1, "label": "100%×150_Branding_desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox_method": "createAdaptive", "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "ezfl" } } }, { "id": 2, "label": "1200х400", "provider": "adfox", "adaptive": [ "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "ezfn" } } }, { "id": 3, "label": "240х200 _ТГБ_desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fizc" } } }, { "id": 4, "label": "Article Branding", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "p1": "cfovx", "p2": "glug" } } }, { "id": 5, "label": "300x500_desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "ezfk" } } }, { "id": 6, "label": "1180х250_Interpool_баннер над комментариями_Desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "pp": "h", "ps": "bugf", "p2": "ffyh" } } }, { "id": 7, "label": "Article Footer 100%_desktop_mobile", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fjxb" } } }, { "id": 8, "label": "Fullscreen Desktop", "provider": "adfox", "adaptive": [ "desktop", "tablet" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fjoh" } } }, { "id": 9, "label": "Fullscreen Mobile", "provider": "adfox", "adaptive": [ "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fjog" } } }, { "id": 10, "disable": true, "label": "Native Partner Desktop", "provider": "adfox", "adaptive": [ "desktop", "tablet" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fmyb" } } }, { "id": 11, "disable": true, "label": "Native Partner Mobile", "provider": "adfox", "adaptive": [ "phone" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fmyc" } } }, { "id": 12, "label": "Кнопка в шапке", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "p1": "bscsh", "p2": "fdhx" } } }, { "id": 13, "label": "DM InPage Video PartnerCode", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "adfox_method": "createAdaptive", "adfox": { "ownerId": 228129, "params": { "pp": "h", "ps": "bugf", "p2": "flvn" } } }, { "id": 14, "label": "Yandex context video banner", "provider": "yandex", "yandex": { "block_id": "VI-223676-0", "render_to": "inpage_VI-223676-0-1104503429", "adfox_url": "//ads.adfox.ru/228129/getCode?pp=h&ps=bugf&p2=fpjw&puid1=&puid2=&puid3=&puid4=&puid8=&puid9=&puid10=&puid21=&puid22=&puid31=&puid32=&puid33=&fmt=1&dl={REFERER}&pr=" } }, { "id": 15, "label": "Баннер в ленте на главной", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "adfox": { "ownerId": 228129, "params": { "p1": "byudx", "p2": "ftjf" } } }, { "id": 16, "label": "Кнопка в шапке мобайл", "provider": "adfox", "adaptive": [ "tablet", "phone" ], "adfox": { "ownerId": 228129, "params": { "p1": "byzqf", "p2": "ftwx" } } }, { "id": 17, "label": "Stratum Desktop", "provider": "adfox", "adaptive": [ "desktop" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fzvb" } } }, { "id": 18, "label": "Stratum Mobile", "provider": "adfox", "adaptive": [ "tablet", "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "bugf", "p2": "fzvc" } } }, { "id": 19, "disable": true, "label": "Тизер на главной", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "p1": "cbltd", "p2": "gazs" } } } ] { "page_type": "default" }