Ser-Gen

Склеивать файлы или держать раздельно?

07 Mar 2014

Часто встречаю в рекомендациях по оптимизации загрузки страниц такой совет:

Объединяйте файлы стилей, скриптов, картинок в один соответствующий файл, это поможет сократить количество запросов и этим ускорит загрузку ресурсов!

В наличии несколько файлов:

jquery.fancybox.js
jquery.tiptip.js
jquery.some.js
jquery.more.js
jquery.plgn.js
init.js
load.js
main.js

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

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

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

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

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

Не гадай, тестируй!

От абстрактных к контекстным

04 Mar 2014

Элементы интерфейса на страницах сайта редко бывают абстрактными, они связаны назначением в общих блоках и их объединениях. Внутри таких блоков формируется контекст.

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

Контекстные блоки — расширенные и обьединённые абстрактные, приправленные нужными только им стилями!

Например, нужно дать элементу Error__header стили блока Header с его модификаторами.

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

  • указанием классов блоков вместе на одном узле в разметке;
  • объединением селекторов блоков вручную или при помощи препроцессора.

Объединенение классов в разметке

<span class="nt"><h4</span> <span class="na">class=</span><span class="s">"Header Header--main Header--type-error Error__header"</span><span class="nt">></h4></span>

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

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

Объединение в вёрстке

Чтобы контекстный блок использовал стили абстрактного, можно объединять их классы в составных селекторах.

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

Для того, чтобы упростить объединение селекторов, в препроцессорах есть функция @extend, позволяющая указывать класс расширяющей сущности в блоке объявлений расширяемой.

<span class="nc">.Header</span> <span class="p">{</span><span class="err">...</span><span class="p">}</span>
<span class="nc">.Header--main</span> <span class="p">{</span><span class="err">...</span><span class="p">}</span>
<span class="nc">.Header--type-error</span> <span class="p">{</span><span class="err">...</span><span class="p">}</span>

<span class="nc">.Error__header</span> <span class="p">{</span>
  <span class="err">@extend</span> <span class="err">.Header;</span>
  <span class="err">@extend</span> <span class="err">.Header--main;</span>
  <span class="err">@extend</span> <span class="err">.Header--type-error;</span>
<span class="p">}</span>

что даёт в итоге нужное

<span class="nc">.Header</span><span class="o">,</span> <span class="nc">.Error__header</span> <span class="p">{</span><span class="err">...</span><span class="p">}</span>
<span class="nc">.Header--main</span><span class="o">,</span> <span class="nc">.Error__header</span> <span class="p">{</span><span class="err">...</span><span class="p">}</span>
<span class="nc">.Header--type-error</span><span class="o">,</span> <span class="nc">.Error__header</span> <span class="p">{</span><span class="err">...</span><span class="p">}</span>

Проблема может возникнуть, если модификаторы связаны с друг другом. @extend не добавит контекстный класс к .Header--main.Header--type-error, если разработчик сам не напишет @extend .Header--main.Header--type-error.

Для решения этой проблемы нужно будет написать функцию, которая будет делать то, что нам нужно:

<span class="nc">.Header</span> <span class="p">{</span>
  <span class="nl">font-weight</span><span class="p">:</span> <span class="nb">bold</span><span class="p">;</span>
  <span class="err">&--main</span> <span class="err">{</span>
    <span class="nl">font-family</span><span class="p">:</span> <span class="s2">'Segoe UI'</span><span class="p">,</span> <span class="nb">sans-serif</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="o">&</span><span class="nt">--type-error</span> <span class="p">{</span>
    <span class="nl">color</span><span class="p">:</span> <span class="no">red</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="o">&</span><span class="nt">--main</span><span class="o">&</span><span class="nt">--type-error</span> <span class="p">{</span>
    <span class="nl">font-size</span><span class="p">:</span> <span class="m">1.2em</span><span class="p">;</span>
  <span class="p">}</span>
<span class="err">}</span>

<span class="nt">Header</span><span class="o">(</span><span class="nt">mods</span><span class="o">)</span> <span class="p">{</span>
  <span class="err">@extend</span> <span class="err">.Header;</span>
  <span class="err">if</span> <span class="err">(match('main',</span> <span class="err">mods))</span> <span class="err">{</span>
    <span class="err">@extend</span> <span class="err">.Header--main;</span>
  <span class="p">}</span>
  <span class="nt">if</span> <span class="o">(</span><span class="nt">match</span><span class="o">(</span><span class="s2">'error'</span><span class="o">,</span> <span class="nt">mods</span><span class="o">))</span> <span class="p">{</span>
    <span class="err">@extend</span> <span class="err">.Header--type-error;</span>
  <span class="p">}</span>
  <span class="nt">if</span> <span class="o">(</span><span class="nt">match</span><span class="o">(</span><span class="s2">'main'</span><span class="o">,</span> <span class="nt">mods</span><span class="o">)</span> <span class="o">&&</span> <span class="nt">match</span><span class="o">(</span><span class="s2">'error'</span><span class="o">,</span> <span class="nt">mods</span><span class="o">))</span> <span class="p">{</span>
    <span class="err">@extend</span> <span class="err">.Header--main.Header--type-error;</span>
  <span class="p">}</span>
<span class="err">}</span>

<span class="nc">.Error__header</span> <span class="p">{</span>
  <span class="err">Header('main</span> <span class="err">error');</span>
<span class="p">}</span>

Таким образом, появляется возможность расширения блока стилями абстрактного при помощи функции с нужными параметрами.