Новые шаблоны для LS - стандарт верстки

В комментариях к моему топику про HTML-хуки было немало высказываний на тему стандартизации разрабатываемых шаблонов по LS. Хочу высказать свои соображения на эту тему.

Собственно, проблем тут две:
1) Разбивка страниц на отдельные шаблоны (файлы)
2) Именование CSS-классов

Выскажусь пока по первой проблеме.

Разбивка страниц на отдельные шаблоны

Если когда-нибудь, кто-нибудь решится-таки стандартизировать это дело, то я предлагаю подойти к нему кардинально, и рубить хвост у собачки не кусочками, а разом и одним ударом. Что я имею ввиду? А вот что — нужно, наконец, задействовать отличнейший механизм Smarty по наследованию шаблонов.

Поясню на примере. Как сейчас выглядит шаблон главной страницы:
{include file='header.tpl' menu='blog' menu_content='blog'}
{include file='topic_list.tpl'}
{include file='footer.tpl'}

При этом в шаблоне header.tpl сидит весь тег head (с двумя хуками — начало и конец), начальная часть body (тоже с хуком на начало), а также начальные части секций container, wrapper и content. Проичем, исходя из того, что так заданы их id, это уникальные секции на странице (т.е. каждая из них может встречаться на странице только один раз).

Я предлагаю оформить корневой «родительский» шаблон следующим образом:
<!DOCTYPE html>
<head>
{block name="head"}
<!-- Здесь все, что сейчас в файле header.tpl -->
{/block}
</head>
<body>
  {block name="body"}
  <div id="container" ... >
    {block name="container"}
    <header>
        {block name="header"}
        {/block}
    </header>
    <div id="wrapper">
        {block name="wrapper"}
            {block name="sidebar"}
            {/block}
            <div id="content">
                {block name="content"}
                {/block}
            </div>
        {/block}
    </div>
    <footer>
        {block name="footer"}
        {/block}
    </div>
</body>

Так мы разметили шаблон, который можно назвать, скажем, мастер-шаблон (master.tpl). И все остальные шаблоны наследуются от него. Например, на ActionIndex будет вешаться такой шаблон index.tpl:
{extends file="master.tpl"}
{block name="container" prepend}
  {include file="header_top.tpl"}
  {include file="nav.tpl"}
  <!-- А можно и HTML-код еще сюда добавить -->
  <div class="some-message">...</div>
{block}
{block name="sidebar"}
  {if !$noSidebar}
    {include file="sidebar.tpl"}
  {/if}
{block}
{block name="content"}
  {include file="topic_list.tpl"}
{block}
{block name="footer"}
  {include file='footer.tpl'}
{block}

Шаблон topic.tpl может наследоваться от шаблона index.tpl, и в нем может быть переопределен только блок content и добавленные новые блоки, нужные для всех топиков. А шаблон topic-photoset.tpl может быть наследован уже от него, и в нем будут переопределены только блоки, специфические для фотосета.

Что мы в итоге получаем:

1) В одном файле содержится основная структура документа, а значит, можно изменить макет документа, меняя только мастер-шаблон

2) Весь контент, который меняется крайне редко (например, тег head, да и footer, наверное тоже), имеет смысл поместить в мастер-шаблон, и в то же время его можно переопределить в любом дочернем шаблоне.

3) Каждый Smarty-блок заменяет два темплейт-хука (на начало и на конец блока).

4) Шаблоны наследуются по принципу «от общего к частному», постепенно уточняя и конкретизируя отдельные блоки

5) При желании можно на лету менять макет (пишем {extends file="$tpl.master"} и загоняем в $tpl.master нужный мастер-шаблон) в зависимости от конкретного случая — напр., для отображения на мобильных устройствах, для print-режима, для ajax-запросов и т.д.

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

Конечно, стандартизация CSS-классов и id элементов тоже очень нужны. Но, ИМХО, нужно начинать со структуры самих шаблонов.

36 комментариев

avatar
хорошее дополнение к вашему первому топику!
avatar
а бы сказал цель поставлена правильная но не кастомная :)

но может я читал слишком диагонально :)
avatar
но не кастомная :)
пардон, не понял
avatar
имею ввиду схема приведенная проще чем есть сейчас, но она теряет свою гибкость.
avatar
Ага, теперь я понял, что ты имел ввиду, но все равно непонятно, почему :)
В каком месте она теряет гибкость?
Смотри, есть цепочка наследования шаблонов (из моего примера):
master.tpl — index.tpl — topic.tpl — topic-photoset.tpl

И в общем случае идет, как писал, детализация «от общего к частному». Но это не значит, что так обязательно должно быть. Если вдруг тебе в topic-photoset.tpl понадобилось переопределить какой-то блок, который определен в мастер-шаблоне (например переписать весь футер имено для фотосетов) — ничто не мешает тебе это сделать!
avatar
и как мне сделать, то что вы сказали для фотосетов?

прописать условия в шаблоне фотосета if? или нет в мастере?
avatar
Нет, никаких if! В мастер-шаблоне есть блок footer, как описано в топике:
...
    <footer>
        {block name="footer"}
        {/block}
    </div>
...

В принципе, содержимое блока может быть и тут прописано уже (между {block name=«footer»}...{/block}), а можно прописать его в index.tpl, хоть так:
{extends file="master.tpl"}
...
{block name="footer"}
  <ul class="footer-list">
    <li>...</li>
    <li>...</li>
  </ul>
{block}
...

хоть так:
{extends file="master.tpl"}
...
{block name="footer"}
  {include file="footer.tpl"} <!-- здесь HTML-код футера -->
{block}
...

И на страницах, созданных по всем дочерним шаблонам, будет именно такой футер. Но в шаблоне topic-photoset.tpl можно его взять и переопределить:
{extends file="topic.tpl"}
...
{block name="footer"}
  <ul class="footer-photoset">
    <!-- другой футер -->
  </ul>
{block}
...

Вот и все
avatar
ммм вот оно что… что то мне это напоминает шаблонизатор Django :)

так ли?
avatar
Врать не буду — не знаю, с Джанго не работал
avatar
Вадим, полностью Вас поддерживаю. На данный момент логика шаблонов не понятная. А использование голого шаблона без ксс вообще нарушает строй див-верстки.
Готов принять участие в реорганизации и тестах.
avatar
Для начала хотелось бы заручиться поддержкой хотя бы нескольких человек, которые занимаются версткой под LS. Мне хоть и приходилось верстать под LS, но хотелось бы услышать и учесть мнение других людей, которые имеют практический опыт верстки именно под этот движок. Затем нужен дизайнер. Хороший дизайнер, который создаст конкурентноспособный дизайн, который будет востребован. Параллельно (пока создается дизайн) нужно выработать соглашение по именованию классов. Ну а затем — сама верстка нового дизайна по новой системе шаблонов и в соответствии с выработанным CSS-стандартом. И, разумеется, было б хорошо, если б ort эту всю затею поддержал.

Я так это вижу
avatar
Отличное предложение, готов помочь чем смогу. В своих проектах (не на ls), уже давно используем наследование шаблонов и это очень помогает при разработке и упрощает код.

Еще хочу предложить при верстке использовать методологию, которую продвигает Яндекс — БЭМ (http://ru.bem.info/method/ а здесь интересные тесты: clubs.ya.ru/bem/replies.xml?item_no=338). С ее помощью можно будет как угодно масштабировать команду, занимающуюся версткой или доработкой проекта, и можно будет решить проблему со «слетающей» версткой блоков, которые добавляют плагины. И вообще это очень удобно, когда стили в проекте строго организованы
avatar
вот еще интересная заметка про БЭМ clubs.ya.ru/bem/replies.xml?item_no=1400
avatar
Когда-то читал про БЭМ, но успел добросовестно забыть. А методология однозначно в тему. Тем более, что это именно методология, которая может быть очень гибко адаптирована под наши интересы.
avatar
Если использовать БЭМ, то можно слегка изменить схему организации шаблонов. Например, я использую такую:

По-скольку в БЭМ центральным элементом является блок, то я создал каталог с блоками, куда вместе складываю .css, .js и .tpl файлы, отвечающие за функциональность конкретного блока, получается примерно следующее:

/blocks/ — это каталог с блоками
/blocks/header/ — здесь хранятся файлы, относящиеся к блоку header, то есть:
/blocks/header/header.tpl
/blocks/header/header.css
/blocks/header/header.js

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

В экшенах же я наследую мастер шаблон и только подключаю необходимые блоки.
avatar
Тут есть над чем подумать и обсудить, но есть одна проблемка, с которой неминуемо придется столкнуться: терминология. Сейчас термин «блок» применительно к LS означает совсем не то, что «блок» в БЭМ или в Смарти :)

Я предлагал уже к выходу версии LS 1.0 закрепить более подходящий, на мой взгляд, термин — виджет. Но поддержки как-то не нашел
avatar
Для небольших проектов, которые делает один человек, проблем в создании шаблона нет. Он сам себе и кодер, и верстальщик, и дизайнер, и вебмастер. Где там, чего надо, он сам все знает. А большие проекты на ЛС, которые пишут командой, я еще не встречал.
  • aex
  • 0
avatar
Ну, во-первых, насчет «сам все знает» — количество топиков а-ля «как изменить цвет/лого/кнопочку/пр» как бы опровергает

А во-вторых, когда десятки авторов плагинов адаптируют свои творения под новый скин — это даже тяжелее, чем командная работа? ;)
avatar
А во-вторых, когда десятки авторов плагинов адаптируют свои творения под новый скин — это даже тяжелее, чем командная работа
Дада… Святые слова…
avatar
Дело не в том, сколько человек занимается проектом. Дело, скорее, в том, сколько плагиностроителей вынуждены мириться с… эээ… «кто в лес, кто — по дрова» шаблоностроителей…

Да и в проекте… Мне кажется, на данный момент любой мало-мальски серьезный проект не хило так меняет шаблоны. При чем меняется это «на коленке», т.е. «абы как» — а если выходит новая, «вкусная» версия шаблона, то «накатить» ее на уже измененный дизайн близко к невозможному.
avatar
Идея отличная и давным-давно назревшая, сейчас зоопарк из мелких файлов в шаблоне очень неочевидно структурирован. Всегда раздражало, что общий скелет страницы увидеть невозможно.

В дополнение — всё-таки про CSS. Было бы очень неплохо внедрить в LS какой-нибудь из фреймворков типа bootstrap, skeleton, foundation и тп. Плюсы:

— готовый стандартный грид, шрифты, резет, кнопки, модалы вот это всё
— responsive из коробки
— плагины, кастомизация и другие плюсы популярных обкатанных решений
— на существующие классы типа row, span*, container, hero unit проще и очевиднее будет навешивать логическую семантику шаблона, например ".row.post", ".container.header" ".row.sidebar-block" и так далее

Понятно, что никто не мешает это сделать уже сейчас, но наличие того же бутстрапа в дефолтном и девелоперском шаблоне (из которых делают шаблоны в разы чаще, чем с нуля) позволит упростить и ускорить верстку новых шаблонов.
avatar
сейчас занимаюсь версткой шаблона под дефолтный бутстрап.
avatar
я тоже. Много самописного js кода и верстки LS можно заменить на бутстраповские компоненты.
avatar
Хорошая задумка. Но разброс основных темплейтов — это ещё часть беды. Конечно, принаровившись уже с закрытыми глазами определяешь где какая часть шаблона лежит, но всё-равно удобства мало.
Более глобальная, на мой взгляд, проблема — это шаблоны плагинов. Если используется 1-2 плагина, то ещё можно побегать по папкам, но когда используется 5-10 плагинов — вот тут-то и начинается цирк. Приходится лазить по куче папок, чтобы найти нужный кусок шаблона, далее открывать в редакторе по 10-20 файлов, чтобы не возвращаться к этой рутине с передвижениями по папкам. А если ещё какие-то плагины наследуют части стандартного шаблона — то тут вообще ппц. Приходится перелопачивать всё и вся, чтобы найти какой именно плагин заменяет ту или иную часть шаблона (это, конечно, косяк со стороны разработчиков плагинов — так как можно всё на хуках делать и без делегаций полных кусков темплейта). А вообще, было бы логично, все шаблонные файлы плагинов хранить в /templates/skin/*имя скина*/plugins/ или что-нибудь типа этого. Тогда бы для фронтендеров было меньше гемороя.
avatar
было бы логично, все шаблонные файлы плагинов хранить в /templates/skin/*имя скина*/plugins/ или что-нибудь типа этого
Предложение спорное, т.к. оно облегчает жизнь одним, но усложняет другим. Даже сегодня, когда все, что касается плагина, хранится в одной папке, юзеры умудряются установить плагин не с первого раза. А уж когда по разным папкам раскидано…

Кстати, на заре становления LS, кажется, это проходили, когда еще плагинов не было, и нужно было что-то по разным папкам рассовывать. Нет, не айс.
avatar
Присоединюсь к вам. Действительно, удобнее организовать файлы и разработка шаблонов\плагинов пойдёт быстрее.
avatar
Продолжение разговора о стандартизации шаблонов для LS здесь: livestreet.ru/blog/wishlist/13125.html
avatar
Два вопроса по блокам:
1. делаем капчу внутри блока, как плагин может сменить капчу?
2. если внутри блока есть инклюд, в скомпиленном шаблоне он останется инклюдом или склеится в один файл?
  • ort
  • 0
avatar
1. Шаблон-наследник может менять содержимое любого блока любого шаблона-родителя. Напр., в шаблоне-родителе register.tpl:
<form>
  <input ... />
  {block name="captcha"}
  <img src="..." />
  {/block}
  <button>...</button>
</form>

И если мы хотим заменить блок с капчей, то создаем новый шаблон, где переопределяем блок, и этот шаблон даем на вывод:
<!-- это шаблон-наследник -->
{extends file='register.tpl'}
{block name=captcha}
<!-- здесь новый HTML-код для капчи -->
{/block}

2. Специально не проверял, но думаю, что инклюд так и останется инклюдом. Смарти собирает результирующий шаблон, заменяя блоки, но то, что в итоге сидит внутри оставшихся блоков, оно там так и остается. И я, кстати, не считаю, что надо от инклюдов совсем отказываться, наверное, в каких-то случаях их использование может быть и оправдано. Но чрезмерное их использование плохо сказывается на производительности рендеринга страницы
avatar
1. этот момент понятен, я про другой — шаблон-наследник, что за шаблон? Делегирование шаблона плагином?
avatar
Да, мы фактически возвращаемся к делегированию шаблонов. Но при использовании Смарти вер.2 это был серьезный гемор, т.к. делегированный плагином шаблон полностью заменяет исходный, и если несколько плагинов это делают — труба дело.

Но Смарти 3 ситуацию резко меняет — если использовать механизм наследования и четкую блочную верстку (это обязательное условие!), то в делегировании шаблонов нет ничего страшного. Напомню, что делегированные шаблоны ведь могут не только замещать контент блока, они могут его и добавлять — в начало блока или в конец. А могут и свои блоки определять, которых не было у родителя.
avatar
до конца не улавливаю
допустим есть шаблон регистрации с двумя разными капчами, один плагин меняет первую капчу, другой вторую — как быть? В исходном шаблоне обе капчи обернуты в блок(без инклюда).

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

Допустим, в двух плагинах задается свой шаблон (напр., register1.tpl и register2.tpl), и задается последовательное наследование, начиная от родителя register.tpl:

register.tpl -> register1.tpl -> register2.tpl

А сами шаблоны такие:
registration.tpl
<form>
  <input name="input_0">

  <!-- block captcha -->
  {block name="captcha"}<!--капча 0 -->{/block}
  <!-- /block captcha -->

  <!-- block submit -->
  {block name="submit"}
  <input type="submit">
  {/block}
  <!-- /block submit -->
</form>

registration1.tpl

  {block name="captcha"}<!--капча 1 -->{/block}
  {block name="submit" append}
  <input name="input_1">
  {/block}

registration2.tpl

  {block name="captcha"}<!--капча 2 -->{/block}

Тогда в результате получим такой код:
<form>
  <input name="input_0">

  <!-- block captcha -->
  <!-- капча 2 -->
  <!-- /block captcha -->

  <!-- block submit -->
  <input name="input_1">
  <input type="submit">
  <!-- /block submit -->
</form>

Т.е. блок captcha был заменен контентом из register2.tpl (т.к. этот шаблон последний в цепочке, в котором есть определение этого блока), а блок submit был заменен контентом из register1.tpl, а потом туда же добавлен контент блока из родительского шаблона, потому что там в определении блока есть ключевое слово append.

В общем, принцип как в ООП, когда методы потомка перекрывают методы родителя, и в дочерних перекрывающих методах могут вызывать родительские.
avatar
Забыл добавить — можно в самих шаблонах указывать родительский шаблон через директиву {extends file=«parent.tpl»}, а можно задать нужную цепочку наследования при вызове метода Смарти:
$smarty->display('extends:register.tpl|register1.tpl|register2.tpl'); 
avatar
т.е. ты предлагаешь переделать механизм делегирования шаблонов плагинами, чтобы выстраивалась цепочка по аналогии с inherit? Тогда понятно, просто об этом нет информации в топике
avatar
Да, в топике я больше про организацию самого шаблона писал, про наследование в плагинах не касался
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.