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

Интересные трюки HTML. Экстремальный минимализм

Интересные трюки HTML. Экстремальный минимализм - 1


Мы уже много говорили про оптимизацию сайтов до минимального размера, преимущества статичного HTML, а также упаковку сайта (и веб-сервера) в портативный формат одного исполняемого файла [1], который нативно исполняется под любой ОС.

Но стремление к минимизации может пойти дальше, если вы хотите поместить весь сайт в адресную строку браузера. А с помощью сокращателя ссылок даже большой сайт сжимается до восьми байт. В этом случае и хостинг [2] не нужен (то есть роль хостинга [2] выполняет сервис сокращения ссылок).

▍ Сайт в URL

Вот концептуальный пример:

https://smolsite.zip/UEsDBAoAAAAAAEZkYVdE9j5DPAAAADwAAAAKAAAAaW5kZXguaHRtbDwhRE9DVFlQRSBIVE1MPjx0aXRsZT7S5fHyPC90aXRsZT48cD7P8Oji5fIg9+jy4PLl6//sINXg4fDgIVBLAQIfAAoAAAAAAEZkYVdE9j5DPAAAADwAAAAKACQAAAAAAAAAIAAAAAAAAABpbmRleC5odG1sCgAgAAAAAAABABgAd3HKkqYM2gF3ccqSpgzaAfnEyWumDNoBUEsFBgAAAAABAAEAXAAAAGQAAAAAAA==

Это делается очень просто: создаём статичный HTML-сайт из index.html и других файлов, архивируем всё в ZIP и кодируем в Base64:

$ zip -DXjq9 somesite.zip index.html mylogo.png
$ echo "https://smolsite.zip/`cat somesite.zip | base64 --wrap 0`"

И всё, потом полученный ZIP можно вставлять в адресную строку после https://smolsite.zip/ — и сайт откроется в браузере (на КДПВ). Согласно FAQ [3], сервер разархивирует его содержимое и хранит в памяти 15 минут, хотя теоретически извлечение контента из архива может сделать и сам браузер [4], так что нынешнее серверное решение не вполне оптимально.

Этот сайт можно ещё сильнее сжать с помощью сокращателя ссылок: https://tinyurl.com/4a7huvj2 [5]. В этом случае мы используем сервис сокращения ссылок в качестве бесплатного веб-хостинга.

Smolsite.zip [3] — это часть проекта LWAN [6] по созданию инфраструктуры для максимального производительного, эффективного и легковесного веб-сервера.

Точно также в качестве бесплатного веб-хостинга можно использовать QR-коды, распечатанные на бумаге. Такие сайты откроются в браузере даже в отсутствие интернета. Полностью офлайновый хостинг [2].

Такие же URL можно составлять по схеме Data URI [7], например:

data:text/html,<h1>My%20small%20website</h1><p>Look,%20it's%20real!</p>

Вставьте это в адресную строку — и у вас откроется «сайт». Можно использовать его как ">блокнотик для записей, если у вас нет отдельного notepad'а (например, на хромбуке).

Это чем-то напоминает сервис NoPaste [8], который тоже превращает произвольный текст в URL вроде такого [9]. Аналогичные проекты itty.bitty.site [10] и goog.space [11].

▍ Как восстановить текст из браузера

Если браузер по какой-то причине обновил страницу и текст в окне потерялся, можно воспользоваться этим советом [12]: сделать дам памяти Firefox и поискать потерянный текст там. Инструкция работает для любых текстовых форм, в том числе для самодельных браузерных «блокнотиков» из предыдущего раздела.

Есть ещё расширение Textarea Cache (Chrome [13] и Firefox [14]), которое сохраняет в кэше текстовые данные из форм.

▍ NoJS и NoCSS

На Хабре упоминали [15] клуб 1kB [16] для сайтов размером меньше 1 КБ. Кроме него, есть и другие содружества минималистов: например, No JS [17] для сайтов, которые не используют JavaScript, а также No CSS [18].

Наверное, такими темпами стоит ожидать в будущем появления клуба No HTML [19] с веб-страницами в чистом тексте, без необязательных тегов, только необходимый минимум. На самом деле в HTML много опциональных тегов [20], которые необязательно использовать. Согласно официальной спецификации, тег <html> не является обязательным. Его можно удалить и в начале, и в конце документа.

Кроме того, во многих случаях можно безболезненно опустить теги <head> и <body> (в начале и в конце), а также закрывающие теги <li>, <dt>, <dd>, <p>, <rt>, <rp>, <optgroup>, <option>, <colgroup> (в начале и конце), <caption>, <thead>, <tbody> (в начале и конце), <tfoot>, <tr>, <td> и <th> (только внимательно прочитайте условия, при которых теги можно игнорировать). Это информация из официальной документации WHATWG по ссылке выше.

Например, такая таблица:

<table>
 <caption>37547 TEE Electric Powered Rail Car Train Functions (Abbreviated)</caption>
 <colgroup><col><col><col></colgroup>
 <thead>
  <tr>
   <th>Function</th>
   <th>Control Unit</th>
   <th>Central Station</th>
  </tr>
 </thead>
 <tbody>
  <tr>
   <td>Headlights</td>
   <td>✔</td>
   <td>✔</td>
  </tr>
  <tr>
   <td>Interior Lights</td>
   <td>✔</td>
   <td>✔</td>
  </tr>
  <tr>
   <td>Electric locomotive operating sounds</td>
   <td>✔</td>
   <td>✔</td>
  </tr>
  <tr>
   <td>Engineer's cab lighting</td>
   <td></td>
   <td>✔</td>
  </tr>
  <tr>
   <td>Station Announcements - Swiss</td>
   <td></td>
   <td>✔</td>
  </tr>
 </tbody>
</table>

И её полный аналог после удаления необязательных тегов:

<table>
 <caption>37547 TEE Electric Powered Rail Car Train Functions (Abbreviated)
 <colgroup><col><col><col>
 <thead>
  <tr> <th>Function                              <th>Control Unit     <th>Central Station
 <tbody>
  <tr> <td>Headlights                            <td>✔                <td>✔
  <tr> <td>Interior Lights                       <td>✔                <td>✔
  <tr> <td>Electric locomotive operating sounds  <td>✔                <td>✔
  <tr> <td>Engineer's cab lighting               <td>                 <td>✔
  <tr> <td>Station Announcements - Swiss         <td>                 <td>✔
</table>

Или взять стандартный шаблон документа:

<!DOCTYPE HTML>
<html>
  <head>
    <title>Hello</title>
  </head>
  <body>
    <p>Welcome to this example.</p>
  </body>
</html>

Он полностью аналогичен следующему:

<!DOCTYPE HTML><title>Hello</title><p>Welcome to this example.

Если вспомнить, то оригинальная спецификация языка HTML от Тима Бернерса-Ли, опубликованная 29 октября 1991 года, содержала всего 18 тегов [21]: <title>, <nextid>, <a>, <isindex>, <plaintext>, <listing>, <p>, <h1>…<h6>, <address>, <hp1>, <hp2>…, <dl>, <dt>, <dd>, <ul>, <li>,<menu> и <dir>. Недавно документу исполнилось 32 года. Говорят, что HTML был разработан под сильным влиянием универсального языка разметки SGML, оттуда вся его структура и логика.

▍ Оптимизация скриптов

В этом году инженеры Википедии рассказали [22], как они оптимизировали JS-скрипты, значительно ускорив загрузку страниц. Этот опыт может быть полезен и другим веб-разработчикам.

Оптимизация Википедии свелась к двум простым шагам:

  1. Удаление лишнего JavaScript. Нужно понимать, что JavaScript — основная причина медленной работы сайта. Так что просто вырезать скрипты — самый простой и быстрый способ [23] ускорить его. Например, в мобильной версии Википедии профилирование показало, что основное время выполнения приходится на метод _enable, который отвечает за разворачивание/сворачивание контента.

    Интересные трюки HTML. Экстремальный минимализм - 2

    Внутри него больше всего времени уходит на вызов метода .on("click") jQuery. Если посмотреть код, то вызов .on("click") прикреплял прослушку событий почти к каждой ссылке на странице, чтобы открывался соответствующий раздел, если это внутренняя ссылка с хэшем.

    function _enable( $container, prefix, page, isClosed ) {
      ...
      // Restricted to links created by editors and thus outside our
      // control T166544 - don't do this for reference links - they will
      // be handled elsewhere
      var $link = $container.find("a:not(.reference a)");
      $link.on("click", function () {
        // the link might be an internal link with a hash.  if it is check
        // if we need to reveal any sections.
        if (
          $link.attr("href") !== undefined &&
          $link.attr("href").indexOf("#") > -1
        ) {
          checkHash();
        }
      });
      util.getWindow().on("hashchange", function () {
        checkHash();
      });
    }

    В длинных статьях Википедии тысячи ссылок [24], что и увеличивало время выполнения на 200+ мс на слабеньких устройствах.

    Этот факт не заметили раньше по двум причинам:

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

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

  2. Оптимизация существующего JavaScript. Дальнейшее профилирование выявило похожий метод initMediaViewer, который выполнялся около 100 мс. Он прикреплял прослушку событий к каждой уменьшенной картинке на странице, чтобы нажатие по ней выводило на экран полное изображение:
    /**
     * Event handler for clicking on an image thumbnail
     *
     * @param {jQuery.Event} ev
     * @ignore
     */
    function onClickImage(ev) {
      ev.preventDefault();
      routeThumbnail($(this).data("thumb"));
    }
     
    /**
     * Add routes to images and handle clicks
     *
     * @method
     * @ignore
     * @param {jQuery.Object} [$container] Optional container to search
     * within
     */
    function initMediaViewer($container) {
      currentPageHTMLParser
        .getThumbnails($container)
        .forEach(function (thumb) {
          thumb.$el.off().data("thumb", thumb).on("click", onClickImage);
        });
    }

    Аналогично предыдущему случаю, от этого страдают страницы с тысячами картинок [26], а задержка может составить сотни миллисекунд.

    Решением стало делегирование событий [27]. Это мощная техника, позволяющая прикрепить обработчик событий не ко всем элементам, а только к одному общему предку. В нашем случае он прикрепляется к контейнеру, который содержит все картинки, а источник событий проверяется через свойство event.target в обработчике. Как вариант, можно использовать event.target.closest(selector) из API [28]. Проверка показывает, откуда поступило нажатие: по уменьшенной копии или нет.

    Вот как выглядит новый код [29]:

    /**
     * Event handler for clicking on an image thumbnail
     *
     * @param {MouseEvent} ev
     * @ignore
     */
    function onClickImage(ev) {
      var el = ev.target.closest(PageHTMLParser.THUMB_SELECTOR);
      if (!el) {
        return;
      }
     
      var thumb = currentPageHTMLParser.getThumbnail($(el));
      if (!thumb) {
        return;
      }
     
      ev.preventDefault();
      routeThumbnail(thumb);
    }
     
    /**
     * Add routes to images and handle clicks
     *
     * @method
     * @ignore
     * @param {HTMLElement} container Container to search within
     */
    function initMediaViewer(container) {
      container.addEventListener("click", onClickImage);
    }

До оптимизации время загрузки скриптов на мобильных устройствах нижнего уровня доходило до 600 мс [30], что неприемлемо долго для интерактивных интерфейсов. В такой ситуации страница блокируется: ни прокрутка, ни переход по ссылкам, ни нажатие кнопок не работают, что вызывает раздражение у посетителей. И нужно учитывать, что выполнение скриптов 600 мс — это только первый этап ожидания. Затем пользователь должен ещё дождаться выполнения соответствующей задачи обработчика кликов (click handler) и рендеринга страницы.

В результате оптимизации удалось снизить время выполнения скриптов вдвое, т. е. до 300 мс. Хотя это тоже долговато. По современным стандартам веб-разработки [31] всё, что дольше 100 мс, считается «медленным» процессом, поскольку пользователь не считает такое взаимодействие мгновенным и нативным.

Разработчики Google ввели для измерения подобных «блокирующих» взаимодействий специальную метрику Total Blocking Time. Из-за фоновых задержек на простаивающие задачи реальный бюджет для обработки ввода не превышает 50 мс:

Интересные трюки HTML. Экстремальный минимализм - 3

По крайней мере, таковы рекомендации экспертов [32].

Синтетические тесты Википедии [33] показали, что в результате оптимизаций время загрузки мобильной версии на телефоне Moto G (5) сократилось на 280 мс, из них примерно 200 мс принесла первая оптимизация с удалением кода. Конечно, это старенький бюджетный смартфон, но и на новых моделях ускорение загрузки мобильной Википедии в апреле-мае 2023 года тоже было заметно на глаз.

Интересные трюки HTML. Экстремальный минимализм - 4

После выпуска в продакшн мониторинг на реальных пользователях подтвердил эти изменения [34].

Для дальнейшей оптимизации TBT опытные специалисты рекомендуют разбивать большие задачи [35] на ряд мелких.

Интересные трюки HTML. Экстремальный минимализм - 5

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

Интересные трюки HTML. Экстремальный минимализм - 6

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


Предыдущие части: 1 [36], 2 [37].

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

Источник [38]


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

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

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

[1] в портативный формат одного исполняемого файла: https://habr.com/ru/companies/ruvds/articles/682150/

[2] хостинг: https://www.reg.ru/?rlink=reflink-717

[3] FAQ: https://smolsite.zip/

[4] извлечение контента из архива может сделать и сам браузер: https://developer.mozilla.org/en-US/docs/Web/API/Compression_Streams_API

[5] https://tinyurl.com/4a7huvj2: https://tinyurl.com/4a7huvj2

[6] LWAN: https://lwan.ws/

[7] Data URI: https://en.wikipedia.org/wiki/Data_URI_scheme

[8] NoPaste: https://nopaste.boris.sh/

[9] вроде такого: https://nopaste.boris.sh/#XQAAAQArAAAAAAAAAABoJ9YnxwgTkhVTSJ0dZKG62HJepQhVmNsN/bFECJJiIA0sPuQpGzUeSFeZuA3++4PDgA==

[10] itty.bitty.site: https://itty.bitty.site/#/?eJyzKbC7MP9iw4UdFzZd2HqxSeFi+4UdF5subADirRd2X+y/sEfhwtILGy5sBKrZoGijX2AHADWGH1A=

[11] goog.space: https://goog.space/#data=eyJ2YWx1ZSI6ItCf0YDQuNCy0LXRgiDRh9C40YLQsNGC0LXQu9GP0Lwg0KXQsNCx0YDQsCEifQ%3D%3D

[12] этим советом: https://merveilles.town/@j3s/110981322978284262

[13] Chrome: https://chrome.google.com/webstore/detail/textarea-cache/chpphekfimlabghbdankokcohcmnbmab

[14] Firefox: https://addons.mozilla.org/en-US/firefox/addon/textarea-cache/

[15] упоминали: https://habr.com/ru/companies/ruvds/articles/692840/

[16] клуб 1kB: https://1kb.club/

[17] No JS: https://no-js.club/

[18] No CSS: https://nocss.club/

[19] No HTML: https://web.archive.org/web/20230122032143/https://no-ht.ml/

[20] много опциональных тегов: https://html.spec.whatwg.org/multipage/syntax.html#optional-tags

[21] всего 18 тегов: https://www.w3.org/History/19921103-hypertext/hypertext/WWW/MarkUp/Tags.html

[22] рассказали: https://www.nray.dev/blog/300ms-faster-reducing-wikipedias-total-blocking-time/

[23] самый простой и быстрый способ: https://timkadlec.com/remembers/2020-04-21-the-cost-of-javascript-frameworks/

[24] тысячи ссылок: https://en.wikipedia.org/wiki/United_States

[25] удалить полностью: https://gerrit.wikimedia.org/r/c/mediawiki/extensions/MobileFrontend/+/908333/6/src/mobile.startup/Toggler.js#22

[26] страницы с тысячами картинок: https://en.wikipedia.org/wiki/B8_polytope

[27] делегирование событий: https://learn.javascript.ru/event-delegation

[28] API: https://developer.mozilla.org/en-US/docs/Web/API/Element/closest

[29] новый код: https://gerrit.wikimedia.org/r/c/mediawiki/skins/MinervaNeue/+/908675/10/resources/skins.minerva.scripts/initMobile.js#66

[30] до 600 мс: https://phabricator.wikimedia.org/T241139

[31] современным стандартам веб-разработки: https://web.dev/rail/#response-process-events-in-under-50ms

[32] рекомендации экспертов: https://web.dev/articles/optimize-long-tasks#task_management_strategies

[33] Синтетические тесты Википедии: https://developer.mozilla.org/en-US/docs/Web/Performance/Rum-vs-Synthetic#synthetic_monitoring

[34] подтвердил эти изменения: https://www.nray.dev/_astro/long-task-duration-results.a598c9a5.png

[35] разбивать большие задачи: https://web.dev/articles/optimize-long-tasks#task-management-strategies

[36] 1: https://habr.com/ru/companies/ruvds/articles/731960/

[37] 2: https://habr.com/ru/companies/ruvds/articles/748950/

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