Новые шаблоны для LS - стандарт верстки
В комментариях к моему топику про HTML-хуки было немало высказываний на тему стандартизации разрабатываемых шаблонов по LS. Хочу высказать свои соображения на эту тему.
Собственно, проблем тут две:
1) Разбивка страниц на отдельные шаблоны (файлы)
2) Именование CSS-классов
Выскажусь пока по первой проблеме.
Если когда-нибудь, кто-нибудь решится-таки стандартизировать это дело, то я предлагаю подойти к нему кардинально, и рубить хвост у собачки не кусочками, а разом и одним ударом. Что я имею ввиду? А вот что — нужно, наконец, задействовать отличнейший механизм Smarty по наследованию шаблонов.
Поясню на примере. Как сейчас выглядит шаблон главной страницы:
При этом в шаблоне header.tpl сидит весь тег head (с двумя хуками — начало и конец), начальная часть body (тоже с хуком на начало), а также начальные части секций container, wrapper и content. Проичем, исходя из того, что так заданы их id, это уникальные секции на странице (т.е. каждая из них может встречаться на странице только один раз).
Я предлагаю оформить корневой «родительский» шаблон следующим образом:
Так мы разметили шаблон, который можно назвать, скажем, мастер-шаблон (master.tpl). И все остальные шаблоны наследуются от него. Например, на ActionIndex будет вешаться такой шаблон index.tpl:
Шаблон 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 элементов тоже очень нужны. Но, ИМХО, нужно начинать со структуры самих шаблонов.
Собственно, проблем тут две:
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 комментариев
но может я читал слишком диагонально :)
В каком месте она теряет гибкость?
Смотри, есть цепочка наследования шаблонов (из моего примера):
master.tpl — index.tpl — topic.tpl — topic-photoset.tpl
И в общем случае идет, как писал, детализация «от общего к частному». Но это не значит, что так обязательно должно быть. Если вдруг тебе в topic-photoset.tpl понадобилось переопределить какой-то блок, который определен в мастер-шаблоне (например переписать весь футер имено для фотосетов) — ничто не мешает тебе это сделать!
прописать условия в шаблоне фотосета if? или нет в мастере?
В принципе, содержимое блока может быть и тут прописано уже (между {block name=«footer»}...{/block}), а можно прописать его в index.tpl, хоть так:
хоть так:
И на страницах, созданных по всем дочерним шаблонам, будет именно такой футер. Но в шаблоне topic-photoset.tpl можно его взять и переопределить:
Вот и все
так ли?
Готов принять участие в реорганизации и тестах.
Я так это вижу
Еще хочу предложить при верстке использовать методологию, которую продвигает Яндекс — БЭМ (http://ru.bem.info/method/ а здесь интересные тесты: clubs.ya.ru/bem/replies.xml?item_no=338). С ее помощью можно будет как угодно масштабировать команду, занимающуюся версткой или доработкой проекта, и можно будет решить проблему со «слетающей» версткой блоков, которые добавляют плагины. И вообще это очень удобно, когда стили в проекте строго организованы
По-скольку в БЭМ центральным элементом является блок, то я создал каталог с блоками, куда вместе складываю .css, .js и .tpl файлы, отвечающие за функциональность конкретного блока, получается примерно следующее:
/blocks/ — это каталог с блоками
/blocks/header/ — здесь хранятся файлы, относящиеся к блоку header, то есть:
/blocks/header/header.tpl
/blocks/header/header.css
/blocks/header/header.js
Таким образом, я могу очень быстро ориентироваться в достаточно большом и даже незнакомом проекте.
В экшенах же я наследую мастер шаблон и только подключаю необходимые блоки.
Я предлагал уже к выходу версии LS 1.0 закрепить более подходящий, на мой взгляд, термин — виджет. Но поддержки как-то не нашел
А во-вторых, когда десятки авторов плагинов адаптируют свои творения под новый скин — это даже тяжелее, чем командная работа? ;)
Да и в проекте… Мне кажется, на данный момент любой мало-мальски серьезный проект не хило так меняет шаблоны. При чем меняется это «на коленке», т.е. «абы как» — а если выходит новая, «вкусная» версия шаблона, то «накатить» ее на уже измененный дизайн близко к невозможному.
В дополнение — всё-таки про CSS. Было бы очень неплохо внедрить в LS какой-нибудь из фреймворков типа bootstrap, skeleton, foundation и тп. Плюсы:
— готовый стандартный грид, шрифты, резет, кнопки, модалы вот это всё
— responsive из коробки
— плагины, кастомизация и другие плюсы популярных обкатанных решений
— на существующие классы типа row, span*, container, hero unit проще и очевиднее будет навешивать логическую семантику шаблона, например ".row.post", ".container.header" ".row.sidebar-block" и так далее
Понятно, что никто не мешает это сделать уже сейчас, но наличие того же бутстрапа в дефолтном и девелоперском шаблоне (из которых делают шаблоны в разы чаще, чем с нуля) позволит упростить и ускорить верстку новых шаблонов.
Более глобальная, на мой взгляд, проблема — это шаблоны плагинов. Если используется 1-2 плагина, то ещё можно побегать по папкам, но когда используется 5-10 плагинов — вот тут-то и начинается цирк. Приходится лазить по куче папок, чтобы найти нужный кусок шаблона, далее открывать в редакторе по 10-20 файлов, чтобы не возвращаться к этой рутине с передвижениями по папкам. А если ещё какие-то плагины наследуют части стандартного шаблона — то тут вообще ппц. Приходится перелопачивать всё и вся, чтобы найти какой именно плагин заменяет ту или иную часть шаблона (это, конечно, косяк со стороны разработчиков плагинов — так как можно всё на хуках делать и без делегаций полных кусков темплейта). А вообще, было бы логично, все шаблонные файлы плагинов хранить в /templates/skin/*имя скина*/plugins/ или что-нибудь типа этого. Тогда бы для фронтендеров было меньше гемороя.
Кстати, на заре становления LS, кажется, это проходили, когда еще плагинов не было, и нужно было что-то по разным папкам рассовывать. Нет, не айс.
1. делаем капчу внутри блока, как плагин может сменить капчу?
2. если внутри блока есть инклюд, в скомпиленном шаблоне он останется инклюдом или склеится в один файл?
И если мы хотим заменить блок с капчей, то создаем новый шаблон, где переопределяем блок, и этот шаблон даем на вывод:
2. Специально не проверял, но думаю, что инклюд так и останется инклюдом. Смарти собирает результирующий шаблон, заменяя блоки, но то, что в итоге сидит внутри оставшихся блоков, оно там так и остается. И я, кстати, не считаю, что надо от инклюдов совсем отказываться, наверное, в каких-то случаях их использование может быть и оправдано. Но чрезмерное их использование плохо сказывается на производительности рендеринга страницы
Но Смарти 3 ситуацию резко меняет — если использовать механизм наследования и четкую блочную верстку (это обязательное условие!), то в делегировании шаблонов нет ничего страшного. Напомню, что делегированные шаблоны ведь могут не только замещать контент блока, они могут его и добавлять — в начало блока или в конец. А могут и свои блоки определять, которых не было у родителя.
допустим есть шаблон регистрации с двумя разными капчами, один плагин меняет первую капчу, другой вторую — как быть? В исходном шаблоне обе капчи обернуты в блок(без инклюда).
Просто где то проскакивало, что не нужно было городить блочные хука, а сразу использовать блоки смарти. Вот такой кейс(разные плагины меняют что то в одном шаблоне) блочные хуки смогут обработать, а блоки смарти пока не понимаю как.
Допустим, в двух плагинах задается свой шаблон (напр., register1.tpl и register2.tpl), и задается последовательное наследование, начиная от родителя register.tpl:
register.tpl -> register1.tpl -> register2.tpl
А сами шаблоны такие:
registration.tpl
registration1.tpl
registration2.tpl
Тогда в результате получим такой код:
Т.е. блок captcha был заменен контентом из register2.tpl (т.к. этот шаблон последний в цепочке, в котором есть определение этого блока), а блок submit был заменен контентом из register1.tpl, а потом туда же добавлен контент блока из родительского шаблона, потому что там в определении блока есть ключевое слово append.
В общем, принцип как в ООП, когда методы потомка перекрывают методы родителя, и в дочерних перекрывающих методах могут вызывать родительские.