Быстродействие фронтенда для дизайнеров и разработчиков

Гарри Робертс 15 апреля 2013

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

Быстродействие — это не только крайне важный, но и невероятно интересный предмет, и я все больше и больше увлекаюсь им и на работе (я вечно достаю на этот счет нашего ведущего специалиста по быстродействию), и в собственных проектах, и в рамках CSS Wizardry (здесь достаётся Энди Дэвису).

В этой гигантской статье я поделюсь с вами множеством быстрых, простых, но очень интересных вещей, которые я узнал о быстродействии: надеюсь, они пригодятся и веб-дизайнерам, и фронтенд-разработчикам, а вся эта статья послужит вводной для любого, кто хочет начать заниматься быстродействием и сделать свой фронтенд молниеносно быстрым. Все эти советы вы можете воплотить в жизнь сами, и очень просто. Нужно немножко хитрости и базовые знания о том, как работают браузеры — и всё, вы готовы обыграть систему!

Здесь не будет кучи путаных графиков и трудноперевариваемых цифр. Вместо этого мы сделаем акцент на теории и приемах для повышения быстродействия, которые я освоил, читая, отслеживая, учась у коллег и экспериментируя (достаточно много времени я провел, просто уставившись в каскад отрисовки CSS Wizardry). Кроме того, я дам ссылки на другие статьи по теме, чтобы подчеркнуть какие-то ключевые моменты. Наслаждайтесь!

N.B. Чтобы эта статья была полезной, вам все-таки нужно немножко знать о быстродействии, но все незнакомые термины, которые будут упоминаться в этой статье, очень легко нагуглить!

  1. Принципы
    1. Стили наверху, скрипты внизу
    2. Делайте меньше запросов
    3. Максимальная параллелизация
  2. HTTP-запросы и поиск DNS
    1. Предзагрузка DNS
  3. Предзагрузка ресурсов
  4. CSS и быстродействие
  5. Минификация и gzip
  6. Оптимизация изображений
    1. Спрайты
    2. Изображения для ретины
    3. JPG с прогрессивной загрузкой
    4. Не используйте изображения вообще
  7. Дальнейшее чтение

Принципы

Практически все дизайнеры и фронтенд-разработчики кое-что знают о быстродействии: например, что нужно делать как можно меньше запросов, оптимизировать изображения, размещать ссылки на стили в <head>, размещать JS-код перед </body>, минимизировать JS и CSS, и т.п. Эти базовые вещи уже помогут вашим страницам загружаться быстрее. Но способов ускорить загрузку ещё много… очень много.

Ещё очень важно помнить о том, что браузеры (из-за которых у нас каждый рабочий день болит голова) стали очень умными: много работы по оптимизации быстродействия они делают за вас, так что значительная часть рекомендаций сводится к тому, как наилучшим образом использовать эту работу. Многие ноу-хау по быстродействию касаются понимания, использования и настройки того, что браузер уже делает.

Стили наверху, скрипты внизу

Это простое правило, и следовать ему очень легко, но почему оно имеет такое значение? Если совсем кратко:

  • CSS блокирует отрисовку, поэтому вам нужно разобраться с ним как можно быстрее (то есть в верхней части документа, внутри <head>).
  • JS блокирует загрузки, так что вам нужно разобраться с ним в последнюю очередь, чтобы быть уверенным, что ваши JS-файлы не мешают загрузке других ресурсов на этой странице.

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

Так что размещайте CSS в верхней части страницы, чтобы браузер мог начать отрисовку сразу.

JavaScript блокирует загрузки по ряду причин (браузеры снова умничают), но для начала мы должны знать, как именно происходит загрузка ресурсов в браузерах: если коротко, браузер загружает столько ресурсов, сколько может загрузить параллельно с одного домена. Чем больше доменов задействовано, тем больше ресурсов могут одновременно загружаться параллельно.

JavaScript прерывает этот процесс и блокирует параллельные загрузки с текущего и всех остальных доменов, потому что:

  • Вызванный скрипт может изменить содержимое страницы, и значит, браузер должен разобраться с этим скриптом перед тем, как начать заниматься чем-то ещё. Для этого браузер просто останавливает загрузку всего остального, чтобы полностью сфокусироваться на скрипте.
  • Обычно, чтобы скрипты работали, их нужно загружать в определенном порядке: например, нужно загрузить jQuery, а потом плагин. Ясно, что при параллельной загрузке скриптов, сперва загрузится плагин, а только потом — jQuery. Поэтому браузеры блокируют параллельную загрузку JavaScript-файлов.

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

Однако, по всей видимости, современные браузеры стали ещё умнее. Я приведу здесь отрывочек из письма Энди Дэвиса, потому что он объясняет все гораздо лучше, чем я:

Современные браузеры загружают JS параллельно, и только отрисовка блокируется до тех пор, пока не исполнится скрипт (разумеется, перед этим браузер должен его загрузить).

Загрузка скрипта часто осуществляется предзагрузчиком браузера.

Когда браузер не может отрендерить страницу (например, ждет загрузки CSS или исполнения JS), предзагрузчик анализирует оставшийся код на странице и ищет ресурсы, которые может загрузить.

Некоторые браузеры (например, Chrome) расставляют приоритеты в загрузке ресурсов: например, если в очередь на загрузку стоят скрипты и изображения, браузер сперва загрузит скрипты.

Умно!

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

Делайте меньше запросов

Ещё одна совершенно очевидная и базовая оптимизация быстродействия: загружайте меньше. Каждый ресурс на странице — это лишний HTTP-запрос, на каждый ресурс, необходимый для отрисовки страницы, браузер отвлекается. Каждый из этих запросов может привести к поиску DNS, редиректам, обработке 404-й ошибки и т.п. Таким образом, каждый HTTP-запрос, который вы делаете, будь это запрос стилей, картинок, веб-шрифтов, JS-файла, чего угодно — потенциально весьма дорогостоящая операция. Минимизация количества этих запросов — один из самых простых способов оптимизировать быстродействие.

Возвращаясь к браузерам и параллелизации: большинство браузеров будут загружать всего несколько ресурсов с каждого домена одновременно, а JS, как вы помните, блокирует эти загрузки в любом случае. Каждый HTTP-запрос, который вы делаете, должен быть оправдан, не смотрите на это сквозь пальцы.

Максимальная параллелизация

Для того, чтобы заставить браузер загружать больше ресурсов параллельно, вы можете отдавать их с разных доменов. Если браузер может загружать одновременно, например, только два ресурса с домена, то, раздавая ресурсы с двух доменов, вы сможете загружать одновременно четыре ресурса; с трёх — значит браузер может выжать шесть одновременных загрузок.

У большого количества сайтов есть домены для статических ресурсов. Например, Twitter раздает статические ресурсы с si0.twimg.com:

	<link rel="stylesheet"
	      href="https://si0.twimg.com/…/t1_core.bundle.css"
	      type="text/css" media="screen">

Facebook использует fbstatic-a.akamaihd.net:

	<link rel="stylesheet"
	      href="https://fbstatic-a.akamaihd.net/…/76f893pcD3j.css">

Используя эти домены для статических ресурсов, Twitter и Facebook могут отдавать больше ресурсов параллельно: ресурсы с twitter.com и si0.twimg.com могут загружаться одновременно. Это очень простой способ получить большее количество одновременных загрузок ресурсов на вашей странице, и его можно улучшить, совместив с технологией CDN (она позволяет уменьшить сетевые задержки за счёт того, что ресурс отдается с наиболее подходящего физического сервера).

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

Итак, вот наши принципы быстродействия:

  • Размещайте ссылки на стили наверху страницы
  • Размещайте JavaScript внизу (насколько это возможно)
  • Делайте как можно меньше HTTP-запросов
  • Раздавая ресурсы с нескольких доменов, вы можете увеличить количество ресурсов, которые браузер будет загружать параллельно.

HTTP-запросы и поиск DNS

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

С этим, однако, есть и проблема — DNS-запросы. Каждый раз, когда делается запрос к новому домену (с холодного кэша), HTTP-запрос должен произвести довольно долгий DNS-запрос (между 20 и 120 мс). За это время исходящий запрос смотрит, где же, собственно, находится ресурс: интернет организован с помощью IP-адресов, на которые ссылаются доменные имена, которые, в свою очередь, управляются DNS.

В обращение к каждому новому домену, с которого вы запрашиваете ресурсы, включена стоимость DNS-запроса, и вам нужно быть уверенным, что оно того стоит. Если вас сайт небольшой (как, например, CSS Wizardry), тогда вам, скорее всего, не стоит раздавать ресурсы с поддомена: браузер, вероятно, сможет скачать несколько ресурсов с одного домена без параллелизации быстрее, чем сделать DNS-запросы на несколько доменов и распараллелить загрузку ресурсов с них.

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

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

Важно помнить, что, если HTML уже запрошен с домена, скажем, foo.com, DNS-запрос для этого хоста уже произошёл, так что дополнительные запросы к любому ресурсу на foo.com больше не проходят через DNS-запрос.

Предзагрузка DNS

Если вы, как и я, хотите, чтобы у вас на сайте был виджет Twitter, аналитика или какие-то веб-шрифты, то вам нужно будет ссылаться на внешние домены. Это означает, что вам нужно будет тратить время на DNS-запросы. Мой совет: не использовать какие попало виджеты, не обдумав заранее их влияние на быстродействие. Но если вы решили, что какой-то виджет вам необходим, полезно знать следующее.

Поскольку эти ресурсы располагаются на других доменах, CSS для вашего веб-шрифта, например, будет загружаться параллельно с вашим собственным CSS, что в каком-то смысле хорошо, но скрипты всё равно будут блокировать браузер (если они не асинхронные).

На самом деле, проблема здесь заключается в DNS-запросах, связанных с внешними доменами. К счастью, есть очень быстрый и лёгкий способ ускорить этот процесс: предзагрузка DNS.

Что делает предзагрузка DNS, понятно из названия; реализовать её очень просто. Если вам нужно запросить ресурсы, скажем, с widget.foo.com, вы можете предзагрузить DNS для этого поддомена, просто добавив в начале страницы в секции <head>:

	<head>
	
	    <link rel="dns-prefetch" href="//widget.foo.com">
	
	</head>

Эта простая строчка объявит браузерам, которые поддерживают предзагрузку, что им стоит начать загружать DNS для этого домена за долю секунды до того, как это понадобится сделать для загрузки ресурса. Таким образом, когда браузер дойдёт до элемента <script>, запрашивающего виджет, DNS-запрос уже будет запущен. Так браузер чуть-чуть опережает события.

Этот простой элемент <link> (я использую его на CSS Wizardry) полностью обратно совместим и не отразится отрицательно на быстродействии. Думайте об этом, как о прогрессивном улучшении быстродействия.

Дальнейшее чтение

Speed Up Your Site Using Prefetching.

Предзагрузка ресурсов

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

Веб-шрифты и изображения, упомянутые в CSS, ведут себя точно так же: браузер начнет загружать их, как только наткнётся на ту часть HTML-кода, для которого они нужны. Как я уже говорил выше, браузеры очень умные, и здесь мы видим ещё одно подтверждение этому. Представьте себе, если бы браузеры загружали изображения из CSS, как только увидели в стилях следующее:

	.page--home         { background-image:url(home.jpg); }
	.page--about        { background-image:url(about.jpg); }
	.page--portfolio    { background-image:url(portfolio.jpg); }
	.page--contact      { background-image:url(contact.jpg); }

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

Если же мы полностью уверены, что какое-то изображение из CSS точно будет использоваться на каждой странице, мы можем обмануть браузер и заставить его скачать это изображение как можно раньше, ещё до того, как он доберется до HTML, которому оно требуется. Сделать это невероятно просто, но, в зависимости от того, как именно вы решите это сделать, это может быть немного грязным приёмом.

Итак, грязный, но самый безопасный способ: поставить на каждой странице скрытый <div>, в котором при помощи элементов <img> с пустым атрибутом alt вставлены все изображения из CSS. Я поступил так со спрайтом на CSS Wizardry; я знаю, что они используется на каждой странице, и поэтому с уверенностью могу предзагружать его в своем HTML. Браузеры замечательно обрабатывают теги <img>: предзагружая картинку, браузер обращается к ней очень рано, поэтому, заставив его загрузить спрайты с помощью тега <img> в разметке, мы добиваемся более ранней загрузки изображения, чем затребовал бы CSS. Таким образом, упомянув (скрытое) изображение в HTML, я ускоряю эту загрузку.

Со вторым, более «чистым» способом, который очень похож на пример с предзагрузкой DNS, есть некоторая путаница:

<link rel="prefetch" href="sprite.png">

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

Путаница заключается в несогласованности между двумя статьями: по этой статье с MDN можно понять, что prefetch — подсказка для браузера, что, может быть, стоит предзагрузить ресурс, если браузер сейчас ничем не занят. Напротив, в этой статье с Planet Performance сказано, что браузер всегда будет предзагружать ресурсы, если он поддерживает синтаксис rel="prefetch", и не упоминается, что это будет сделано «в свободное время». Графики загрузки, на которые я смотрел, вроде бы подтверждают второй вариант, но странный глюк в WebKit, из-за которого нельзя наблюдать результаты предзагрузки, если у тебя открыт отладчик (привет, быстродействие Шредингера!), приводит к том, что я не могу быть уверенным на 100%. Буду очень благодарен за любые комментарии по этому поводу.

Я уже говорил, что шрифты и изображения работают почти одинаково: сказанное выше относится и к файлам шрифтов, но шрифт нельзя загрузить в спрятанном <div>, нужно использовать prefetch.

<link rel="prefetch" href="webfont.woff">

Проще говоря, мы делаем следующее: заставляем браузер скачать наш ресурс заранее, так что к тому времени, как нужно будет применять наш CSS, он уже будет скачан (ну или хотя бы начнет скачиваться). Ура!

Дальнейшее чтение

Speed Up Your Site Using Prefetching.

CSS и быстродействие

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

Одно из маленьких открытий, которое мы сделали в процессе работы, звучит так: не раздавайте CSS с поддомена.

Помните, как мы обсуждали блокировку отрисовки загрузкой стилей. Браузер хочет получить ваш CSS как можно скорее, CSS находится на критическом пути — то есть на том необходимом пути, который браузер проходит от момента, когда пользователь затребовал страницу, и до того, когда он что-то увидел. В отличие от JS и изображений, CSS находится там из-за своего свойства блокировать отрисовку. В ваших интересах проходить критический путь настолько быстро, насколько это возможно — то есть без дополнительных DNS-запросов.

Однажды мы разрабатывали сайт, рабочее окружение которого раздавало все ресурсы с одного хоста (например, foo.com), но когда дело дошло до того, чтобы сделать его более приближенным к реальному, мы начали раздавать ресурсы с s1.foo.com и s2.foo.com. Получилось, что все изображения, JS, CSS и шрифты были расположены на разных доменах, что приводило к нескольким DNS-запросам. Проблема здесь в том, что неоходимый для получения CSS-файла DNS-запрос, отправленный из холодного кэша, сразу же замедлял наш критический путь. Наши графики ужасно скакнули, показывая задержку, которой в теории не должно было случиться: все прогрессивные практики диктуют, что вы должны распределять большое количество ресурсов по поддоменам, не правда ли? CSS это не касается. Необходимый DNS-запрос занимал ощутимое время, на которое в итоге задерживалась отрисовка страницы.

CSS — один из самых страшных врагов быстродействия, подчеркивает Стоян Стефанов, — именно из-за этой блокировки отрисовки. Также стоит отметить, что браузер скачает все CSS-файлы перед тем, как начнет рендерить страницу. Это значит, что браузер в любом случае запросит print.css, даже если страница всего лишь выводится на экран. Это значит, что все стили, которые используются только вместе с медиавыражениями, например, следующие стили, скачаются в любом случае, даже если они не нужны:

	<link rel="stylesheet"
	      media="screen and (min-device-width: 800px)"
	      href="desktop.css">

Впрочем, Энди Дэвис сообщил мне, что WebKit расставляет приоритеты в порядке загрузки CSS таким образом, что сперва загружается только тот CSS, который нужен для первоначального отображения страницы, а загрузка всех остальных стилей (например, print.css) как можно дольше откладывается. Отлично!

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

  • Никогда не раздавайте CSS с отдельного домена, поскольку это приводит к задерживающим отрисовку DNS-запросам.
  • Вставляйте CSS в HTML-код как можно раньше, чтобы браузер мог скачать его и заняться другими вещами.
  • Собирайте CSS в один файл. Браузер все равно скачает весь CSS, поэтому гораздо лучше просто собрать все, что у вас есть, в один HTTP-запрос.
  • Сожмите его с помощью gzip и минифицируйте, чтобы браузеру пришлось загружать меньше.
  • Закэшируйте все, что можно, чтобы весь этот процесс происходил как можно реже.

CSS находится на вашем критическом пути, так что вам нужно разобраться с ним быстро; он блокирует отрисовку, это означает, что пользователям загрузка страницы будет казаться медленной. Когда мы перенесли CSS на поддомен, наше быстродействие резко упало.

Дальнейшее чтение

CSS And the Critical Path

Минификация и gzip

Есть две простые вещи, которые вы можете (и должны) сделать со своими текстовыми ресурсами: минификация, чтобы убрать комментарии и пробелы, и сжатие с помощью gzip, чтобы ещё сильнее уменьшить размер.

Если выбирать из этого только что-то одно, то gzip эффективнее, чем минификация. Но если вы можете, делайте и то и другое.

Обычно для того, чтобы включить gzip, нужно чуть-чуть поиграть с .htaccess, но, как подсказывает мой добрый друг Ник Пэйн, .htaccess — не самая лучшая вещь с точки зрения серверного быстродействия — .htaccess заново анализируется на каждом входящем запросе, поэтому при его использовании возникает достаточно большая нагрузка.

Итак, из документации Apache:

Вам стоит перестать использовать .htaccess полностью, если у вас есть доступ к конфигурационному файлу главного httpd-сервера. Использование .htaccess замедляет ваш Apache. Любую директиву, которую вы включаете в .htaccess, гораздо лучше поместить в блок Directory, поскольку эффект будет таким же, а быстродействие — лучше…

Если же у вас есть только доступ к .htaccess, не волнуйтесь: эта нагрузка обычно настолько маленькая, что беспокоиться о нёй на стоит. Включить gzip с помощью .htaccess на самом деле очень просто. С минификацией сложнее, разве что у вас есть процесс сборки проекта, или если вы используете какой-то препроцессор или CodeKit, который компилирует исходники сразу в минифицированную версию.

Кстати, главной причиной, по которой я переписал inuit.css на Sass было (по крайней мере, сперва) то, что я мог легко скомпилировать минифицированную версию.

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

Gzip, как и любой другой алгоритм сжатия, берет любой текстовый исходник и сжимает его на основании повторяющихся строк. В целом, gzip сжимает код очень хорошо, потому что в любом коде, как правило, есть типовые строки, которые повторяются: например, background-image в CSS, <strong> в разметке и т.п.

Gzip действительно очень сильно уменьшает размер ваших ресурсов, и вам определенно нужно включать его. Если вам нужен хороший пример .htaccess, посмотрите, как это сделано в HTML5 Boilerplate.

Сжатие вашего контента это гигантская экономия. На данный момент inuit.css весит 77 КБ. После минификации и gzip-сжатия он весит всего лишь 5,52 КБ. Таким образом, эти два приема дают нам экономию в 93%. Ну а раз gzip хорошо работает на текстовых ресурсах, то вы можете сжимать с его помощью и SVG, и даже некоторые форматы шрифтов!

Оптимизация изображений

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

Спрайты

Если вы хотите, чтобы ваш сайт обладал хорошим быстродействием, спрайты просто-напросто обязательны: вы загружаете одну большую картинку через один HTTP-запрос, а не несколько изображений за несколько запросов. Проблема состоит в том, что не все изображения можно объединить в спрайт: например, если у вас есть иконка, которая должна быть фоновым изображением на элементе переменной длины, то у вас не получится это сделать — это не работает для элементов, размеры которых не фиксированы. Вы можете оставить много свободного места вокруг картинки в своём спрайте, но лишние пиксели в спрайтах сами по себе являются проблемой для быстродействия.

Чтобы справиться с изображениями, которые нельзя поместить в спрайты, нам понадобится «спрайтовый элемент». По сути, это просто пустой элемент, обычно <i>, единственная задача которого — оставаться пустым и содержать фоновое изображение. (Всё же элемент <i> имеет другое назначение и здесь больше подойдёт <span>прим. редактора.)

Я использовал такие элементы, когда разрабатывал Sky Bet, они используются на YouTube и Facebook, а Джонатан Снук написал целый раздел о них на SMACSS.

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

	<li>
	    <a href="/profile/">
	        <i class="icon icon--person"></i> Profile
	    </a>
	</li>

Здесь мы не можем отправить в спрайты ни для <li>, ни для <a>, так что мы просто ставим пустой <i>, в котором и находится иконка. Именно это — одна из тех вещей, которые я больше всего люблю в теме быстродействия: вы используете разные умные приемы, чтобы увеличить скорость загрузки страницы, но при этом используете разметку, которая традиционно считается «плохой». Отлично же!

Дальнейшее чтение

To Sprite Or Not To Sprite.

Изображения для ретины

Вам не нужно готовить для ретины все изображения. Картинка в два раза больше по ширине и высоте содержит в четыре раза больше пикселей, чем такая же картинка в стандартном разрешении. В четыре. Раза. Хоть это и не значит, что размер файла увеличится соответственно — все-таки у изображений свои методы сжатия — но памяти на это изображение требуется в четыре раза больше.

Давайте мы на секунду остановимся и подумаем: изображения для ретины чаще всего (хоть и необязательно) нужны для того, чтобы отображение дизайна на телефонах было более четким. У телефонов гораздо меньше памяти, чем у других устройств. Таким образом, изображения для ретины занимают кучу памяти на устройствах, у которых, как известно, лишней памяти немного… Подумайте ещё раз, действительно ли вам нужны изображения для ретина, или вы можете пойти на разумный компромисс?

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

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

Если ваша статистика использования браузеров позволяет, вместо растровых изображений вы можете использовать SVG или шрифт с иконками. На CSS Wizardry я использую SVG и это даёт мне следующие преимущества:

  • Независимость от разрешения
  • Можно минифицировать
  • Можно сжимать в gzip

Мой коллега Мэтт Аллен сделал шрифт с иконками, который можно использовать вместе со спрайтовым элементом, чтобы на странице были пригодные для ретина-дисплеев масштабируемые иконки.

Ещё вы можеете попробовать сервисы вроде ReSRC.it, чтобы загружать изображения в зависимости от устройства и дополнительных условий.

JPG с прогрессивной загрузкой

Ещё один интересный аспект быстродействия — это его восприятие: дело не только в том, что говорят цифры, но и в том, есть ли ощущение, что сайт быстрый.

Вам наверняка знакома прерывистая загрузка больших JPG-изображений: 100 пикселей картинки загрузилось, пауза, ещё 50, пауза, потом ещё 200, потом — бах! — вся картинка загрузилась.

Это работа обычного (baseline) JPG, и она действительно выглядит крайне прерывистой. Если вы переключаетесь на JPG с прогрессивной загрузкой, всё происходит намного веселее: сперва появляется вся картинка, но сильно размытая, затем изображение постепенно фокусируется. Звучит хуже, чем предыдущем варианте, но на самом деле ощущается, что загрузка идет быстрее: пользователь сразу что-то видит, а качество постепенно улучшается. Эти изображения, как правило, чуть тяжелее своих стандартных версий, но в целом будет казаться, что изображение загружается намного быстрее.

Для того, чтобы создать JPG с прогрессивной загрузкой, нужно всего лишь включить соответствующий флажок в диалоге «Save for Web» в Photoshop — и дело сделано!

Дальнейшее чтение

Progressive JPEGs: a New Best Practice.

Не используйте изображения вообще

Лучше, чем спрайты, SVG и игнорирование ретины — полный отказ от изображений. Если вы можете сверстать дизайн картинкой со стопроцентной точностью, а повторить его чистым CSS с точностью 75% — лучше выберите CSS-решение (конечно, если для этого не потребуются лишние сто строчек кода!). Если у вас нет картинок — нет и HTTP-запросов, а также это упрощает поддержку сайта. Если вы можете не использовать изображения — не используйте.

Итоги

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

Если у вас есть предложения, что можно было бы сюда добавить — или вы не согласны, или хотите поправить меня — пожалуйста, присоединяйтесь к обсуждению; весь этот мир быстродействия для меня относительно нов, поэтому я очень хочу продолжать учиться у других и узнавать что-то новое.

Я очень надеюсь, что эта простыня хоть немного помогла вам, и, прочитав её, вы получили знания о вещах, о которых вы, возможно, никогда бы и не задумались. Ещё я надеюсь, что эта статья помогла вам хотя бы вполовину так заинтересоваться вопросами быстродействия, как ими заинтересовался я.

Я особенно хотел бы поблагодарить Ника Пэйна и Энди Дэвиса за помощь в прояснении нескольких вещей, которые я описал в этой статье. Спасибо, парни!

Дальнейшее чтение

Если вам понравилась эта статья и вы хотите узнать ещё, я настоятельно рекомендую следующее:

Перевод оригинальной записи «Front-end performance for web designers and front-end developers» Гарри Робертса (Harry Roberts), опубликованной на сайте CSS Wizardry. Переведено и опубликовано с разрешения автора.

Перевод Влада Андерсена, редактура Вадима Макеева и Ольги Алексашенко.

Теги: , ,

Комментарии +

  1. Батя 21 апреля 2013 в 0:07

    Не о чем. Большая статья? - одна вода.
    С днс только запутал. Предзагрузка картинок из css - вообще жесть. Положить х.. на ретину тоже порадовало.

    Единственное, что вынес для себя полезного, это baseline JPG.

    Вообще достаточно использовать спрайты и svg для картинок. Объеденить и сжать весь css в один файл, также поступить и с js. Вот и всё, что нужно было написать.

  2. Бодро 22 апреля 2013 в 13:14

    Спасибо. Отличная статья!

  3. Дмитрий 27 апреля 2013 в 0:35

    Отличная, простая и вместе с тем полезная статья. Кому интересно, могу посоветовать Tali Garsiel How browsers work, где более подробно описан процесс разбора кода и рендеринга страницы.

  4. morontt 7 мая 2013 в 2:06

    Отличная и полезная статья :)

  5. Sklif 16 июля 2016 в 0:08

    Браузер может совершать максимум 4 одновременных загрузки, о каких 6 и более с разных доменов тут идёт речь?

  6. Вадим Макеев 16 июля 2016 в 0:37

    Sklif16, вопрос лучше задать непосредственно Гарри в Твиттере.

Перейти к началу