{
    "version": "https:\/\/jsonfeed.org\/version\/1",
    "title": "Dmitry Podgorniy, posts tagged: верстка",
    "home_page_url": "https:\/\/blog.dmitrypodgorniy.com\/tags\/verstka\/",
    "feed_url": "https:\/\/blog.dmitrypodgorniy.com\/tags\/verstka\/json\/",
    "icon": "https:\/\/blog.dmitrypodgorniy.com\/user\/userpic@2x.png",
    "author": {
        "name": "Дмитрий Подгорный",
        "url": "https:\/\/blog.dmitrypodgorniy.com\/",
        "avatar": "https:\/\/blog.dmitrypodgorniy.com\/user\/userpic@2x.png"
    },
    "items": [
        {
            "id": "116",
            "url": "https:\/\/blog.dmitrypodgorniy.com\/all\/razbor-zadachi-s-konkursa-yandeksa-po-uskoreniyu-zagruzki-strani\/",
            "title": "Разбор задачи с конкурса Яндекса по ускорению загрузки страницы",
            "content_html": "<p>Описание, условие и код: <a href=\"https:\/\/github.com\/yandex-cs\/yac2013\">https:\/\/github.com\/yandex-cs\/yac2013<\/a><br \/>\nРезультаты (я семнадцатый): <a href=\"http:\/\/cs.yandex.net\/ratings\">http:\/\/cs.yandex.net\/ratings<\/a><\/p>\n<p>Первый вгляд на состояние вещей:<br \/>\nТяжелые картинки, множество шрифтов, тонны комментариев, много сриптов при бедной функциональности самой страницы. Страница рендерится за 9-12ms<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/blog.dmitrypodgorniy.com\/pictures\/Screen-Shot-2013-10-03-at-17.00.54.png\" width=\"340\" height=\"197\" alt=\"\" \/>\n<\/div>\n<p>Как я работал:<br \/>\nНакомитил множество изменений, и мой первый пуш отреджектили, потому что не нашли тег footer. Я удалил тег для того, чтобы избавиться от <a href=\"http:\/\/code.google.com\/p\/html5shiv\/\">html5shiv.js<\/a>, так как footer был единственным html5 тегом на странице. Прикольно, что этот тег не нашелся роботом даже когда я его вернул. Потом я откатился на самое начало, и начал вносить изменения пачками, чтобы проще было понять какие мои агрессивные изменения были непровалидированы роботом. На седьмой пачке изменений, я понял, что все самые влиятельные изменения, которые я могу провести, уже проведены, при этом до вершины олимпа еще далеко. Я успокоился, смирившись с тем, что фронтенд разработчик и ускоритель страниц из меня не тот. Разгадка оказалась проста, она будет ближе к концу.<\/p>\n<p>Детальный взгляд:<br \/>\nПромахи не отсортированы в порядке важности и влиянию на загрузку страницы.<\/p>\n<p><b>Красивые комментарии<\/b> в index.html<br \/>\nВыкидываем.<\/p>\n<p><b>90кб фавиконка.<\/b><br \/>\n<a href=\"https:\/\/github.com\/yandex-cs\/yac2013\/blob\/gh-pages\/index.html#L9\">https:\/\/github.com\/yandex-cs\/yac2013\/blob\/gh-pages\/index.html#L9<\/a><br \/>\n<a href=\"https:\/\/github.com\/yandex-cs\/yac2013\/blob\/gh-pages\/assets\/img\/favicon.ico\">https:\/\/github.com\/yandex-cs\/yac2013\/blob\/gh-pages\/assets\/img\/favicon.ico<\/a><br \/>\nЯвно не то. Ужимаем до 16x16 пикселей. Не знаю, может какие браузеры понимают большие фавиконки. Быстрый поиск в интернете никаких подсказок не дал. Размер ужатой фавиконки: 0.5 кб.<\/p>\n<p><b>Множество неиспользуемых скриптов.<\/b><br \/>\n<a href=\"https:\/\/github.com\/yandex-cs\/yac2013\/blob\/gh-pages\/index.html#L24\">https:\/\/github.com\/yandex-cs\/yac2013\/blob\/gh-pages\/index.html#L24<\/a><br \/>\nТо, что они не используются станет ясно позже. jQuery используется в 1 месте и через жопу, поэтому все скрипты в итоге будут удалены.<\/p>\n<p><b>SVG в формате base64 в фоне body<\/b><br \/>\nПревращаю в png base 64, размер уменьшается с 16 до 5 кб. Нахожу первый ключ:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/blog.dmitrypodgorniy.com\/pictures\/Screen-Shot-2013-10-03-at-17.46.54.png\" width=\"625\" height=\"230\" alt=\"\" \/>\n<\/div>\n<p><b>Огромное изображение<\/b> (460кб) для хедера позиционируется фоном, показывая только часть.<br \/>\n<a href=\"https:\/\/github.com\/yandex-cs\/yac2013\/blob\/gh-pages\/assets\/img\/photo_head.jpg\">https:\/\/github.com\/yandex-cs\/yac2013\/blob\/gh-pages\/assets\/img\/photo_head.jpg<\/a><br \/>\nИзображение режим, сохраняем в jpeg с 51% сжатием. Это тот момент, когда фотка максимально пожата, при этом максимально хорошо выглядит (при значении ниже начинают ползти артефакты). Обрезанная фотка: 23 кб. Можно было заморачиваться дальше, но овчинка выделки не стоит пока.<\/p>\n<p><b>Единственное место в коде, где используется jQuery<\/b><br \/>\n<a href=\"https:\/\/github.com\/yandex-cs\/yac2013\/blob\/gh-pages\/index.html#L65\">https:\/\/github.com\/yandex-cs\/yac2013\/blob\/gh-pages\/index.html#L65<\/a><br \/>\nПри этом только для того, чтобы изменить разметку и подгрузить другое изображение <a href=\"https:\/\/github.com\/yandex-cs\/yac2013\/blob\/gh-pages\/index.html#L87\">в меню<\/a>. Выкидываем скрипт, источник изображения меняем вручную.<\/p>\n<p><b>Иконки меню.<\/b> Много, тяжелые, уменьшенные стилями.<br \/>\n<a href=\"https:\/\/github.com\/yandex-cs\/yac2013\/blob\/gh-pages\/index.html#L87\">https:\/\/github.com\/yandex-cs\/yac2013\/blob\/gh-pages\/index.html#L87<\/a><br \/>\nИмеют неоригинальные размеры, и подозрительный вес в <a href=\"https:\/\/github.com\/yandex-cs\/yac2013\/blob\/gh-pages\/assets\/img\/ico-crown.png\">9кб каждая<\/a>. Изменяем в тот размер, что используется, прогоняем через <a href=\"http:\/\/advsys.net\/ken\/utils.htm#pngout\">pngout<\/a>, получаем 0.5кб каждая. Для того, чтобы не делать 6 лишних запросов, инлайню изображения через base64.<\/p>\n<p>base64 увеличивает объем изображения примерно на 33%, но при этом браузеру не надо слать дополнительный запрос на сервер. К тому же, если страница загзиплена, то base64 не так сильно влияет на итоговый объем данных.<\/p>\n<p><b>Подгрузка скрипта для вставки баннера<\/b><br \/>\n<a href=\"https:\/\/github.com\/yandex-cs\/yac2013\/blob\/gh-pages\/index.html#L128\">https:\/\/github.com\/yandex-cs\/yac2013\/blob\/gh-pages\/index.html#L128<\/a><br \/>\nВыкидываем чепуху со скриптом, вставляем баннер прямо на страницу. Попутно заменяем png изображение на jpg, уменьшая размер файла вдвое.<\/p>\n<p>В удаленном скрипте нас ждет второй ключ – голубой. Замка к нему не нашел:<\/p>\n<pre><pre class=\"e2-text-code\"><code>if (0 == 1) {\r\n\tdocument.write('&lt;scr' + 'ipt type=&quot;text\/javascript&quot; src=&quot;HTTP:\/\/about:blank.js?plugin=&quot;&gt;&lt;\/scr' + 'ipt&gt;&lt;nosc' + 'ript&gt;Blue KEY!&lt;\/no' + 'script&gt;');\r\n}<\/code><\/pre><\/pre>\n<p><b>img не оригинального размера, и веса (1700кб)<\/b><br \/>\n<a href=\"https:\/\/github.com\/yandex-cs\/yac2013\/blob\/gh-pages\/index.html#L153\">https:\/\/github.com\/yandex-cs\/yac2013\/blob\/gh-pages\/index.html#L153<\/a><br \/>\n<a href=\"https:\/\/github.com\/yandex-cs\/yac2013\/blob\/gh-pages\/assets\/img\/photo_02.jpg\">https:\/\/github.com\/yandex-cs\/yac2013\/blob\/gh-pages\/assets\/img\/photo_02.jpg<\/a><br \/>\nИзображение ресайзится буквально на пару пикселей относительно оригинального. Это дает дополнительную нагрузку на проц. Обрезаем изображение. Попутно обращаем внимение, что изображение весит подозрительно много. Прогоняем через минификатор джипегов, получаем итоговый размер в 11.2кб.<\/p>\n<p>Найдя два ключа, предполагаю, что есть третий и он зелен. Туточки, среди мусора метаинформации, где и ожидалось.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/blog.dmitrypodgorniy.com\/pictures\/Screen-Shot-2013-10-03-at-17.50.37.png\" width=\"314\" height=\"97\" alt=\"\" \/>\n<\/div>\n<p>Предполагаю, но не проверяю, что третий ключ находился в метаинформации этого изображения (всего было замечено два ключа). <a href=\"https:\/\/github.com\/yandex-cs\/yac2013\/issues\/643\">Спрашиваем<\/a>.<\/p>\n<p><b>Стили с описанием шрифтов<\/b> грузятся динамически. и весят по 200кб.<br \/>\n<a href=\"https:\/\/github.com\/yandex-cs\/yac2013\/blob\/gh-pages\/assets\/css\/bootstrap.css#L1\">https:\/\/github.com\/yandex-cs\/yac2013\/blob\/gh-pages\/assets\/css\/bootstrap.css#L1<\/a><br \/>\nТут интуресный момент. Если браузер видит, что для текста определен нестандартный шрифт, и есть font-face для этого шрифта, браузер скрывает текст до тех пор, пока шрифт не прогрузится. Даже при динамическом добавлении определений шрифтов после готовности документа сначала показывается текст, потом скрывается и браузер ждет догрузки шрифтов.<\/p>\n<p>Я хотел добиться результата, когда страницу можно читать до того, как шрифты прогрузились (в идеале шрифты надо прогружать с таймаутом, чтобы отмести тех, у кого интернет медленен, и не подгружать файлы шрифтов при последующих загрузках страницы). Иду на хитрость: <a href=\"подгружаю\">аяксом <a href=\"https:\/\/github.com\/podgorniy\/yac2013\/blob\/gh-pages\/index.html#L185\">https:\/\/github.com\/podgorniy\/yac2013\/blob\/gh-pages\/index.html#L185<\/a><\/a> шрифты, и только после того, как все прогрузились, объявляю @font-face. Протестировал с фиддлером на хроме-фаерфоксе-ие9 – все ок: страница читабельна, шрифты появляются позже. Единственно, что хром иногда пробовал запросить один шрифт еще раз.<\/p>\n<p>Похоже, что такие оптимизации шутилка не меряет, потому как после этого, как мне казалось, шикарного решения, я поднялся в рейтинге совсем чуть.<\/p>\n<p><b>140кб бутстрапных стилей<\/b> мозолят глаза.<br \/>\n<a href=\"https:\/\/github.com\/yandex-cs\/yac2013\/blob\/gh-pages\/assets\/css\/bootstrap.css\">https:\/\/github.com\/yandex-cs\/yac2013\/blob\/gh-pages\/assets\/css\/bootstrap.css<\/a><br \/>\nАнализ хромовскими инструментами показал, что 93% селекторов из этого файла не используются. Поиск инструментов, которые бы почистили файл от неиспользуемых селекторов не увенчался успехом. Все найденные инструменты только давали список неиспользуемых селекторов. Поэтому я <a href=\"https:\/\/gist.github.com\/podgorniy\/a10f41337dbd08c7e94f\">написал штуку<\/a>, получающую на вход список селекторов и css файл, а на выходе дает чистый файл. Конечный размер файла стилей 14кб. Удаление мертвых селекторов так же уменьшило время отрисовки страницы до 7мс.<\/p>\n<p><b>Тени, уголки<\/b> в хедере. Из за них страница отрисовывалась не за 2-3мс, а за 7.<br \/>\nЗаменяю тени на изображение – профит. Время отрисовки уменьшилось до 2-3мс.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/blog.dmitrypodgorniy.com\/pictures\/Screen-Shot-2013-10-03-at-21.00.50.png\" width=\"249\" height=\"145\" alt=\"\" \/>\n<\/div>\n<p>Надо понимать, что эта оптимизация никак не про ускорение начальной отрисовки страницы. Это оптимизация больше влияет на то, как ощущается пользователем скорость работы со страницей.<\/p>\n<p><hr\/><\/p>\n<p>Всего выше не оказалось достаточным. Главный вес, и, соответственно проблема, заключалась в шрифтах. Топовые ребята инлайнят шрифты через data-uri, и используют за-gzip-ленные статические файлы. Так как я со шрифтами де-факто ничего не сделал, их вес сыграл свою роль.<\/p>\n",
            "date_published": "2013-10-03T20:26:14+02:00",
            "date_modified": "2013-10-03T20:25:36+02:00",
            "image": "https:\/\/blog.dmitrypodgorniy.com\/pictures\/Screen-Shot-2013-10-03-at-17.00.54.png",
            "_date_published_rfc2822": "Thu, 03 Oct 2013 20:26:14 +0200",
            "_rss_guid_is_permalink": "true",
            "_rss_guid": "https:\/\/blog.dmitrypodgorniy.com\/all\/razbor-zadachi-s-konkursa-yandeksa-po-uskoreniyu-zagruzki-strani\/",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css"
                ],
                "og_images": [
                    "https:\/\/blog.dmitrypodgorniy.com\/pictures\/Screen-Shot-2013-10-03-at-17.00.54.png",
                    "https:\/\/blog.dmitrypodgorniy.com\/pictures\/Screen-Shot-2013-10-03-at-17.46.54.png",
                    "https:\/\/blog.dmitrypodgorniy.com\/pictures\/Screen-Shot-2013-10-03-at-17.50.37.png",
                    "https:\/\/blog.dmitrypodgorniy.com\/pictures\/Screen-Shot-2013-10-03-at-21.00.50.png"
                ]
            }
        }
    ],
    "_e2_version": 3254,
    "_e2_ua_string": "E2 (v3254; Aegea)"
}