Это перевод статьи Льюиса Лазариса (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 |
Многие могут подумать, что такой вид абстракции стилей несколько засоряет 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 в ее блоге, Николь выпустила несколько презентаций с хорошими слайдами. Ниже перечислены основные:
- Объектно ориентированный CSS (слайдшоу)
- Высокопроизводительные сайты (видео)
- Наши лучшие практики, убивающие нас (слайдшоу)
- Раздутый CSS (слайдшоу)
Заключение
Многие люди боятся идеологии 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 разметке. Старайтесь писать атрибуты в элементах в одном и том же порядке.
Давайте делать хорошо и удобно людям!


