Хорошие верстальщики отправляются на небеса, а плохие куда захотят. Или — почему БЭМ не приносит счастья?
Все мы привыкли слышать поучительные разговоры о том "как надо верстать", или о том "как не надо". Иногда понятие "как надо" строится на объективных фактах, иногда на фактах которые скрыты где-то в глубине проблемы. Всё вместе это образует некоторые правила вёрстки, которыми и руководствуется верстальщик в своей повседневной работе.
Первоначально правила вёрстки были сродни искусству - ты мог делать что угодно, и никто тебя не останавливал, кроме возможностей веб-браузеров естественно. Потом эти правила превратились в что-то вроде хороших советов для домохозяек. Ты прибегал к тому или иному совету раз от раза, просто что бы сделать свою работу более интересной, почувствовать себя переоткрывателем чего-то. Но это было не обязательно. Вообще это был довольно длительный период веба, но и всё-таки ему настал конец. Появился тренд на догматизацию, свободы становилось всё меньше и меньше - и в какой-то момент появился БЭМ .
Вёрстка должна быть увлекательной
Эту статью мне захотелось написать, после ознакомления со статьёй «Верстка для самых маленьких. Верстаем страницу по БЭМу».
Сразу оговорюсь, что цель моей статьи не научить «верстать правильно», хотя большая часть посвящена именно вёрстке, а дать верстальщикам, разработчикам, дизайнерам и руководителям немного другой взгляд на проблему вёрстки и вообще программирования UI для современного веба.
Начну с того, что являюсь приверженцем тех взглядов, что главное в командной раработке это максимально возможная свобода действий каждого участника разработки. Члены команды не должны чувствовать себя связаны каким-то методологиями, догмами и другими религиозными взглядами. Всё это очень сильно вредит мотивации, которая и является единственным двигателем проекта. По сути руководствуясь только своей мотивацией matz сделал Ruby, Резинг jQuery, а сэр Тим Бернерс-Ли HTML – как мы видим эти проекты до сих играют немаловажную роль в вебе.
Как же повысить мотивацию и развязать руки тем кто работает с фронтендом в веб-проекте и при этом не снизить качество разработки?
Ответ довольно прост – всего этого можно легко добиться делая ставку на современные технологии и тенденции в мировом вебе.
Отказ от HTML в пользу haml/slim/jade делает вёрстку проще и выразительней
Несмотря на то что HTML создавался для облегчения вёрстки и в 1980-е был самым что ни на есть высокоуровневым языком, сейчас ситуация полностью противоположная. HTML стал слишком сложным и специфичным, смысл верстать в HTML такой же, как программировать в машинных кодах, когда под рукой ассемблер.
К тому же в HTML как наследнике SGML изрядно извращена сама идея GML. Для этого можно сравнить примеры вёрстки на GML/HTML/slim.
GML-script, 1969 год.
:h1.Chapter 1: Introduction
:p.GML supported hierarchical containers, such as
:ol
:li.Ordered lists (like this one),
:li.Unordered lists, and
:li.Definition lists
:eol.
as well as simple structures.
:p.Markup minimization (later generalized and formalized in SGML),
allowed the end-tags to be omitted for the "h1" and "p" elements.
Современный HTML
<h1> Chapter 1: Intruduction </h1>
<ol>
<li> Ordered lists (like this one),
<li> Unordered lists, and
<li> Definition lists
</ol>
<p>as well as simple structures.</p>
<p>Markup minimization (later generalized and formalized in SGML),
allowed the end-tags to be omitted for the "h1" and "p" elements
</p>
Ruby Slim, 2011
h1 Chapter 1: Intruduction
ol
li Ordered lists (like this one),
li Unordered lists, and
li Definition lists
p as well as simple structures.
p Markup minimization (later generalized and formalized in SGML),
allowed the end-tags to be omitted for the "h1" and "p" elements
Как видим slim больше соответствует первоначальной идеи GML чем современный HTML. Так что использование современных шаблонизаторов делает код читабельнее и лаконичнее, он одинаково понятен и верстальщику и программисту. В нём легко выделить семантику. Более того, многие шаблонизаторы поддерживают включения и нативного HTML-кода, так что есть возможность делать гибридные шаблоны, особенно если в проекте много унаследованной вёрстки.
Вёрстка является частью экосистемы проекта, нет смысла её отделять
Руководители и заказчики частенько желают видеть результаты вёрстки в отдельных html-файлах. Вёрстка сразу в рабочем проекте кажется им надувательством. Поэтому верстальщики вынуждены копи-пастить десятки раз layout из одного файла в другой что бы получить постраничный html-прототип проекта. Такой подход приводит к тому что в вёрстке содержится куча ошибок в разных файлах и эти ошибки приходится исправлять программистам.
Вёрстка неотделима от проекта. Точно так же как контроллеры неотделимы от видов. Нельзя взять и папочку views из одного проекта и перекинуть в другой, так что бы всё заработало. Поэтому не стоит питать иллюзий и насчёт вёрстки.
Отказ от CSS в пользу LESS/SASS развязывает руки
В CSS заложены довольно строгие ограничения, в частности в нативном CSS нельзя осуществить манипуляции, которые в программировании называют наследованием. Т.е. один класс не может наследовать свойства другого класса, единственный способ распространить один и тот же стиль для разных элементов это создать общий селектор. Так что при программировании стилей всегда приходится выбирать между общностью селекторов и изолированностью стиля. К частью в LESS легко решает проблемы за счёт гибкой системы mixin-ов.
Приведу небольшой пример. Пусть в проекте есть несколько классов элементов одного цвета с одинаковым шрифтом, но при этом имеющие разную семантику и расположенные в разных частях страницы:
/* однотипные классы */
.button{
background-color: blue;
color: white;
font-family: Arial;
font-size: 12px;
}
.header{
background-color: blue;
color: white;
font-family: Arial;
font-size: 12px;
}
.footer{
background-color: blue;
color: white;
font-family: Arial;
font-size: 12px;
}
В LESS можно просто выделить mixin с названием blue-arial-element;
blue-arial-element{
// в less можно делать строчные комментарии
// поэтому property желательно писать «в столбик»
// background-color: black;
background-color: blue;
color: white;
font-family: Arial;
font-size: 12px;
}
.button{
.blue-arial-element;
}
.header{
.blue-arial-element;
}
.footer{
.blue-arial-element;
}
Более того, этот mixin несмотря на то что и выглядит как класс, не будет засвечен в HTML-коде. Так что если наступит время когда от него придётся избавиться, его можно будет удалить из styles.less без изменения кода HTML. В классическом же решении, классы приходится выковыривать из всех мест где они появляются.
Из таких mixin-ов можно (и нужно) сооружать целые библиотеки стилей, которые позволяют легко переносить стили из одного проекта в другой.
Понимание того что ты делаешь, важнее того как ты это делаешь
Можно ли сходу сказать что происходит в этом html-коде?
<div class="b-company">
<div class="b-company__header">
<div class="b-item-head">
<div class=b-item-head__img>
<img src="img/sq.png">
</div><div class="b-item-head__text">ABOUT WHITESQUARE</div>
</div>
</div>
<div class="b-company__content">
<div class="b-content">
<img class="b-content__img" src="img/middle.png"/>
<div class="b-content__text">
In ultricies pellentesque massa a porta. Aliquam
ipsum enim, hendrerit ut porta nec, ullamcorper et
nulla. In eget mi dui, sit amet scelerisque nunc.
Aenean augue arcu, convallis ac vulputate vitae, mollis
non lectus. Donec hendrerit lacus ac massa ornare
hendrerit sagittis lacus tempor. Vivamus et dui et
neque accumsan varius et ut erat.
Enean augue arcu, convallis ac ultrices.
</div>
<div class="b-content__link">
<p><a href="#" class="b-link">Read more</a></p>
</div>
</div>
</div>
</div>
Очевидно что этот код немного запутан. Если верить статье упомянутой во введении, то код создаёт небольшую статью с заголовком, фотографией и текстом-описанием. Можно ли сделать эту вёрстку лучше? Наверное было бы лучше если бы не приходилось тратить время на её расшифровку. Другими словами, это выглядело бы примерно так:
article
div.title
h1 About whitesquare
div.filler
figure: img width="136" height="136" alt="" src="sample.png"
p
| Lorem ipsum dolor sit amet, consectetur adipiscing elit.
| Pellentesque dictum metus ligula, vitae bibendum augue
| fermentum non. Fusce euismod libero eu lectus scelerisque
| hendrerit. Nam vel fermentum tellus, vel lobortis felis.
| Phasellus dolor ipsum, vehicula ac justo quis,
| scelerisque tempus nibh.
a Read more
Оказывается, что вёрстка может говорить сама за себя. И нет никаких препятствий что бы не делать её такой. Можно много времени уделять разговорам о повторном использовании кода, но все эти разговоры не имеют большого значения если на выходе получается нечитабельный код. Сложный разросшийся код это явный признак того, что в проекте что-то не так. И нет причин, что бы в вёрстке веб-проектов были какие-то другие принципы. Верстальщики такие же люди как и программисты, никто не любит чувствовать дискомфорт на своём рабочем месте. К тому же разросшаяся вёрстка доставляет страдание всем — и верстальщикам, и программистам.
BEMLESS, или верстаем как хочется
Представим на некоторое время что не существует никаких правил вёрстки и подобных ограничений. У нас есть только макет, тот же Corporate Blue и сервер Sinatra со следующими настройками:
Gemfile
source 'https://rubygems.org'
ruby '1.9.3'
gem 'sinatra'
gem 'slim'
gem 'therubyracer'
gem 'less'
config.ru
require './app'
run Sinatra::Application
И само приложение app.rb
require 'sinatra'
require 'slim'
require 'less'
set :views, :less => 'assets/stylesheets', :default => 'views'
helpers do
def find_template(views, name, engine, &block)
_, folder = views.detect { |k,v| engine == Tilt[k] }
folder ||= views[:default]
super(folder, name, engine, &block)
end
end
get '/' do
slim :index
end
get '/:style.css' do
less params[:style].to_sym
end
get '/:image.png' do
send_file File.join(settings.root, "assets/images/#{params[:image]}.png")
end
Как видно, настройки проекта и сам проект занимает намного меньше кода чем типичный html-заголовок.
В проекте три хука, первый для индекс-страницы которая называется index.slim и лежит в папке views, второй и третий подгружают ресурсы вида *.css
и *.png
из соответствующих папок. (Чуть ниже будут приведены ссылки и на github проект готовый к отправке на heroku.)
В общем проект в sublime выглядит примерно так:
Теперь пришло время обратиться к макету:
Я не буду акцентироваться на том, что и как надо верстать, просто буду описывать шаг за шагом что я вижу в slim-код.
Вёрстка каркаса страницы
Сначала необходимо добавить заголовки (обычно они лежат в layout, но т. к. приложение одностраничное, то запишу прям в index.slim):
doctype html
html
head
meta charset="utf-8"
title Whitesquare
link rel="stylesheet" href="/styles.css"
link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Oswald:400,300"
/[if lt IE 9]
script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"
Затем я вижу следующие элементы: хедерлайн и хедер. Это верхняя часть сайта. Заверстаю её в том порядке как и в макете:
hr
header
a.logo href="/": img src="logo.png"
div.search
input type="text" placeholder="Search"
div.button Go
Как нетрудно заметить, это несколько лаконичнее чем в БЭМ:
<div class="b-page__line">
<div class="b-head">
<div class="b-head__logo">
<div class="b-logo">
<a href="#"><img class="b-logo__img" src="img/Logo.png"/></a>
</div>
</div>
<div class="b-head__search">
<div class="b-search">
<div class="b-search__input">
<input type="text" class="b-input b-input_search" placeholder="Search">
</div><div class="b-search__input"><div class="b-button">GO</div>
</div>
</div>
</div>
</div>
</div>
Далее следует навбар и слайдер. Вёрстка по тому же принципу — для навбара берётся элемент nav, список оформляется в список, ссылки в ссылки. Т.е. вёрстка становится средством описания иерархии элементов, то что находится внутри должно вкладываться, то что находится рядом должно быть рядом. Все элементы отражают ровно то, что увидит потом конечный пользователь. Если такого элемента нет, то используется наиболее близкий по семантике с соответствующим классом.
nav
ul
li: a href="#" Home
li: a.active href="#" About us
li: a href="#" Services
li: a href="#" Partners
li: a href="#" Projects
li: a href="#" Careers
li: a href="#" Contact
div.slider
div.screen
ul
li
div.index 1
div.title Lorem ipsum dolop
li.active
div.index 2
div.title Ultricies peletesque
li
div.index 3
div.title Aliquam ipsum
li
div.index 4
div.title Nullam sed maurus ut
После навбара идёт главный блок со статьями:
div.main
div.big-news
article
div.title
h1 About whitesquare
div.filler
figure: img width="136" height="136" alt="" src="sample.png"
p
| Lorem ipsum dolor sit amet, consectetur adipiscing elit.
| Pellentesque dictum metus ligula, vitae bibendum augue
| fermentum non. Fusce euismod libero eu lectus scelerisque
| hendrerit. Nam vel fermentum tellus, vel lobortis felis.
| Phasellus dolor ipsum, vehicula ac justo quis, scelerisque
| tempus nibh.
article
div.title
h1 A word from our CEO
div.filler
figure: img width="136" height="136" alt="" src="sample.png"
p: i
| "Lorem ipsum dolor sit amet, consectetur adipiscing elit.
| Pellentesque dictum metus ligula, vitae bibendum augue
| ermentum non. Fusce euismod libero eu lectus scelerisque
| hendrerit. Nam vel fermentum tellus, vel lobortis felis.
| Phasellus dolor ipsum, vehicula ac justo quis, scelerisque
| tempus nibh."
p Yane Naumovski, CEO
div.news
article
div.title
h1 Service
div.filler
p
| Lorem ipsum dolor sit amet, consectetur adipiscing elit.
| Pellentesque dictum metus ligula, vitae bibendum augue
| fermentum non. Fusce euismod libero eu lectus scelerisque
| hendrerit. Nam vel fermentum tellus, vel lobortis felis.
| Phasellus dolor ipsum, vehicula ac justo quis, scelerisque
| tempus nibh. Lorem ipsum dolor sit amet, consectetur
| adipiscing elit. Pellentesque dictum metus ligula, vitae
| bibendum augue fermentum non. Fusce euismod libero eu
| lectus scelerisque hendrerit. Nam vel fermentum tellus,
| vel lobortis felis. Phasellus dolor ipsum, vehicula ac
| justo quis, scelerisque tempus nibh.
article
div.title
h1 Our teams
div.filler
figure: img width="36" height="36" alt="" src="sample.png"
p
| Lorem ipsum dolor sit amet, consectetur adipiscing elit.
| Pellentesque dictum metus ligula, vitae bibendum augue
| fermentum non.
figure: img width="36" height="36" alt="" src="sample.png"
p
| Lorem ipsum dolor sit amet, consectetur adipiscing elit.
| Pellentesque dictum metus ligula, vitae bibendum augue
| fermentum non.
figure: img width="36" height="36" alt="" src="sample.png"
p
| Lorem ipsum dolor sit amet, consectetur adipiscing elit.
| Pellentesque dictum metus ligula, vitae bibendum augue
| fermentum non.
article
div.title
h1 24/7/365 SUPPORT
div.filler
p
| Lorem ipsum dolor sit amet, consectetur adipiscing elit.
| Pellentesque dictum metus ligula, vitae bibendum augue
| fermentum non. Fusce euismod libero eu lectus scelerisque
| hendrerit. Nam vel fermentum tellus, vel lobortis felis.
| Phasellus dolor ipsum, vehicula ac justo quis, scelerisque
| tempus nibh.
div.clients
div.title
h1 Our Clients
div.filler
a href="#": img alt="client1" src="client1.png"
a href="#": img alt="client2" src="client2.png"
a href="#": img alt="client3" src="client3.png"
a href="#": img alt="client4" src="client4.png"
a href="#": img alt="client5" src="client5.png"
a href="#": img alt="client6" src="client6.png"
a href="#": img alt="client7" src="client7.png"
Этот участок кода уже выглядит намного более запутанным, но это конечно поверхностное впечатление, из-за большого количества текста и однотипных элементов, в production или при наличии fake-генераторов (что сейчас являются довольно распространённой практикой) код будет выглядеть намного симпатичнее:
div.main
div.big-news
article
div.title
h1=@about.title
div.filler
figure: img width="136" height="136" alt="" src=@about.photo
p=@about.text
article
div.title
h1=@ceo.title
div.filler
figure: img width="136" height="136" alt="" src=@ceo.photo
p: i=@ceo.quote
p=@ceo.name
div.news
article
div.title
h1=@service.title
div.filler
p=@service.text
article
div.title
h1 Our teams
div.filler
- @team.each do |emp|
figure: img width="36" height="36" alt="" src=emp.photo
p=emp.title
article
div.title
h1 24/7/365 SUPPORT
div.filler
p=@support.text
div.clients
div.title
h1 Our Clients
div.filler
- @clients.each do |client|
a href="#": img alt=client.title src=client.logo
Теперь сравним с тем, что предлагает БЭМ:
<div class="b-page__line">
<div class="b-main">
<div class="b-main__item">
<div class="b-company">
<div class="b-company__header">
<div class="b-item-head">
<div class=b-item-head__img>
<img src="img/sq.png">
</div><div class="b-item-head__text">ABOUT WHITESQUARE</div>
</div>
</div>
<div class="b-company__content">
<div class="b-content">
<img class="b-content__img" src="img/middle.png"/>
<div class="b-content__text">
In ultricies pellentesque massa a porta. Aliquam ipsum
enim, hendrerit ut porta nec, ullamcorper et nulla. In
eget mi dui, sit amet scelerisque nunc. Aenean augue arcu,
convallis ac vulputate vitae, mollis non lectus. Donec
hendrerit lacus ac massa ornare hendrerit sagittis lacus
tempor. Vivamus et dui et neque accumsan varius et ut erat.
Enean augue arcu, convallis ac ultrices.
</div>
<div class="b-content__link">
<p><a href="#" class="b-link">Read more</a></p>
</div>
</div>
</div>
</div>
</div>
<div class="b-main__item">
<div class="b-company">
<div class="b-company__header">
<div class="b-item-head">
<div class="b-item-head__img">
<img src="img/sq.png">
</div>
<div class="b-item-head__text">A WORD FROM OUR CEO</div>
</div>
</div>
<div class="b-company__content">
<div class="b-content">
<img class="b-content__img" src="img/middle.png"/>
<div class="b-content__text">
In ultricies pellentesque massa a porta. Aliquam
ipsum enim, hendrerit ut porta nec, ullamcorper
et nulla. In eget mi dui, sit amet scelerisque
nunc. Aenean augue arcu, convallis ac vulputate
vitae, mollis non lectus. Donec hendrerit lacus
ac massa ornare hendrerit sagittis lacus tempor.
Vivamus et dui et neque accumsan varius et ut erat.
Enean augue arcu, convallis ac ultrices.
</div>
<div class="b-content__link">
<p>Yane Naumoski, CEO</p>
</div>
</div>
</div>
</div>
</div>
<div class="b-main__item b-main__item_small">
<div class="b-company">
<div class="b-company__header">
<div class="b-item-head">
<div class="b-item-head__img">
<img src="img/sq.png">
</div><div class="b-item-head__text ">SERVICES</div>
</div>
</div>
<div class="b-company__content">
<div class="b-content">
<div class="b-content__text">
In ultricies pellentesque massa a porta. Aliquam
ipsum enim, hendrerit ut porta nec, ullamcorper
et nulla. In eget mi dui, sit amet scelerisque
nunc. Aenean augue arcu, convallis ac vulputate
vitae, mollis non lectus. Donec hendrerit lacus
ac massa ornare hendrerit sagittis lacus tempor.
Vivamus et dui et neque accumsan varius et ut
erat. Enean augue arcu, convallis ac ultrices.
</div>
<div class="b-content__link">
<p><a href="#" class="b-link">Read more</a></p>
</div>
</div>
</div>
</div>
</div>
<div class="b-main__item b-main__item_small">
<div class="b-company">
<div class="b-company__header">
<div class="b-item-head">
<div class="b-item-head__img">
<img src="img/sq.png">
</div><div class="b-item-head__text ">OUR TEAM</div>
</div>
</div>
<div class="b-company__content">
<div class="b-content">
<div class="b-context__team">
<ul class="b-team">
<li class="b-team__item">
<div class="b-teammate">
<img class="b-teammate__img" src="img/small.png">
<div class="b-teammate__head">
Lorem Ipsum
</div>
<div class="b-teammate__text">
In ultricies pellentesque massa a porta.
Aliquam ipsum enim, hendrerit ut porta nec
</div>
</div>
</li>
<li class="b-team__item">
<div class="b-teammate">
<img class="b-teammate__img" src="img/small.png">
<div class="b-teammate__head">
Lorem Ipsum
</div>
<div class="b-teammate__text">
In ultricies pellentesque massa a porta.
Aliquam ipsum enim, hendrerit ut porta nec
</div>
</div>
</li>
<li class="b-team__item">
<div class="b-teammate">
<img class="b-teammate__img" src="img/small.png">
<div class="b-teammate__head">
Lorem Ipsum
</div>
<div class="b-teammate__text">
In ultricies pellentesque massa
a porta. Aliquam ipsum enim,
hendrerit ut porta nec
</div>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<div class="b-main__item b-main__item_small">
<div class="b-company">
<div class="b-company__header">
<div class="b-item-head">
<div class="b-item-head__img">
<img src="img/sq.png">
</div><div class="b-item-head__text ">24/7/365 SUPPORT</div>
</div>
</div>
<div class="b-company__content">
<div class="b-content">
<div class="b-content__text">
In ultricies pellentesque massa a porta.
Aliquam ipsum enim, hendrerit ut porta nec,
ullamcorper et nulla. In eget mi dui,
sit amet scelerisque nunc. Aenean augue
arcu, convallis ac vulputate vitae, mollis
non lectus. Donec hendrerit lacus ac massa
ornare hendrerit sagittis lacus tempor.
Vivamus et dui et neque accumsan varius
et ut erat. Enean augue arcu, convallis
ac ultrices.
</div>
<div class="b-content__link">
<p><a href="#" class="b-link">Read more</a></p>
</div>
</div>
</div>
</div>
</div>
<div class="b-main__item b-main__item_long">
<div class="b-company">
<div class="b-company__header">
<div class="b-item-head">
<div class="b-item-head__img">
<img src="img/sq.png">
</div><div class="b-item-head__text ">OUR CLIENTS</div>
<div class="b-item-head__white-space"></div>
</div>
</div>
<div class="b-company__content">
<div class="b-companies">
<img class="b-companies__img" src="img/middle.png">
<img class="b-companies__img" src="img/middle.png">
<img class="b-companies__img" src="img/middle.png">
<img class="b-companies__img" src="img/middle.png">
<img class="b-companies__img" src="img/middle.png">
<img class="b-companies__img" src="img/middle.png">
</div>
</div>
</div>
</div>
</div>
<div class=g-clear></div>
</div>
Здесь я думаю комментарии излишни. Остался футер, его верстаю в такой же манере:
footer
div.info
div.twitter-feed
h1 Twitter feed
p
a href="#" 23 oct
br
| Fusce euismod libero eu lectus scelerisque
| hendrerit. Nam vel fermentum tellus, vel
| lobortis felis. Phasellus dolor ipsum,
| vehicula ac justo quis, scelerisque tempus nibh.
div.sitemap
h1 Sitemap
div.column
a href="#" Home
a href="#" About
a href="#" Service
div.column
a href="#" Partners
a href="#" Support
a href="#" Contact
div.social-networks
h1 Social networks
div.big-icons
a.twitter href="#": img alt="twitter logo" src="social-twitter.png"
a.facebook href="#": img alt="facebook logo" src="social-facebook.png"
a.gplus href="#": img alt="gplus logo" src="social-gplus.png"
div.small-icons
a.vimeo href="#": img alt="vimeo logo" src="social-vimeo.png"
a.flickr href="#": img alt="flickr logo" src="social-flickr.png"
a.inst href="#": img alt="instagram logo" src="social-inst.png"
a.rss href="#": img alt="rss logo" src="social-rss.png"
div.credits
a.logo href="#": img src="footer-logo.png" alt="Whitesquare logo"
p
| Copyright © 2012 Whitesquare. A
a href="http://pcklab.com" pcklab
| creation
Описание стилей
Без стилей страница будет выглядеть почти plain text. Теперь пришло время описать стили, для этого можно создать styles.less и накидать иерархию, которая будет более-менее соответствовать иерархии в html.
Первончально это может выглядеть примерно так (листинг styles.less):
.whitesquare{
hr{}
header{
a.logo{}
.search{
input{}
.button{}
}
}
nav{
ul{
li{
a{}
}
}
}
div.slider{
.screen{}
ul{
li{
.index{}
.title{}
&.active{
.index{}
.title{}
}
}
}
}
.main{
.big-news{
article{}
}
.news{
article{
}
.clearfix;
}
.clients{
.title{}
a{}
}
}
footer{
.info{
h1{}
p{}
.twitter-feed{}
.sitemap{}
.social-networks{}
.credits{}
}
}
}
Т.е. создаётся less-файл который задаёт структуру шаблона, от расположения того или иного элемента в иерархии этой структуры зависит стили которые он унаследует или нет.
Далее я могу сказать, что эта страница имеет некоторый зернистый фон, и описать соответствующим образом CSS-свойства, например так:
.gray-noise{
background-color: #f7f7f7;
color: #8f8f8f;
background: url("bg.png");
}
А хедерлайн растянут на всю страницу и имеет некоторую толщину:
.full-width{
margin: 0;
width:100%;
}
.thick-headerline{
height:5px;
background-color:#7e7e7e;
}
Все эти классы помещаются в helpers.less, а в самом файле styles.less они добавляются как mixin'ы
.whitesquare{
.full-width;
.gray-noise;
.tahoma-font;
hr{
.full-width;
.thick-headerline;
}
}
Такую операцию можно провернуть не только с цветами, но и со сложными элемантами используя параметрические mixin'ы. Например для маленьких и больших figure можно использовать один mixin с параметром @size
:
.custom-figure(@size){
margin-top: 0px;
margin-left: 0px;
margin-right: 10px;
display: block;
width: @size; height: @size;
float: left;
background-color: @light-gray;
border: 1px solid #c9c9c9;
img{
margin: 1px;
}
}
Теперь в styles.less
это обеспечит отображение как маленьких картинок, так и больших:
.big-news{
article{
float: left;
width: 50%;
.title{
.complex-title;
}
figure{
.custom-figure(138px);
}
p{
margin-right: 10px;
}
}
}
.news{
article{
float: left;
width: 33.3333%;
.title{
.complex-title;
}
figure{
.custom-figure(38px);
}
p{
margin-right: 10px;
}
}
.clearfix;
}
Таким образом, файл styless.less
начинает играть туже роль что контроллеры в MVC-проекты, появляется возможность варьировать стиль элемента без переписывания стилей или изменения вёрстки.
Полный листинг стилей можно посмотреть на bitbucket https://bitbucket.org/kreshikhin/bemless, а результат на heroku http://bemless.herokuapp.com/
Т.к. целью статьи было показать преимущества свободного подхода, то я не стал добиваться идеальной вёрстки, и там есть ещё над чем работать.
И снова БЭМ
Теперь не лишним будет детально разобраться в чём конкретно заключаются недостатки БЭМ и в чём преимущества современной вёрстки на шаблонизаторах с css-препроцессором. Для этого проанализируем цели декларируемые в описании методологии http://ru.bem.info/method/
1. Типовые проекты должны разрабатываться быстро, но жить долго. Нужно уметь за короткий срок создать проект, архитектура которого позволит без труда поддерживать и развивать его долгие годы.
БЭМ не позволяет создавать что-то быстро, но заставляет писать очень много лишнего кода. Каждый БЭМ-класс должнен удовлетворять куче требований, которые могут быть не связаны с семантикой класса, а лишь отражать его положение в структуре. Таким образом, верстальщик берёт на себя часть работы компьютера. Цель же любой команды - максимально автоматизировать процесс разработки, что бы каждый её участник мог наилучшим образом реализовать свой творческий потенциал.
Использование современных шаблонизаторов и css-прероцессоров куда лучше позволяет решать эту задачу.
2. Над проектом работает много людей. Нужно уметь эффективно организовывать работу команд, как из двух разработчиков, так и из десятков.
Веб является миром инноваций и творчества. Единственный путь добиться хороших результатов от творческих работников заключается в предоставлении им максимальной свободы действия. БЭМ ограничивает свободу, в то время как современные инструменты разработки направлены на эмансипацию труда: системы контроля версий позволяют одновременно редактировать один файл нескольким разработчикам; системы непрерывной интеграции позволяют отсеивать креш-коммиты; таск-менеджеры планировать работу даже для людей в разных временных поясах. БЭМ наоборот – идёт против тренда, накладывая только ограничения и не представляя никакой свободы компенсирующей эти ограничения.
3. Масштабируемость команд. Добавление новых людей в команду должно улучшать производительность команды. Необходима возможность быстро вводить новых разработчиков в курс дела и выделять им собственные зоны ответственности. Для того, чтобы с одним и тем же кодом можно было работать долгое время и разным составом команды, код должен быть хорошо структурирован.
Масштабируемость лучше всего достижима в том случае, если от кандидатов не требуется каких-то дополнительных знаний. Современные шаблонизаторы и препроцессоры интуитивно понятны, в отличии от чистого HTML и CSS. БЭМ кроме этого требует ещё и соблюдения внутренней бюрократии.
Бюрократия же не масштабируема по определению.
4. Повторное использование кода. Каждый новый проект или элемент интерфейса не должны писаться с нуля. Если где-то внутри компании уже выполнялась похожая задача, нужно максимально повторно использовать полученный в результате код. У кода не должно быть контекстной зависимости, его нужно уметь легко переносить в другое место.
БЭМ принципиально не позволяет использовать код повторно, если понимать повторное использование в классическом смысле. Единственное что позволяет делать БЭМ это копипастить, бессмысленно и беспощадно. Современные css-препроцессоры позволяют создавать целые библиотеки для повторного использования на основе миксинов, которые способны играть такую же роль как функции и классы в языках общего назначения.
Выводы
Свобода действий в командной разработке и приверженность современным технологиям гораздо важнее чем какие-либо методологии. Вместе с CSS-препроцессором типа LESS и на современном шаблонизаторе вроде slim легко решаются абсолютно все проблемы, которые призван решить БЭМ. При этом качество проекта намного возрастает:
- можно использовать чистую семантическую вёрстку в т.ч. HTML5, не плодя лишних классов
- вёрстка лаконична и читабельна
- есть возможность создавать библиотеки для повторного использования css-кода
- стили и элементы не имеют жёсткой привязки, стили можно подстраивать не меняя названия класса
- вёрстка готова к интеграции в проект, без переделки под шаблонизатор
- у верстальщика развязаны руки, нет методологических ограничений
- данные технологии легко вписываются в демократически организованные команды
Этот список конечно не полный, в html и css вёрстке накопилось столько проблем, что их все не получится обсудить в одной статье.
В любом случае выбор за вами, сидеть на БЭМ или двигаться дальше.