Управление css-стилями и js-скриптами

Общее использование

Управление css- и js-файлами - это одна из основных задач, которыми занимаются шаблоны в TAO. Для подключения файлов в шаблоне реализованы следующие методы:

  • use_script($filename, $options = array()) - подключение одного скрипта с указанием его параметров.
  • use_style($filename, $options = array()) - подключение одного стиля с указанием его параметров.
  • use_scripts(...) - подключение нескольких скриптов.
  • use_styles(...) - подключение нескольких стилей.

Примеры использования:

$this
	->use_script('modernizr.js')
	->use_style('bootstrap.css')
	->use_script('jquery.js', array('type' => 'lib', 'weight' => -20, 'join' => false))
	->use_style('960gs.css', array('add_timestamp' => true, 'join' => false, 'type' => 'lib', 'weight' => -10))
	->use_scripts(
		array('name' => 'backbone.js', 'minify' => false),
		array('name' => 'require.js', 'minify' => false, 'add_timestamp' => false)
	)
	->use_styles('smacss/layout.css', 'smacss/base.css', 'fonts.css');

Доступные параметры

  • type (string) - тип подключаемого файла, может быть либо app либо lib (по умолчанию app). Все файлы типа lib подключаются до app.
  • weight (float, int) - вес подключаемого файла. Чем меньше вес, тем выше в списке окажется файл и тем раньше он будет подключен.
  • join (bool) - объединять ли файл. По умолчанию все файлы объединяются в один, если включена соответствующая опция.
  • immutable (bool) - если эта опция выставлена в true при подключении файла, то повторные подключения того же файла не будут перезаписывать его опции. По умолчанию false.
  • attrs (array) - массив атрибутов тега link или script соответственно. Используется, например, для задания media=print.
  • add_timestamp (bool) - добавлять ли к url подключаемого файла timestamp (время последнего изменения файла).
  • minify (bool) - включить сжатие файла или нет.
  • place (string) - название места подключения файла, см. далее.

immutable

Параметр immutable часто используется для jquery.js, т.к. его могут подключать в разных местах, сбросив при этом вес и тип. Поэтому стандартной практикой является следующее объявление в layout-е:

$this->use_script('jquery.js', array('type' => 'lib', 'weight' => -20, 'immutable' => true, 'join' => false));

Для стилей css:

$this->use_style('print.css', array('add_timestamp' => true, 'attrs' => array('media' => 'print')));
...

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

$this
      ->use_attrs('js', array('type' => 'lib'))
      ->use_attrs('css', array('type' => 'lib'));

timestamp

По умолчанию ко всем подключаемым файлам дописывается их время модификации в виде timestamp. С помощью параметра файла add_timestamp = false можно отключить такое поведение для конкретного файла. Если необходимо отключить добавление timestamp для всех файлов, то это можно сделать с помощью вызова Core::configure.

Core::configure('Templates.HTML', array('add_timestamp' => false));

По умолчанию, эта опция добавляется как query-параметр. Это может быть не всегда приемлемо. В таком случае можно переопределить шаблон формирования ссылки, например так:

Core::configure('Templates.HTML', array('timestamp_pattern' => '/nocache/%2$d%1$s'));

По умолчанию timestamp_pattern => '%s?%d' . Шаблон ссылки задается в формате php-функции sprintf, где в качестве первого аргумента передается ссылка, а в качестве второго timestamp.

При этом соответствующее правило для корректной отдачи файлов по таким урлам должно присутствовать в .htaccess. Например, для примера выше:

RewriteRule ^nocache/\d+/(.*) $1 [L]

Определение пути к файлам

По умолчанию js-скрипты ищутся в каталоге www/scripts/, а css-стили в www/styles/. Т.е. при подключении $this->use_script('modernizr.js') будет найден файл www/scripts/modernizr.js и подключен по ссылке /scripts/modernizr.js.

Названия каталогов можно изменить с помощью Core::configure:

Core::configure('Templates.HTML', array(
	'paths' => array('css' => 'some_you_own_path/css', 'js' => 'some_you_own_path/js')
));

Переопределение библиотечных файлов

Во внутренних шаблонах TAO также подключаются различные css-, js-файлы, которые находятся в каталоге www/tao/ (обычно это symlink).

Если возникает необходимость, например, переопределить какой-то стиль в файле www/tao/styles/content.css, то необходимо создать файл с тем же именем в www/styles/content.css, и тогда вместо стандартного будет подключаться именно он.

Замечание: Стоит остерегаться случайного переопределения файлов! Если на проекте возникнет необходимость обновить jquery, то новую версию нужно положить не в www/scripts/jquery.js, а в www/scripts/jquery.v-x.x.x.js и прописать этот файл в шаблоне work.phtml. Дело в том, что админка проекта использует те же файлы, что и основной сайт, соответственно подчиняется его законам. А сама админка не совместима с более свежими версиями jquery, в результате, если для новой jquery вы будете использовать старое название, то админка перестанет корректно работать.

Подключение файлов в компоненте

При подключении файлов в компоненте они будут искаться в том числе внутри компонента. Например, для content.css

$this->use_style('content.css');

Поиск будет происходить в следующем порядке:

  • www/styles/content.css
  • www/tao/styles/content.css
  • ComponentDir/app/styles/content.css
  • ComponentDir/styles/content.css

Таким образом, можно переопределять стили и скрипты внутри компонента, а также не писать каждый раз CMS::component_static_path(). Все вышесказанное справедливо и для js-скриптов.

Замечание 1: Поиск внутри компонента осуществляется на основе, так называемого, текущего компонента CMS::$current_component_name. Текущим является тот, чей Router обрабатывается в данный момент, т.е. компонент «принявший на себя» запрос.

Замечание 2: Стоит остерегаться случайного совпадения имён файлов. Если в компоненте на одной из страниц используется базовый validation.js а на другой вы захотите использовать свой скрипт с именем ComponentDir/app/scripts/validation.js, то при создании данного файла произойдет автоматическая подмена файла валидатора с первой страницы.

Объединение css-, js-файлов

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

Для включения объединения файлов достаточно вызвать:

// инструкции должны быть раньше вызова $this['head']
$this
	->join_scripts() // для объединения js-скриптов
	->join_styles() // для объединения css-файлов;

При этом, по умолчанию будут объединяться все файлы. Что бы исключить какой-либо файл из объединения достаточно выставить для него опцию join в false или вызвать метод no_join:

$this->no_join('site.css')
$this->use_style('test.css', array('weight' => 50, 'join' => false))

Группировка файлов

Все подключаемые файлы со скриптами и стилями можно условно разделить на 2 группы:

  • подключаемые в layout'е (для всех страниц сайта).
  • подключаемые в шаблоне страницы/блока (для конкретной группы страниц).

Чаще всего большие файлы layout'ов приходится отделять от объединения с шаблонными, например:

$this->no_join('jquery.js', 'cycle.js', 'site.css')

В результате подобных манипуляций, во-первых, снова увеличивается количество подключаемых файлов, а во-вторых, в движке ТАО не предусмотрена минификация исключенных из объединения файлов (бедный site.css). Для решения образовавшихся проблем был разработан специальный механизм группировки файлов - метод join_styles_group.

$this ->join_styles_group('group1', array('site.css', 'test.css'), array('add_timestamp' => true, 'minify' => false, 'weight' => -10));

Где

  • group1 - произвольное имя группы. Влияет только на название генерируемого файла.
  • array('site.css', 'test.css') - cписок файлов, попадающих в группу. По факту, для данных файлов сначала вызывается метод no_join, выделяющий их из общего потока, а потом происходит из объединение в потоке группы. Причем объединение происходит в том порядке, в каком эти файлы указаны в списке.
  • array('add_timestamp' => true, 'minify' => false, 'weight' => -10) - опции для файла группы (такие же, что и для отдельного файла).

Стоит отметить, что основной поток объединения файлов имеет вес 0, следовательно указывая для конкретной группы положительный или отрицательный вес мы его ставим после или перед файлом основного потока соответственно.

Выделение всех скриптов, стилей из layout'а в отдельную группу тоже несет свои сложности. Проблема в том, что минификация больших файлов - ресурсоемкая операция, и проводить ее на сервере каждый раз при изменении одного из файлов не является разумным решением. Для решения данной ситуации рекомендуется объединять неизменяемые файлы плагинов в одну группу, а «самописные» файлы в другую. Например:

$this->use_style('fonts.css', array('weight' => -20, 'add_timestamp' => true));
$this->use_style('fancybox.css', array('weight' => -10, 'add_timestamp' => false));
$this->use_style('site.css', array('weight' => -5, 'add_timestamp' => true));
$this->use_style('media.css', array('weight' => -4, 'add_timestamp' => true));
$this->use_script('jquery.js', array('type' => 'lib','weight' => -20, 'immutable' => true, 'join' => false, 'add_timestamp' => false));
$this->use_script('fancybox.pack.js', array('type' => 'lib','weight' => -5, 'immutable' => true, 'join' => false, 'add_timestamp' => false));
$this->use_script('cookie.js', array('weight' => 0, 'add_timestamp' => true));
$this->use_script('common.js', array('weight' => 20, 'add_timestamp' => true));

$this->join_styles_group('layouts', array('fonts.css','site.css','media.css','fancybox.css'), array('add_timestamp' => false, 'minify' => true, 'weight' => -100));
$this->join_scripts_group('plygins', array('jquery.js', 'fancybox.pack.js', 'cookie.js'), array('add_timestamp' => false, 'minify' => true, 'weight' => -100, 'type' => 'lib'));
$this->join_scripts_group('layouts', array('common.js'), array('add_timestamp' => false, 'minify' => true, 'weight' => -10, 'type' => 'app'));
$this->join_styles()->minify_styles();
$this->join_scripts()->minify_scripts();

Сжатие css-, js-файлов

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

composer.phar install

И добавить в index.php:

include('../vendor/autoload.php');

Внимание: перед запуском установки/обновления composer необходимо проверить список зависимостей composer.json, в нем должна быть строчка ' "nitra/php-min": "dev-master" ''.

После установки подключаем сжатие в шаблонах:

$this
	->minify_scripts() // для js-скриптов
	->minify_styles(); // для css-файлов

Если какой-то файл или группу не нужно минифицировать, то можно выставить опцию minify в false.

События Events при объединении и минификации файлов

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

templates.assets.preprocess ($path, $data, $content)

  • $path - путь к формируемому файлу.
  • $data - массив параметров.
  • $content - содержимое файла.

Событие, вызываемое при подключении css- или js-файла. Позволяет добавить какую-либо обработку перед формированием списка файлов.

templates.assets.postprocess ($path, $data, $content)

  • $path - путь к формируемому файлу.
  • $data - массив параметров.
  • $content - содержимое файла.

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

Решение для inline-скриптов

У шаблона имеется несколько встроенных блоков:

  • content - содержимое встроенного шаблона.
  • head - заголовки.
  • script - inline скрипты, попадают в head.
  • styles - inline стили, попадают в head.

Для добавления inline-скриптов можно воспользоваться следующей конструкцией:

<?php $this->js("alert('Hello');"); ?>

<?php $this->begin('script'); ?>
$(function() {
	alert('World');
});
<?php $this->end('script'); ?>

Кроме того, для передачи параметров из php в js, есть метод add_scripts_settings:

// в шаблоне
$this->add_scripts_settings(array('fields' => 'gallery' => array('name' => 'test')));

// в js-скрипте
 alert(TAO.settings.fields.gallery.name);

Подключение файлов за пределами docroot

Иногда возникает необходимость подключить стиль или скрипт за пределами docroot-а, например, из каталога компонента или директории app. Для этого к пути файла необходимо добавить file://

$this->use_styles('file://../app/scripts/main.js');

Подключение файлов внизу страницы

Для подключения файлов внизу страницы необходимо при подключении передать параметр place => 'bottom'.

$this->use_script('name.js', array('weight' => 20, 'place' => 'bottom'));

А внизу страницы добавляем вставку:

%assets{bottom}

Параметр place не ограничевается единственным значением bottom. При необходимости можно создать любое количество мест для подключения скриптов. Обычно хватает одного дополнительного места - bottom, перед закрывающим тегом body.

04.02.2015
Все статьи