Pull to refresh

CSS наших дней

Reading time 7 min
Views 7.1K

Лучшие практики стилизации элементов сейчас можно выразить следующими тезисами:


  1. Старайтесь стилизовать элементы так, чтобы их визуализация не ломалась при перемещении их в другое место. Из этого принципа следует, что стоит минимизировать использование составных селекторов (например, вида header p a).
  2. Используйте пространства имён, чтобы минимизировать вероятность конфликтов правил относящихся к разным элементам. Это приводит к длинным именам, но избавляет от кучи проблем в будущем.

Итак, какие возможности для привязки стилей к элементам у нас есть сейчас? У любого элемента есть следующие характеристики:


  1. Имя элемента
  2. Идентификатор
  3. Набор классов
  4. Набор атрибутов
  5. Набор свойств

Давайте посмотрим, как мы можем их использовать, на примере простого списка задач, содержащего карточки с названием задачи и оценкой времени её выполнения...


Имя элемента


<my-task-list>
  <my-task-card>
      <my-task-card-title>Write HTML</my-task-card-title>
      <my-task-card-estimate>1 hour</my-task-card-estimate>
  </my-task-card>
  <my-task-card>
      <my-task-card-title>Write CSS</my-task-card-title>
      <my-task-card-estimate>2 hours</my-task-card-estimate>
  </my-task-card>
  <my-task-card>
      <my-task-card-title>Write JS</my-task-card-title>
      <my-task-card-estimate>10 hours</my-task-card-estimate>
  </my-task-card>
</my-task-list>

my-task-list {
  display: flex;
  flex-direction: column;
}

my-task-card {
  display: inline-flex;
  margin: .5rem;
  padding: .5rem;
  border: 2px solid gray;
  border-radius: .5rem;
}

my-task-card-title {
  margin: .5rem;
  font-weight: bolder;
  flex: 1 1 auto;
}

my-task-card-estimate {
  margin: .5rem;
  font-weight: lighter;
}

http://liveweave.com/XjrwY5


Как видим, код CSS получился довольно простым, но длинные имена тегов весьма перегружают HTML. Кроме того, имена элементов отлично подходят для указания имени блока, но совершенно не позволяют добавлять элементу модификаторов (например, чтобы как-то выделить завершённые или важные задачи). Но самая главная проблема кастомизированных имён элементов в том, что иногда имя элемента должно быть строго определённым. Например, элемент video для вставки видео на страницу, или элемент a для создания гиперссылки.


Данный способ стилизации почти не используется ввиду упомянутых ограничений. Лишь новички и энтузиасты от web components практикуют эту технику.


Идентификаторы


<div id="my-task-list">
  <a id="my-task-card" href="#task=1">
      <div id="my-task-card-title">Write HTML</div>
      <div id="my-task-card-estimate">1 hour</div>
  </a>
  <a id="my-task-card" href="#task=2">
      <div id="my-task-card-title">Write CSS</div>
      <div id="my-task-card-estimate">2 hours</div>
  </a>
  <a id="my-task-card" href="#task=3">
      <div id="my-task-card-title">Write JS</div>
      <div id="my-task-card-estimate">10 hours</div>
  </a>
</div>

#my-task-list {
  display: flex;
  flex-direction: column;
}

#my-task-card {
  display: inline-flex;
  margin: .5rem;
  padding: .5rem;
  border: 2px solid gray;
  border-radius: .5rem;
  text-decoration: inherit;
  color: inherit;
}

#my-task-card-title {
  margin: .5rem;
  font-weight: bolder;
  flex: 1 1 auto;
}

#my-task-card-estimate {
  margin: .5rem;
  font-weight: lighter;
}

http://liveweave.com/ccrFOf


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


Раньше идентификаторы пользовались популярностью для стилизации, но сейчас их полностью вытеснили классы.


Классы


<div class="my-task-list">
  <a class="my-task-card my-task-card_important my-task-card_completed" href="#task=1">
      <div class="my-task-card-title">Write HTML</div>
      <div class="my-task-card-estimate">1 hour</div>
  </a>
  <a class="my-task-card my-task-card_completed" href="#task=1">
      <div class="my-task-card-title">Write CSS</div>
      <div class="my-task-card-estimate">2 hours</div>
  </a>
  <a class="my-task-card" href="#task=1">
      <div class="my-task-card-title">Write JS</div>
      <div class="my-task-card-estimate">10 hours</div>
  </a>
</div>

.my-task-list {
  display: flex;
  flex-direction: column;
}

.my-task-card {
  display: inline-flex;
  margin: .5rem;
  padding: .5rem;
  border: 2px solid gray;
  border-radius: .5rem;
  text-decoration: inherit;
  color: inherit;
}

.my-task-card_important {
  border-color: red;
}

.my-task-card_completed {
  opacity: .5;
}

.my-task-card-title {
  margin: .5rem;
  font-weight: bolder;
  flex: 1 1 auto;
}

.my-task-card-estimate {
  margin: .5rem;
  font-weight: lighter;
}

http://liveweave.com/qZDyzV


Изменения как в CSS, так и в HTML — незначительные, но классов на один элемент можно навешивать куда больше одного, чем мы и воспользовались, дополнительно раскрасив важные и завершённые задачи. Правда, за счёт пространств имён, такие модификаторы довольно сильно раздувают HTML.


99% кода сейчас в вебе написано на классах, тем не менее есть решение лучше..


Атрибуты


<div my-task-list>
  <a my-task-card="important completed" href="#task=1">
      <div my-task-card-title>Write HTML</div>
      <div my-task-card-estimate>1 hour</div>
  </a>
  <a my-task-card="completed" href="#task=2">
      <div my-task-card-title>Write CSS</div>
      <div my-task-card-estimate>2 hours</div>
  </a>
  <a my-task-card href="#task=3">
      <div my-task-card-title>Write JS</div>
      <div my-task-card-estimate>10 hours</div>
  </a>
</div>

[my-task-list] {
  display: flex;
  flex-direction: column;
}

[my-task-card] {
  display: inline-flex;
  margin: .5rem;
  padding: .5rem;
  border: 2px solid gray;
  border-radius: .5rem;
  text-decoration: none;
  color: inherit;
}

[my-task-card~=important] {
  border-color: red;
}

[my-task-card~=completed] {
  opacity: .5;
}

[my-task-card-title] {
  margin: .5rem;
  font-weight: bolder;
  flex: 1 1 auto;
}

[my-task-card-estimate] {
  margin: .5rem;
  font-weight: lighter;
}

http://liveweave.com/8ddncZ


Код CSS усложнился незначительно, зато HTML, не смотря на поддержку модификаторов, стал куда более простым. Тут мы используем специальный селектор, который буквально означает "применить такие-то стили к элементу, у которого в таком-то атрибуте, среди разделённых пробелом слов, есть такое-то".


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


Свойства


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


[my-task-card]:hover {
  border-color: steelblue;
  box-shadow: 0 0 .5rem rgba(0,0,255,.25);
  opacity: 1;
}

К сожалению набор псевдоклассов никак от нас не зависит, поэтому, если, например, нам потребуется выделить карточку текущей открытой задачи, то нам уже придётся использовать модификатор:


[my-task-card]:not([my-task-card~=current]):hover {
  border-color: steelblue;
  box-shadow: 0 0 .5rem rgba(0,0,255,.25);
  opacity: 1;
}

[my-task-card~=current] {
  background: #eee;
  border: none;
}

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


[my-task-card~=hover] {
  border-color: steelblue;
  box-shadow: 0 0 .5rem rgba(0,0,255,.25);
  opacity: 1;
}

[my-task-card~=current] {
  background: #eee;
  border: none;
}

<div my-task-list>
  <a my-task-card="important completed" href="#task=1">
      <div my-task-card-title>Write HTML</div>
      <div my-task-card-estimate>1 hour</div>
  </a>
  <a my-task-card="completed" href="#task=2">
      <div my-task-card-title>Write CSS</div>
      <div my-task-card-estimate>2 hours</div>
  </a>
  <a my-task-card="current" href="#task=3">
      <div my-task-card-title>Write JS</div>
      <div my-task-card-estimate>10 hours</div>
  </a>
</div>

<div my-task-list>
  <a my-task-card="hover important completed" href="#task=1">
      <div my-task-card-title>Write HTML</div>
      <div my-task-card-estimate>1 hour</div>
  </a>
  <a my-task-card="hover completed" href="#task=2">
      <div my-task-card-title>Write CSS</div>
      <div my-task-card-estimate>2 hours</div>
  </a>
</div>

http://liveweave.com/1GJrUM


Тут мы вывели карточки задач во всех возможных состояниях, так что одним взглядом можем легко окинуть их все. Как написать JS, который будет менять модификаторы по необходимой логике — вопрос отдельный и во многом зависит от предпочитаемого вами фреймворка.


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

Tags:
Hubs:
+2
Comments 31
Comments Comments 31

Articles