15.12.2011

Введение в объектно ориентированный CSS (OOCSS)

Введение в объектно ориентированный CSS (OOCSS)

Это перевод статьи Льюиса Лазариса (Louis Lazaris) An Introduction To Object Oriented CSS (OOCSS), опубликованной на сайте Smashing Magazine 12 декабря 2011 года. Это мой личный перевод, как и всегда. Поэтому прошу всех переводчиков, которым также посчастливилось опубликовать русскую версию этой статьи не кричать и не посылать мне гневные письма с обвинениями о краже их перевода. Просто разместите ссылку своей версии в комментариях и я с удовольствием вставлю ее в начало поста.

Вступление от переводчика


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

Вы когда-нибудь слышали фразу «Контент — король»? Будучи веб-разработчиками, мы часто сталкиваемся непосредственно с созданием контента. Не будет преувеличением сказать, что именно контент привлекает посетителей на сайт.

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

К сожалению, многие в этом вопросе обходят CSS стороной (по веским причинам), в значительной степени сосредоточив свои усилия на оптимизации JavaScript и других областях.

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

Принципы OOCSS


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

Как описано в на вики станице OOCSS на GitHub, OOCSS построен на двух принципах.

Отделение структуры от представления


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

До применения принципов OOCSS ваш CSS может выглядеть следующим образом:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#button {
  width: 200px;
  height: 50px;
  padding: 10px;
  border: solid 1px #ccc;
  background: linear-gradient(#ccc, #222);
  box-shadow: rgba(0, 0, 0, .5) 2px 2px 5px;
}

#box {
  width: 400px;
  overflow: hidden;
  border: solid 1px #ccc;
  background: linear-gradient(#ccc, #222);
  box-shadow: rgba(0, 0, 0, .5) 2px 2px 5px;
}

#widget {
  width: 500px;
  min-height: 200px;
  overflow: auto;
  border: solid 1px #ccc;
  background: linear-gradient(#ccc, #222);
  box-shadow: rgba(0, 0, 0, .5) 2px 2px 5px;
}

Вверху у трех элементов присутствуют уникальные для каждого стили, и они используют непригодный к повторному использованию ID (#) селектор. Однако они имеют и общие друг для друга стили, которые могут присутствовать и в описании прочих дизайнерских элементов.

Благодаря толике планирования и небольшой предусмотрительности мы можем абстрагироваться от общих стилей и, в конечном счете, превратить наш CSS во что-нибудь вроде этого:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
.button {
  width: 200px;
  height: 50px;
}

.box {
  width: 400px;
  overflow: hidden;
}

.widget {
  width: 500px;
  min-height: 200px;
  overflow: auto;
}

.skin {
  border: solid 1px #ccc;
  background: linear-gradient(#ccc, #222);
  box-shadow: rgba(0, 0, 0, .5) 2px 2px 5px;
}

Теперь все элементы используют классы. Общие стили объединены в повторно используемый класс .skin и никаких лишних повторений кода. Теперь нам достаточно применить класс .skin ко всем необходимым элементам и результат будет точно таким же, как если бы мы использовали первый вариант CSS примера. За исключением того, что теперь у нас меньше кода и возможность в дальнейшем использовать его вновь.

Отделение контейнеров от контента


Второй принцип, описанный в вики на GitHub — это отделение контейнеров от контента. Чтобы проиллюстрировать важность этого принципа, давайте взглянем на следующий код:

1
2
3
4
5
6
7
#sidebar h3 {
  font-family: Arial, Helvetica, sans-serif;
  font-size: .8em;
  line-height: 1;
  color: #777;
  text-shadow: rgba(0, 0, 0, .3) 3px 3px 6px;
}

Эти стили будут применены ко всем заголовкам третьего уровня, являющиеся детьми элемента с ID sidebar. Но что если мы захотим применить точно такие же стили к заголовкам третьего уровня, которые находятся в подвале, плюс к тому с другим размером шрифта и измененной тенью?

Скорее всего наш мозг родит это:

1
2
3
4
5
6
7
8
9
10
11
12
#sidebar h3, #footer h3 {
  font-family: Arial, Helvetica, sans-serif;
  font-size: 2em;
  line-height: 1;
  color: #777;
  text-shadow: rgba(0, 0, 0, .3) 3px 3px 6px;
}

#footer h3 {
  font-size: 1.5em;
  text-shadow: rgba(0, 0, 0, .3) 2px 2px 4px;
}

Или того хуже:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#sidebar h3 {
  font-family: Arial, Helvetica, sans-serif;
  font-size: 2em;
  line-height: 1;
  color: #777;
  text-shadow: rgba(0, 0, 0, .3) 3px 3px 6px;
}

/* много много других стилей.... */

#footer h3 {
  font-family: Arial, Helvetica, sans-serif;
  font-size: 1.5em;
  line-height: 1;
  color: #777;
  text-shadow: rgba(0, 0, 0, .3) 2px 2px 4px;
}

Теперь у нас ненужные повторения и мы бы о них даже не догадались (ну или просто забили на это). С OOCSS мы более осведомлены относительно того, что общего в различных элементах на этапе выделения их в модули или объекты, которые могут быть задействованы вновь и вновь где угодно.

Стили, которые были объявлены как потомки в предыдущем примере, совершенно не пригодны для повторного использования. Так как они напрямую зависят от конкретного контейнера (в этом случае от подвала или сайдбара).

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

Живой пример


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

Итак, тут у нас пара строк того, что у меня получилось после верстки шапки:

1
2
3
4
5
6
7
8
.header-inside {
  width: 980px;
  height: 260px;
  padding: 20px;
  margin: 0 auto;
  position: relative;
  overflow: hidden;
}

Несколько стилей уникальны для .header-inside. Но остальные могут быть загнаны в модуль, который я потом могу использовать вновь. Я могу абстрагировать структурные стили в собственный класс. Вот результат:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.globalwidth {
  width: 980px;
  margin: 0 auto;
  position: relative;
  padding-left: 20px;
  padding-right: 20px;
  overflow: hidden;
}

.header-inside {
  padding-top: 20px;
  padding-bottom: 20px;
  height: 260px;
}

Стили, принадлежащие .globalwidth описывают следующее:

  • Фиксированную ширину
  • Центрирование с применением margin: auto
  • Относительное позиционирование, для создания позиционного контекста для дочерних элементов
  • Левый и правый отступы в 20 пикселей
  • Overflow выставлен в «hidden» для clearfix’a

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

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

После добавления к элементам .globalwidth верстка выглядит так:

1
2
3
4
5
6
7
8
9
10
11
12
<header>
  <div class="header-inside globalwidth">
  </div>
</header>

<div class="main globalwidth">
</div>

<footer>
  <div class="footer-inside globalwidth">
  </div>
</footer>

Многие могут подумать, что такой вид абстракции стилей несколько засоряет HTML и идет в разрез с принципами разделения разметки и представления.

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

Медиа объект


Одна из пионеров OOCSS — Николь Салливан (Nicole Sullivan) создала модуль под названием media object, который, по ее словам, может сэкономить сотни строк кода.

Медиа объект — прекрасный пример силы OOCSS. Потому как он может содержать в себе любой медийный объект любого размера с любым другим контентом справа от него. При этом можно применить множество других стилей к содержимому объекта и даже к самому объекту. Медиа объект описан общими базовыми стилями, которые помогают избежать ненужные повторения.

Преимущества OOCSS


Я уже затронул некоторые преимущества OOCSS. Здесь я их расширю.

Быстрые сайты


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

Действительно, HTML разметка при этом несколько разбухнет и увеличит размер HTML файла. Но в большинстве случаев небольшие потери в производительности разметки с лихвой перекрываются выигрышем в производительности CSS файла.

Другой концепт, о котором стоит помнить и о котором говориться на вики странице OOCSS — побочная производительность. Это относится к тому факту, что каждый раз когда вы повторно используете что-то в своем CSS вы, в сущности, создаете новый стиль с нулевым количеством строк нового кода. Для действительно больших, хайлоад проектов — это дает критический прирост скорости.

Ремонтопригодные таблицы стилей


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

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

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

Еще одно преимущество — это облегчение поддержки такого кода и увеличение его прочности. Потому как стили имеют модульную структуру. Уменьшается вероятность поломать страницы, созданные с применением OOCSS, когда новый разработчик вносит какие-либо изменения.

Очки стоит отменить


OOCSS породил большое количество обсуждений и споров. Здесь я попытаюсь развеять некоторые общие заблуждения.

По прежнему можно использовать ID


Если вы решили использовать исключительно OOCSS, то ваши стили в значительной степени будут основаны на классах. И вы не будете использовать ID (#) селекторы.

В связи с этим многие не верно думают, что OOCSS рекомендует полностью отказаться от использования атрибута ID.

Правило избегания ID на самом деле означает только то, что не следует использовать ID в качестве селекторов. Поэтому совершенно приемлемо использование принципов OOCSS (и таким образом отказ от привязки стилей к ID селекторам) вместе с использованием атрибута ID в HTML дескрипторах для привязки событий JavaScript и прочее.

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

Работа с небольшими проектами


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

Тем не менее, я думаю будет не такой уж плохой идеей, по крайней мере начать думать в терминах OOCSS во всех ваших проектах. Как только у вас появится навык, уверен, работа над большими проектами, где преимущества более ощутимы, будет на много легче.

Небольшое руководство к действию


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

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

  • Избегайте вложенных селекторов (например, не используйте .sidebar h3)
  • Избегайте привязки стилей к ID атрибутам.
  • Избегайте привязки классов к элементам (например, не используйте div.header или h1.title)
  • Используйте CSS Lint для проверки CSS кода (здесь описаны рекомендации)
  • Используйте модульные сетки

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

Следите за работой Николь Салливан


Если вы хотите продолжить изучение OOCSS, то самая важная персона в этом деле — Николь Салливан (Nicole Sullivan)

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

Заключение


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

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

Несколько слов от переводчика


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

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

Хорошей идеей в этом случае является написание правил в алфавитном порядке. Это, в первую очередь, позволяет поддерживать общий стиль, во-вторых приучает глаз искать те или иные правила в привычных, заведомо известных местах. Скажем, мы точно будем знать, что background описан где-то в самом начале, text или width ближе к концу класса.

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

Приведу пример кода, взятый из начала этой статьи. Я немного переместил правила в классах, чтобы было нагляднее:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#button {
  width: 200px;
  height: 50px;
  box-shadow: rgba(0, 0, 0, .5) 2px 2px 5px;
  padding: 10px;
  border: solid 1px #ccc;
  background: linear-gradient(#ccc, #222);
}

#box {
  width: 400px;
  overflow: hidden;
  border: solid 1px #ccc;
  box-shadow: rgba(0, 0, 0, .5) 2px 2px 5px;
  background: linear-gradient(#ccc, #222);
}

#widget {
  border: solid 1px #ccc;
  width: 500px;
  min-height: 200px;
  overflow: auto;
  background: linear-gradient(#ccc, #222);
  box-shadow: rgba(0, 0, 0, .5) 2px 2px 5px;
}

Здесь правила расположены абы как. При GZIP сжатии получается ровно 200 байт. Немного переделаем код в соответствии с описанной рекомендацией:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#button {
  background: linear-gradient(#ccc, #222);
  border: solid 1px #ccc;
  box-shadow: rgba(0, 0, 0, .5) 2px 2px 5px;
  height: 50px;
  padding: 10px;
  width: 200px;
}

#box {
  background: linear-gradient(#ccc, #222);
  border: solid 1px #ccc;
  box-shadow: rgba(0, 0, 0, .5) 2px 2px 5px;
  overflow: hidden;
  width: 400px;
}

#widget {
  background: linear-gradient(#ccc, #222);
  border: solid 1px #ccc;
  box-shadow: rgba(0, 0, 0, .5) 2px 2px 5px;
  min-height: 200px;
  overflow: auto;
  width: 500px;
}

На выходе GZIP получается 193 байта. Выигрыш в 7 байтов. Не много, но это всего-лишь 3 класса. И для этого не пришлось делать ничего сверхъестественного. Скажем, если в вашем CSS около 200 классов, то выигрыш может достигнуть 500 байт. И так далее. Не говоря уже о том, что такой код приятно читать.

Та же рекомендация относится и к HTML разметке. Старайтесь писать атрибуты в элементах в одном и том же порядке.

Давайте делать хорошо и удобно людям!



Оставить комментарий