IT-инфраструктура для бизнеса и творчества

Анимация ссылок в строке браузера с помощью 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, есть на моём сайте.

(function () { let cdnUrl = `https://specialsf378ef5-a.akamaihd.net/SelectelBranding/images/` let previousArticleNumber = null let currentArticleNumber = 0 let platform = 'Desktop' let articles = [ { name: 'camera', url: `${cdnUrl}CameraCat`, text: 'умную камеру для\u00A0наблюдения за\u00A0котиками', link: 'https://vc.ru/selectel/306690', num: 3 }, { name: 'chill', url: `${cdnUrl}ChillCat`, text: 'трекер, который подскажет, когда пора отдохнуть', link: 'https://vc.ru/promo/288561-eye-tracker', num: 1 }, { name: 'cloud', url: `${cdnUrl}CloudCat`, text: 'котика: даёшь ему «пять», а\u00A0он делает бэкап в облако', link: 'https://vc.ru/dev/294799-maneki-neko', num: 2 } ] let buttonCycle = document.querySelector('.button--cycle') let buttonChoose = document.querySelector('.button--choose') let buttonMobile = document.querySelector('.button--mobile') let textField = document.querySelector('.selectel-footer-subtitle') let imageAgent = document.querySelector('.image--agent') let banner = document.querySelector('.selectel-footer') buttonCycle.addEventListener('click', cycleClick) buttonChoose.addEventListener('click', () => sendEvent(`Promo ${articles[currentArticleNumber].num} Left`, 'Click')) buttonMobile.addEventListener('click', () => sendEvent(`Promo ${articles[currentArticleNumber].num} Left`, 'Click')) let media = window.matchMedia("(max-width: 570px)") media.addEventListener('change', matchMedia) function matchMedia() { if (media.matches) { platform = 'Mobile' } else { platform = 'Desktop' } update() } matchMedia() function cycleClick(event) { sendEvent(`Promo ${articles[currentArticleNumber].num} Right`, 'Click') if (event) { event.preventDefault() event.stopPropagation() } window.open('https://vc.ru/tag/selectelDIY', '_blank') //cycle(event) } function cycle(event) { // incrementArticleNumber() textField.innerHTML = generatedText() imageAgent.src = articles[currentArticleNumber].url + platform + '.svg?3' imageAgent.setAttribute("class", "") imageAgent.classList.add('image--agent', articles[currentArticleNumber].name) banner.href = articles[currentArticleNumber].link } function update() { banner.href = articles[currentArticleNumber].link imageAgent.src = articles[currentArticleNumber].url + platform + '.svg' textField.innerHTML = generatedText() } function incrementArticleNumber() { previousArticleNumber = currentArticleNumber if (currentArticleNumber >= articles.length - 1) { currentArticleNumber = 0 } else { currentArticleNumber++ } } const sendEvent = (label, action = 'Click') => { const value = `SelectelDIY — loc: Footer — ${label} — ${action}`; if (window.dataLayer !== undefined) { window.dataLayer.push({ event: 'data_event', data_description: value, }); } }; function generatedText() { let defaultText if (platform === 'Desktop') { defaultText = `Мы тут собрали %text%. Хотите научим?` } else { defaultText = `Мы тут собрали %text%.` } return defaultText.replace('%text%', articles[currentArticleNumber].text) } function getRandom(min, max) { min = Math.ceil(min) max = Math.floor(max) return Math.floor(Math.random() * (max - min + 1)) + min } (function create() { currentArticleNumber = getRandom(0, articles.length - 1) cycle() let page = document.querySelector('.page--entry') if (page) { function insertAfter() { let parents = page.querySelectorAll('[data-id="7"]') let referenceNode = parents[0] referenceNode.parentNode.insertBefore(banner, referenceNode.nextSibling); loaded() } setTimeout(() => insertAfter(), 0) } }()) function loaded() { banner.classList.add('loaded') } loadImages([ `${cdnUrl}CameraCatDesktop.svg`, `${cdnUrl}ChillCatDesktop.svg`, `${cdnUrl}CloudCatDesktop.svg`, `${cdnUrl}CameraCatMobile.svg`, `${cdnUrl}ChillCatMobile.svg`, `${cdnUrl}CloudCatMobile.svg?3`, ]) function loadImages(urls) { return Promise.all(urls.map(function (url) { return new Promise(function (resolve) { var img = document.createElement('img'); img.onload = resolve; img.onerror = resolve; img.src = url; }); })); } }())
0
40 комментариев
Популярные
По порядку
Написать комментарий...

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

21

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

9

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

0

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

1

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

0

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

7

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

4

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

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

3

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

3

Enlarge your url!

1

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

0

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

3

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

3

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

2

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

2

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

–10

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

–10

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

3

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

1

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

0

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

–3

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

3

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

–1

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

2

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

–1

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

–1

Комментарий удален по просьбе пользователя

–3

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

3

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

0

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

0

Это самый прекрасный язык. Ты просто знаешь его по мемасам или никогда не изучал.

0

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

1

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

0

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

0

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

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

–8

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

0

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

0

Добавил правило в блокировщик рекламы.

0

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

0
Читать все 40 комментариев
VELES BLOG Рассказываем как себя вести, чтобы заработать с Veles
Китайский стартап по производству сельскохозяйственных роботов FJDynamics привлёк $70 млн Статьи редакции

Компания хочет упростить ручную работу в строительстве и садоводстве.

Использование YOLOv5 для задачи детекции

Ликбез по нейронным сетям

Модемы, роутеры и интернет-центры Yota можно приобрести на Avito, OZON и «СберМегамаркет»
Закрылся майнинг-пул из ТОП-10. Что теперь делают майнеры

Недавние ограничения китайских властей сильно ударили по майнинг-пулам. С рынка ушел один из крупнейших игроков – Huobi Pool. Это пул майнеров, входящий в десятку крупнейших майнинг-пулов по объему добычи криптовалют. Прямо сейчас ряд компаний и объединений, входящих ранее в пул, пытаются спасти средства клиентов и переходят в другие майнинговые…

Дата-центр Minto, Республика Карелия, РФ, 2021
Как я стал резидентом ОЭЗ «Технополис Москва» — опыт компании «ХайТэк»

Опытом работы на территории особой экономической зоны столицы делится генеральный директор НТЦ «ХайТэк» Алексей Алясев.

Пресс-служба ОЭЗ «Технополис Москва».
Как «Л'Этуаль» игнорит покупателей

Цель данного поста – привлечь внимание представителей интернет-магазина «Л'Этуаль» к проблеме, которая не решается уже 5 дней. Если, конечно, они сюда заглядывают. А заодно предостеречь других людей, которые свяжутся с сервисом этой многоуважаемой компании в Москве.

За год с 4 до 16 млн выручки в месяц. Как без денег построить свою сеть из доставок роллов?
null