- PVSM.RU - https://www.pvsm.ru -

Интересные трюки HTML, CSS и JS

Интересные трюки HTML, CSS и JS - 1


Здесь вы найдёте небольшую подборку нестандартных вариантов использования HTML/CSS/JS. Если информация окажется полезной, будем собирать эти хаки на постоянной основе и публиковать по мере накопления.

Примечание. Некоторые трюки основаны на открытых уязвимостях браузеров и поисковой системы Google и др. Поэтому могут перестать работать в ближайшее время (или продолжат, если разработчики не признают баги и не захотят их исправлять). Другие функции работают только начиная с конкретных версий Chrome, Firefox и т. д.

▍ Отслеживание поведения пользователей на сайтах конкурентов

Маркетолог и SEO-оптимизатор Дэн Петрович нашёл способ [1], как отслеживать действия пользователей на сайтах конкурентов, включая полную информацию о просмотрах страниц, переходах по ссылкам, времени просмотра, видеозаписях сессий и нажатиях клавиш. Можно собирать всю информацию, которая вводится в веб-формы на чужом сайте, и получать её к себе по электронной почте. Всё это делается с помощью подделки чужого сайта и заманивания юзеров на это зеркало. Способ не совсем этичный, поэтому публикуем информацию исключительно в образовательных целях.

Алгоритм:

  1. Пользователь заходит на нашу страницу из поиска (referrer: google).

    Интересные трюки HTML, CSS и JS - 2

  2. Наша веб-страница перехватывает нажатие кнопки «Назад» в Chrome и подсовывает пользователю нашу копию поисковой выдачи Google.

    Интересные трюки HTML, CSS и JS - 3

    Интересные трюки HTML, CSS и JS - 4

  3. Переход по любой ссылке на сайт конкурента ведёт на наше зеркало сайта конкурента.

    Интересные трюки HTML, CSS и JS - 5

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

Примечание 1. Альтернативный способ заведения пользователей на зеркало чужого сайта — через поисковую рекламу. На самом деле в интернете полно фейковых копий (зеркал) аутентичных сайтов, в том числе Хабра, куда заходят тысячи пользователей из поиска, не подозревая о подделке.

Примечание 2. Несколько лет назад похожий способ использовался для перехвата звонков через публикацию фейковых объявлений на Google Maps со своим телефонным номером вместо оригинальных номеров ФБР и Секретной службы США.

Интересные трюки HTML, CSS и JS - 6

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

▍ Редактируемые страницы HTML

Нажатие кнопки DesignMode ON/OFF делает веб-страницу редактируемой [2]. Нужна всего одна строчка JavaScript в коде:

document.designMode = "on";

Это древние API появились 25 лет назад, но до сих пор поддерживаются в браузерах.

▍ Грамотное использование <picture>

В последние годы во многих браузерах появилась поддержка современных форматов сжатия изображений AVIF и WebP (к сожалению, 10 декабря 2022 года Google удалила [3] поддержку JPEG XL из Chromium, так что этот формат теперь не слишком актуален). Можно сократить трафик со своего сайта, если включить эту оптимизацию [4] с помощью тега <picture>.

Идея в том, чтобы выдавать AVIF и WebP только тем браузерам, которые это поддерживают.

  1. Конвертируем изображения в другой формат. Например, с помощью кроссплатформенной утилиты imagemagick [5] или сервиса avif.io [6].
    $ magick convert image.jpg image.avif

    Аналогичную конвертацию производим для каждой пары форматов (jpg/avif, jpg/webp).

  2. Вместо традиционного <img>, прописываем тег <picture>, который допускает перечисление нескольких URL для одной картинки. Первым указываем AVIF как самый маленький формат. Нормальные браузеры загрузят его, а Edge и все остальные, которые не поддерживают AVIF [7], пойдут дальше по списку: WebP и JPEG.
    <picture>
    <source srcset="/document.avif" type="image/avif">
    <source srcset="/document.webp" type="image/webp">
    <img src="/document.jpeg" alt="Скриншот" width="375" height="153" class="border">
    </picture>

    Все варианты указываем в теге <source>, и только последний в теге <img>.

  3. Известная оптимизация для более быстрой загрузки страниц — настроить HTTP/2 Server Push [8] на сервере, чтобы ресурсы загружались сразу, не дожидаясь их запроса после парсинга HTML. В нашем случае для элементов <picture> не оптимально грузить клиенту всё подряд. Лучше распознать браузерный юзер-агент и заранее пушить картинку соответствующего формата. Специально для этого предназначено поле Accept в user-agent. Например, последний Firefox высылает Accept такого вида:

    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,/;q=0.8

▍ Хранение состояния приложения в URL

Если у вас есть какое-то веб-приложение и вы хотите дать возможность людям работать в нём без авторизации на сайте и хранения данных на сервере, то для этого есть интересный хак: сохранять состояние в URL [9], в браузере клиента.

Это даёт возможность пользователю «сохраниться», а позже продолжить работу (редактирование данных). Также удобно делиться результатами работы с коллегами просто путём отправки URL.

Состояние приложения — файл JSON, он кодируется в строку, потом сжимается и переводится в байты Base64, которые добавляются в URL после символов `/g/a#`. Например, таким образом:

наш_сайт.com/g/a#N4IgzgpgTglghgGxgLwnARgiAxA9lAWxAC5QA7X...

Псевдокод для реализации такой функциональности:

const stateString = JSON.stringify(appState); // appState представляет собой объект JSON
const compressed = compress(stateString);
const encoded = Base64.encode(compressed);
// Пушим закодированную строку в url
// ...Позже при загрузке страницы или undo/redo читаем url и
// делаем следующее
const decoded = Base64.decode(encoded); // в той же кодировке, что и выше, но считывается из url
const uncompressed = uncompress(decoded);
const newState = JSON.parse(uncompressed);
// Загружаем приложение с новым состоянием newState

URL обновляется после каждого изменения состояния приложения, так что скопировать текущее состояние можно простым копипастом из адресной строки браузера. Примеры, как это работает: интерактивные редакторы блок-схем knotend [10] и mermaid.live [11]:

Интересные трюки HTML, CSS и JS - 7

Есть несколько вариантов, как реализовать функции сжатия/декомпрессии, например, lz-stirng [12] или pako [13].

В качестве бонуса мы получаем для своего веб-приложения «бесплатную» функциональность undo/redo из браузерного стека, а также автоматическое внедрение на любую стороннюю веб-страницу, которая поддерживает embed'ы.

Можно ещё посмотреть, как Yahoo! Finance хранит настройки пользователя в URL:

finance.yahoo.com

https://finance.yahoo.com/quote/F/chart?p=F#eyJpbnRlcnZhbCI6IndlZWsiLCJwZXJpb2RpY2l0eSI6MSwidGltZVVuaXQiOm51bGwsImNhbmRsZVdpZHRoIjo0LjM0ODY1OTAwMzgzMTQxNzUsImZsaXBwZWQiOmZhbHNlLCJ2b2x1bWVVbmRlcmxheSI6dHJ1ZSwiYWRqIjp0cnVlLCJjcm9zc2hhaXIiOnRydWUsImNoYXJ0VHlwZSI6ImxpbmUiLCJleHRlbmRlZCI6ZmFsc2UsIm1hcmtldFNlc3Npb25zIjp7fSwiYWdncmVnYXRpb25UeXBlIjoib2hsYyIsImNoYXJ0U2NhbGUiOiJsaW5lYXIiLCJzdHVkaWVzIjp7IuKAjHZvbCB1bmRy4oCMIjp7InR5cGUiOiJ2b2wgdW5kciIsImlucHV0cyI6eyJpZCI6IuKAjHZvbCB1bmRy4oCMIiwiZGlzcGxheSI6IuKAjHZvbCB1bmRy4oCMIn0sIm91dHB1dHMiOnsiVXAgVm9sdW1lIjoiIzAwYjA2MSIsIkRvd24gVm9sdW1lIjoiI2ZmMzMzYSJ9LCJwYW5lbCI6ImNoYXJ0IiwicGFyYW1ldGVycyI6eyJ3aWR0aEZhY3RvciI6MC40NSwiY2hhcnROYW1lIjoiY2hhcnQifX19LCJwYW5lbHMiOnsiY2hhcnQiOnsicGVyY2VudCI6MSwiZGlzcGxheSI6IkYiLCJjaGFydE5hbWUiOiJjaGFydCIsImluZGV4IjowLCJ5QXhpcyI6eyJuYW1lIjoiY2hhcnQiLCJwb3NpdGlvbiI6bnVsbH0sInlheGlzTEhTIjpbXSwieWF4aXNSSFMiOlsiY2hhcnQiLCLigIx2b2wgdW5kcuKAjCJdfX0sInNldFNwYW4iOnsibXVsdGlwbGllciI6NSwiYmFzZSI6InllYXIiLCJwZXJpb2RpY2l0eSI6eyJwZXJpb2QiOjEsImludGVydmFsIjoid2VlayJ9fSwibGluZVdpZHRoIjoyLCJzdHJpcGVkQmFja2dyb3VuZCI6dHJ1ZSwiZXZlbnRzIjp0cnVlLCJjb2xvciI6IiMwMDgxZjIiLCJzdHJpcGVkQmFja2dyb3VkIjp0cnVlLCJldmVudE1hcCI6eyJjb3Jwb3JhdGUiOnsiZGl2cyI6dHJ1ZSwic3BsaXRzIjp0cnVlfSwic2lnRGV2Ijp7fX0sImN1c3RvbVJhbmdlIjpudWxsLCJzeW1ib2xzIjpbeyJzeW1ib2wiOiJGIiwic3ltYm9sT2JqZWN0Ijp7InN5bWJvbCI6IkYiLCJxdW90ZVR5cGUiOiJFUVVJVFkiLCJleGNoYW5nZVRpbWVab25lIjoiQW1lcmljYS9OZXdfWW9yayJ9LCJwZXJpb2RpY2l0eSI6MSwiaW50ZXJ2YWwiOiJ3ZWVrIiwidGltZVVuaXQiOm51bGwsInNldFNwYW4iOnsibXVsdGlwbGllciI6NSwiYmFzZSI6InllYXIiLCJwZXJpb2RpY2l0eSI6eyJwZXJpb2QiOjEsImludGVydmFsIjoid2VlayJ9fX1dfQ--

Строка в декодированном виде

{"interval":"week","periodicity":1,"timeUnit":null,"candleWidth":4.3486590038314175,"flipped":false,"volumeUnderlay":true,"adj":true,"crosshair":true,"chartType":"line","extended":false,"marketSessions":{},"aggregationType":"ohlc","chartScale":"linear","studies":{" vol undr ":{"type":"vol undr","inputs":{"id":" vol undr ","display":" vol undr "},"outputs":{"Up Volume":"#00b061","Down Volume":"#ff333a"},"panel":"chart","parameters":{"widthFactor":0.45,"chartName":"chart"}}},"panels":{"chart":{"percent":1,"display":"F","chartName":"chart","index":0,"yAxis":{"name":"chart","position":null},"yaxisLHS":[],"yaxisRHS":["chart"," vol undr "]}},"setSpan":{"multiplier":5,"base":"year","periodicity":{"period":1,"interval":"week"}},"lineWidth":2,"stripedBackground":true,"events":true,"color":"#0081f2","stripedBackgroud":true,"eventMap":{"corporate":{"divs":true,"splits":true},"sigDev":{}},"customRange":null,"symbols":[{"symbol":"F","symbolObject":{"symbol":"F","quoteType":"EQUITY","exchangeTimeZone":"America/New_York"},"periodicity":1,"interval":"week","timeUnit":null,"setSpan":{"multiplier":5,"base":"year","periodicity":{"period":1,"interval":"week"}}}]}

Наверное, тут много лишней информации, но сам подход понятен.

Примечание. Поскольку браузеры могут обрезать слишком длинные URL, для данных целей надёжнее использовать стандарт URI-фрагментов [14] (строка после знака #). Как говорится, всё новое — это хорошо забытое старое. Криптохостинг Mega.co.nz реализовал этот метод для передачи ключа расшифровки [15] ровно десять лет назад.

▍ Браузерные API сообщают владельцу сайта о падениях на его странице

Пару лет назад Chrome реализовал интересный набор интерфейсов Reporting API [16], о котором до сих пор знают не все разработчики.

Интересные трюки HTML, CSS и JS - 8

Через эти API браузер следит за пользователями вашего сайта и присылает отчёты по падениям/ошибкам с их стороны, просто отправляя JSON по указанному URL.

Правда, в данный момент в Chrome две несовместимые версии API [17], так что нужно разбираться, какую из версий лучше использовать.

Благодаря этим API можно найти нестандартные ошибки на своих страницах. Например, частые падения мобильных браузеров из-за CSS-анимаций [18]. Оказывается, стандартные CSS-анимации непосильны для старых смартфонов — браузер вылетает из-за недостатка RAM.

▍ Тригонометрические функции CSS

Если речь зашла о CSS, то пару месяцев назад все ведущие браузеры добавили поддержку тригонометрических функций [19].

Многие знают, что в свойствах объектов CSS можно использовать математические выражения [20]: от вычислений calc() до логических функций min(), max() и clamp().

А начиная с версии Chrome 111, Firefox 108 и Safari 15.4 появилась ещё поддержка тригонометрических функций sin(), cos(), tan(), asin(), acos(), atan() и atan2(). Все они описаны в спецификациях CSS Values and Units Module Level 4 [21].

Например, вот код [22] для вращения точки по кругу вокруг центральной точки:

:root {
  --radius: 20vmin;
}

.dot {
  --angle: 30deg;
  translate: /* Translation on X-axis */
             calc(cos(var(--angle)) * var(--radius))

             /* Translation on Y-axis */
             calc(sin(var(--angle)) * var(--radius) * -1)
  ;
}

Демо [22]:

Автор: Анатолий Ализар

Источник [23]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/javascript/384454

Ссылки в тексте:

[1] нашёл способ: https://dejanmarketing.com/competitor-hack/

[2] делает веб-страницу редактируемой: https://jfhr.me/document.designmode/

[3] удалила: https://chromium-review.googlesource.com/c/chromium/src/+/4081749

[4] включить эту оптимизацию: https://jfhr.me/optimizing-images-with-the-html-picture-tag/

[5] imagemagick: https://imagemagick.org/index.php

[6] avif.io: https://avif.io/

[7] Edge и все остальные, которые не поддерживают AVIF: https://caniuse.com/?search=avif

[8] HTTP/2 Server Push: https://en.wikipedia.org/wiki/HTTP/2_Server_Push

[9] сохранять состояние в URL: https://www.scottantipa.com/store-app-state-in-urls

[10] knotend: https://www.knotend.com/

[11] mermaid.live: https://mermaid.live/

[12] lz-stirng: https://github.com/pieroxy/lz-string

[13] pako: https://github.com/nodeca/pako

[14] URI-фрагментов: https://en.wikipedia.org/wiki/URI_fragment

[15] передачи ключа расшифровки: https://help.mega.io/security/data-protection/zero-knowledge-encryption

[16] Reporting API: https://developer.chrome.com/articles/reporting-api/

[17] две несовместимые версии API: https://developer.chrome.com/blog/reporting-api-migration/

[18] частые падения мобильных браузеров из-за CSS-анимаций: https://neugierig.org/software/blog/2023/01/browser-crashes.html

[19] тригонометрических функций: https://web.dev/css-trig-functions/

[20] математические выражения: https://web.dev/learn/css/functions/#mathematical-expressions

[21] CSS Values and Units Module Level 4: https://www.w3.org/TR/css-values-4/#trig-funcs

[22] вот код: https://codepen.io/web-dot-dev/pen/ExePgOg

[23] Источник: https://habr.com/ru/companies/ruvds/articles/731960/?utm_source=habrahabr&utm_medium=rss&utm_campaign=731960