[CSS, Клиентская оптимизация] DRY CSS: Как использовать каждое объявление только один раз (перевод)

Автор Сообщение
news_bot ®

Стаж: 6 лет 9 месяцев
Сообщений: 27286

Создавать темы news_bot ® написал(а)
01-Дек-2020 13:33

Использование DRY в CSS — это способ максимально избегать повторения в таблицах стилей. Этот подход не панацея, но он достаточно эффективен и является одним из основных методов оптимизации. Поскольку я использовал и изучал его почти 10 лет, в этой статье хочу поделиться своим опытом и знаниями.
А если вам будет интересна тема оптимизации CSS, то я рассказал об основах в моей небольшой книге "CSS Optimization Basics".
Основные шаги
Прежде чем мы углубимся в подробности, как «высушить» таблицы с помощью DRY, обратите внимание, что этот метод нетривиально автоматизировать из-за каскадности. Но, не смотря на это, я постараюсь ничего не упустить.
  • Пишите CSS обычным и естественным образом.
  • Определитесь с DRY-границами, что вы будете оптимизировать: раздел (функционально разделенные CSS-стили), файл, компонент или @media-запросы. Я работаю на уровне файл/@media, то есть обычно «сушу» всё в максимально возможном объеме.
  • Убедитесь, что формат кода является консистентным, так как border:0;, border: 0; и border: none; означают одно и тоже, но это значительно усложняет поиск дубликатов.
  • Найдите повторяющиеся объявления:
    • Для новых стилей: после первоначальной инициализации.
    • Для новых функций и исправлений: после завершения соответствующих действий.
    • Совет: если для изменений в файле недостаточно подсказки системы версионирования, просто временно сделайте отступ для измененных объявлений для последующий проверки на уникальность.
  • Разрешите повторяющиеся объявления:
    • Проверьте каждое объявление (в новых таблицах стилей) или каждое изменённое объявление на предмет повторений в заданном диапазоне (если дедупликация ограничена отдельными разделами, сузьте поиск этими разделами).
    • Для каждого повторного объявления (переход к действиям):
      • Определите, какое правило в таблице стилей должно быть первым (для этого вы должны определить, какой путь вы выбираете для сортировки селекторов).
      • Если первое правило содержит дополнительные объявления, которые еще не были проверены, то скопируйте всё правило и вставьте его после оригинала. Сохраните обнаруженный дубликат в первом правиле и удалите другие объявления, и сделайте наоборот во втором правиле, чтобы оно было похоже на старое правило, только без объявления, которое будет выполняться более одного раза.
      • Скопируйте селекторы других правил, которые содержат соответствующее объявление, в правило, идущее первым.
      • Обязательно удалите повторяющиеся объявления, селекторы которых были только что скопированы в таблицу стилей, и удалите правило, если оно состоит только из перемещенного дублирующего объявления.
      • (Повторите шаги).
    • Убедитесь, что правила, обрабатывающие ранее повторяющиеся объявления, содержат селекторы в правильном порядке.
    • Убедитесь, что правила, обрабатывающие ранее повторяющиеся объявления, имеют правильное расположение.

Весь этот процесс, на первый взгляд, может показаться запутанным и пугающим, но сейчас мы погрузимся немного глубже и рассмотрим примеры.
Особые случаи
Существует два сценария, требующих особого внимания:
  • Разделение файлов: отдельные CSS-файлы могут быть полезны, особенно при повторной сборке в эксплуатацию, но когда дело доходит до «сушки» объявлений, они создают «жесткий» барьер: требуется много усилий для поиска и удаления повторяющихся объявлений. Если мы работаем с небольшой или средней кодовой базой на CSS, то может быть разумно перейти на одну таблицу стилей. Но когда мы имеем дело со сложными таблицами, то некоторое повторение допустимо.
  • Строгость подхода или отступление от него: если мы строго избегаем повторений (то есть полностью хотим удалить дубликаты), мы всё равно будем иногда сталкиваться с исключениями. Эти исключения, кроме структурно-зависимых, таких как @media-запросы, файловые границы, или когда последовательность (каскад) является важной, будут вызывать проблемы с поддержкой. Селекторные хаки также являются исключением, поскольку некоторые селекторы работают таким образом, что фактически не позволяют пользовательскому агенту корректно интерпретировать соответствующее правило. В таких случаях мы не можем избежать совпадений, потому что при объединении соответствующих селекторов мы можем повлиять на их работу и результат будет некорректный.

Примеры
Теперь давайте поработаем с несколькими классическими таблицамибез использования препроцессора. Мы сосредоточимся на оптимизации на уровне файла, чтобы можно было представить соответствующий код в виде секции или модуля, который выполняет одно и то же действие.
Оптимизация. Пример первый
Этот пример взят с сайта www.engadget.com, где мы обнаружили 92% повторений, случайный раздел, но по-крайней мере отсортированный в алфавитном порядке. Мы предполагаем, что порядок селекторов нас устраивает, и не будем менять и комментировать имена классов и т. д.

Код

SPL
.arrow-left {
  border-color: transparent;
  border-style: solid;
  border-width: 10px 10px 10px 0;
  height: 0;
  width: 0;
}
.arrow-down {
  border-bottom: 10px solid transparent;
  border-left: 10px solid transparent;
  border-right: 10px solid transparent;
  border-top: 10px solid #2b2d32;
  bottom: 0;
  height: 0;
  left: 20px;
  width: 0;
}
.faq-list .faq-item-title {
  cursor: pointer;
}
.faq-list .faq-item-title:after {
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-top: 5px solid #111;
  content: '';
  display: inline-block;
  float: right;
  height: 0;
  opacity: .5;
  vertical-align: top;
  width: 0;
}
#contact input:focus,
#contact textarea:focus {
  border: 1px solid #3398db;
}
.flickity-slider>.table {
  table-layout: fixed;
}
::selection {
  background: #9b59b6;
  color: #fff;
}
.videoWrapper {
  height: 0;
  padding-bottom: 56.25%;
  position: relative;
}
.videoWrapper iframe {
  height: 100%;
  left: 0;
  position: absolute;
  top: 0;
  width: 100%;
}
.i-rail-followus__socials {
  display: table;
}
.i-rail-followus__tw {
  vertical-align: sub;
}


Когда мы смотрим на эту таблицу, то сразу хотим быстро удалить повторяющиеся объявления. Но поскольку мы находимся в самом начале «сушки», не будем отходить от алгоритма и просто спускаемся по таблице сверху вниз, просматривая каждое объявление. Первым является border-color: transparent;. Оно где-нибудь еще используется? Нет, тогда идём к следующему — border-style: solid;. Оно уникальное. Тоже самое с border-width: 10px 10px 10px 0;. Затем height: 0;. Не уникальное.
Соответственно, наша работа начинается с height: 0;. Заметим, что это объявление используется в трех различных правилах: .arrow-down, .faq-list .faq-item-title:after и .videoWrapper. Поскольку у нас нет правила, которое включает в себя именно эти четыре селектора, мы копируем их, чтобы сформировать новое правило непосредственно перед тем, в котором мы нашли первое вхождение height: 0;( .arrow-left). Другими словам, мы пишем новое правило только для height: 0;.
.arrow-left,
.arrow-down,
.faq-list .faq-item-title:after,
.videoWrapper {
  height: 0;
}

Теперь убираем height: 0; из всех остальных правил. Поскольку ни одно из них не состояло исключительно из этого объявления, мы не можем удалить их целиком (пока). Обычно я делаю это за один шаг: если нахожу «бесспорный» дубликат, то создаю новое правило, ищу больше вхождений, удаляю объявление, которое нужно переместить, и копирую селектор(ы), который нужно вставить. С опытом всё это становится проще.
Продолжим с правилом .arrow-left, с объявлением, следующим после height: 0; — width: 0. Дубликат? Да. И это хорошо, потому что когда мы проверяем, где еще используется width: 0;, то видим, что оно почти такое же, но не идентичное селекторам, использующим height: 0;. То есть мы начнем с нового правила для width: 0;, убедившись, что удалили все предыдущие вхождения:
.arrow-left,
.arrow-down,
.faq-list .faq-item-title:after {
  width: 0;
}

Это правило идет после созданного для height: 0; и перед .arrow-letf;, которое мы только что проверили и оптимизировали. Я считаю, что результирующий порядок полезен, потому что предпочитаю, чтобы правила располагались в порядке важности и воздействия. А поскольку мы объединяли правила, то сделали их более эффективными.
Давайте проработаем правило .arrow-down;. В нём нет повторений, хотя его можно описать элегантнее: border: 10px solid transparent; border-top-color: #2b2d32;.
Продолжим с .faq-list .faq-item-title. Тут нет дубликатов. На самом деле этот фрагмент таблицы стилей был довольно простым, поэтому мы больше не находим дополнительных совпадений.

Код

SPL
.arrow-left,
.arrow-down,
.faq-list .faq-item-title:after,
.videoWrapper {
  height: 0;
}
.arrow-left,
.arrow-down,
.faq-list .faq-item-title:after {
  width: 0;
}
.arrow-left {
  border-color: transparent;
  border-style: solid;
  border-width: 10px 10px 10px 0;
}
.arrow-down {
  border-bottom: 10px solid transparent;
  border-left: 10px solid transparent;
  border-right: 10px solid transparent;
  border-top: 10px solid #2b2d32;
  bottom: 0;
  left: 20px;
}
.faq-list .faq-item-title {
  cursor: pointer;
}
.faq-list .faq-item-title:after {
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-top: 5px solid #111;
  content: '';
  display: inline-block;
  float: right;
  opacity: .5;
  vertical-align: top;
}
#contact input:focus,
#contact textarea:focus {
  border: 1px solid #3398db;
}
.flickity-slider>.table {
  table-layout: fixed;
}
::selection {
  background: #9b59b6;
  color: #fff;
}
.videoWrapper {
  padding-bottom: 56.25%;
  position: relative;
}
.videoWrapper iframe {
  height: 100%;
  left: 0;
  position: absolute;
  top: 0;
  width: 100%;
}
.i-rail-followus__socials {
  display: table;
}
.i-rail-followus__tw {
  vertical-align: sub;
}


Оптимизация. Пример второй
Для второго примера возьмём eBay. На этот раз мы тоже хотим просто переформатировать (отступы, сортировка объявлений по алфавиту), но снова сталкиваемся с практиками, которых следует избегать (особенно c именами классов или отсутствием резервных шрифтов, но для шрифтов вроде Arial это не является проблемой).

Код

SPL
.sh-GifCont {
  color: #999;
  font-family: Verdana !important;
  font-size: 10px;
  font-weight: normal;
  padding: 0 10px 4px 10px;
}
.sh-GetFastImg {
  background-image: url('http: //ir.ebaystatic.com/pictures/aw/pics/de/viewitem/spr4VI.png');
  background-position: 0 -178px;
  background-repeat: no-repeat;
  float: left;
  height: 16px;
  margin-right: 4px;
  width: 56px;
}
.sh-float-l {
  float: left;
}
.sh-FrZip {
  padding: 10px 0 0 15px;
  width: 12%;
}
.sh-FrDelLoc {
  padding: 10px 15px 0 10px;
  width: 10%;
}
.sh-FrCnt {
  padding-left: 10px;
  padding-right: 0;
  text-align: left;
}
.sh-FrZipCnt {
  padding: 0 0 0 15px;
}
.sh-FrDelLocCnt {
  padding: 0;
}
.sh-FrBtn {
  padding: 5px 15px 10px 8px;
}
.sh-FrDelSite {
  padding: 6px 0 0;
}
.vi-frs-sh-FrSlctr {
  display: inline;
  padding: 6px 15px 0 10px;
}
.sh-FrZipDiv {
  display: inline;
  padding: 6px 15px 0 0;
}
.sh-FrTxt {
  color: #333;
  font-family: Arial;
  font-size: 12px;
  font-weight: normal;
  padding-left: 15px;
}
.sh-FrLrnMore {
  display: inline;
  padding: 10px 10px 10px 15px;
}
.sh-FrQuote {
  display: inline;
}
.sh-FrLnk {
  margin-top: 5px;
}
.sh-Tbl {
  padding: 10px;
}
.sh-TblCnt {
  color: #333;
  font-family: Arial;
  font-size: 12px;
  font-weight: normal;
  padding-left: 15px;
}
.sh-TblHdr {
  color: #5d5d5d;
  font-family: Verdana;
  font-size: 12px;
  font-weight: normal;
  padding-left: 15px;
}
.sh-Info {
  color: #999;
  font-family: Arial;
  font-size: 11px;
  font-weight: normal;
}
.sh-FrSbTxt {
  color: #999;
  font-family: arial;
  font-size: 11px;
  font-weight: normal;
  padding-left: 15px;
}
.sh-FreightHdr {
  color: #333;
  font-family: Verdana !important;
  font-size: 10px;
  font-weight: normal;
  padding: 5px 0 5px 23px;
}
.sh-Freight-Hdr {
  color: #333;
  font-family: Verdana !important;
  font-size: 10px;
  font-weight: normal;
  padding-left: 13px;
}
.sh-Cnt {
  color: #5d5d5d;
  font-family: Arial;
  font-size: small;
  font-weight: normal;
  padding-left: 13px;
}
.vi-frs-sh-TxtCnt {
  color: #333;
  font-family: Arial;
  font-size: 12px;
  font-weight: normal;
}
.sh-BtnTxt {
  color: #333;
  font-family: Verdana,Tahoma,Arial;
  font-size: 12px;
  font-weight: normal;
  height: 24px;
  margin: 0;
  padding: 0 3px;
  position: relative;
  text-decoration: none;
  top: 0;
}
.sh-bubble-position {
  float: left;
  padding-top: 5px;
}
.sh-del-lrge b {
  font-size: 15px;
}
.sh-gspFirstLine {
  color: #333;
  font-family: Arial;
  font-size: 15px;
  padding: 25px 10px 5px 0;
}
.sh-gspSecondLine {
  color: #777;
  font-family: Arial;
  font-size: 12px;
  padding: 0 10px 15px 0;
}


Первый шаг: color: #999; был использован более одного раза? Да. Итак, мы сначала создаем собственное правило:
.sh-GifCont {
  color: #999;
}

Следует добавить селекторы для двух других вхождений:
.sh-GifCont,
.sh-Info,
.sh-FrSbTxt {
  color: #999;
}

Здесь нам также помогает предположение, что таблица стилей уже использует тот порядок выбора, который нам нужен, и что смена правил не вызовет проблем. Полезно иметь четкое представление о порядке выбора и о решении каскадных проблем, не перемещая затронутые правила или не объединяя их.
font-family: Verdana !important; — это объявление используется трижды. Затем font-size: 10px; — обратите внимание, важно избегать повторения селекторов: это объявление используется теми же селекторами, что мы сгруппировали для «Verdana».
.sh-GifCont,
.sh-FreightHdr,
.sh-Freight-Hdr {
  font-family: Verdana !important;
}
.sh-GifCont,
.sh-FreightHdr,
.sh-Freight-Hdr {
  font-size: 10px;
}

Резюмируем правила:
.sh-GifCont,
.sh-FreightHdr,
.sh-Freight-Hdr {
  font-family: Verdana !important;
  font-size: 10px;}

Таким образом мы проработаем всю таблицу стилей, пока не получим:

Код

SPL
.sh-GifCont,
.sh-Info,
.sh-FrSbTxt {
  color: #999;
}
.sh-GifCont,
.sh-FreightHdr,
.sh-Freight-Hdr {
  font-family: verdana !important;
  font-size: 10px;
}
.sh-GifCont,
.sh-FrTxt,
.sh-TblCnt,
.sh-TblHdr,
.sh-Info,
.sh-FrSbTxt,
.sh-FreightHdr,
.sh-Freight-Hdr,
.sh-Cnt,
.vi-frs-sh-TxtCnt,
.sh-BtnTxt {
  font-weight: normal;
}
.sh-GifCont {
  padding: 0 10px 4px 10px;
}
.sh-GetFastImg,
.sh-float-l,
.sh-bubble-position {
  float: left;
}
.sh-GetFastImg {
  background-image: url('http: //ir.ebaystatic.com/pictures/aw/pics/de/viewitem/spr4VI.png');
  background-position: 0 -178px;
  background-repeat: no-repeat;
  height: 16px;
  margin-right: 4px;
  width: 56px;
}
.sh-FrZip {
  padding: 10px 0 0 15px;
  width: 12%;
}
.sh-FrDelLoc {
  padding: 10px 15px 0 10px;
  width: 10%;
}
.sh-FrCnt {
  padding-left: 10px;
  padding-right: 0;
  text-align: left;
}
.sh-FrZipCnt {
  padding: 0 0 0 15px;
}
.sh-FrDelLocCnt {
  padding: 0;
}
.sh-FrBtn {
  padding: 5px 15px 10px 8px;
}
.sh-FrDelSite {
  padding: 6px 0 0;
}
.vi-frs-sh-FrSlctr,
.sh-FrZipDiv,
.sh-FrLrnMore,
.sh-FrQuote {
  display: inline;
}
.vi-frs-sh-FrSlctr {
  padding: 6px 15px 0 10px;
}
.sh-FrZipDiv {
  padding: 6px 15px 0 0;
}
.sh-FrTxt,
.sh-TblCnt,
.sh-FreightHdr,
.sh-Freight-Hdr,
.vi-frs-sh-TxtCnt,
.sh-BtnTxt,
.sh-gspFirstLine {
  color: #333;
}
.sh-FrTxt,
.sh-TblCnt,
.sh-Info,
.sh-FrSbTxt,
.sh-Cnt,
.vi-frs-sh-TxtCnt,
.sh-gspFirstLine,
.sh-gspSecondLine {
  font-family: arial;
}
.sh-FrTxt,
.sh-TblCnt,
.sh-TblHdr,
.vi-frs-sh-TxtCnt,
.sh-BtnTxt,
.sh-gspSecondLine {
  font-size: 12px;
}
.sh-FrTxt,
.sh-TblCnt,
.sh-TblHdr,
.sh-FrSbTxt {
  padding-left: 15px;
}
.sh-FrLrnMore {
  padding: 10px 10px 10px 15px;
}
.sh-FrLnk {
  margin-top: 5px;
}
.sh-Tbl {
  padding: 10px;
}
.sh-TblHdr,
.sh-Cnt {
  color: #5d5d5d;
}
.sh-TblHdr {
  font-family: verdana;
}
.sh-Info,
.sh-FrSbTxt {
  font-size: 11px;
}
.sh-FreightHdr {
  padding: 5px 0 5px 23px;
}
.sh-Freight-Hdr,
.sh-Cnt {
  padding-left: 13px;
}
.sh-Cnt {
  font-size: small;
}
.sh-BtnTxt {
  font-family: verdana,tahoma,arial;
  height: 24px;
  margin: 0;
  padding: 0 3px;
  position: relative;
  text-decoration: none;
  top: 0;
}
.sh-bubble-position {
  padding-top: 5px;
}
.sh-del-lrge b,
.sh-gspFirstLine {
  font-size: 15px;
}
.sh-gspFirstLine {
  padding: 25px 10px 5px 0;
}
.sh-gspSecondLine {
  color: #777;
  padding: 0 10px 15px 0;
}


Редактирование
То, что мы рассмотрели выше, может показаться большой сложной работой. Но всё, что для этого нужно, это воля, практика и понимание, что сложная и утомительная работа возникает только тогда, когда вы выполняете ее с полностью несортированными, неоптимизированными таблицами стилей. Как только мы проясним наши стандарты написания кода и шаги по оптимизации, обновлять и поддерживать таблицы стилей становится довольно просто. Достаточно будет перепроверить свои правки.
Давайте также рассмотрим это очень кратко в третьем примере, отрывке из Code Responsible.
h1,
h2 {
  color: #000;
  font-family: futurastd-book, futura, 'droid sans', 'helvetica neue', helvetica, sans-serif;
  font-weight: 400;
  line-height: 1.13;
}
h1 {
  font-size: 1.86em;
  margin: 0 0 .53em;
}
h2 {
  counter-increment: counter;
  font-size: 1.5em;
  margin: 1em 0 0;
}

Здесь мы можем легко изменить правило: предположим, что для h1 нужен другой margin, к примеру, margin: 1em 0 0;. Многие сразу поймут, что мы можем и должны сделать. А чтобы показать один из возможных способов, с более сложной таблицей стилей я поступил бы так.
Первое, что нужно сделать, это внести изменение, отметить его (мой редактор — обычно IntelliJ IDEA — показывает изменения и упрощает их поиск, но мне всё равно нравится временно отступать от новых или измененных объявлений) и протестировать:
h1,
h2 {
  color: #000;
  font-family: futurastd-book, futura, 'droid sans', 'helvetica neue', helvetica, sans-serif;
  font-weight: 400;
  line-height: 1.13;
}
h1 {
  font-size: 1.86em;
   margin: 1em 0 0;
}
h2 {
  counter-increment: counter;
  font-size: 1.5em;
  margin: 1em 0 0;
}

Во-вторых, после успешного тестирования я бы проверил все эти измененные строки, не нужно ли их оптимизировать еще раз. Здесь мы обнаружим, что поля для h1 и h2 идентичны.
Следуя способу разбивки на отдельные шаги, создадим правило для h1 и h2. Но у них уже есть собственное правило, поэтому объединим их в одно. Результат:
h1,
h2 {
  color: #000;
  font-family: futurastd-book, futura, 'droid sans', 'helvetica neue', helvetica, sans-serif;
  font-weight: 400;
  line-height: 1.13;
  margin: 1em 0 0;
}
h1 {
  font-size: 1.86em;
}
h2 {
  counter-increment: counter;
  font-size: 1.5em;
}

Этим я хотел показать, что поддерживать таблицы гораздо легче, чем оптимизировать их.
Подсказки
Хочу поделиться несколькими советами (поскольку я обновляю статьи на meiert.com, я могу со временем изменить эти советы).
  • Поиск без учета регистра. Вполне возможно, что различие регистра является не случайным (некоторые области таблицы стилей, такие как сгенерированный контент или URL-адреса, могут быть чувствительны к регистру). eBay является хорошим примером: независимо от отсутствующих резервных шрифтов, некоторые из используемых объявлений шрифтов пишутся с заглавной буквы по-разному. Например, мы находим font-family: Arial; и font-family: arial;. Их следует объединить, а значит версия с корректировкой на повторение использует только одно объявление и только в одной нотации (нижний регистр).
  • Закрывайте каждое (предварительное) объявление точкой с запятой. Это упрощает просто копирование и перемещение объявлений, а также избавляет нас от множества ложных срабатываний (а их будет несколько). Тег !important является прекрасным примером: если мы ищем «незакрытые» выражения, то border: 0 обязательно совпадёт с border: 0 !important, и может появиться бесконечное количество других действительно разных объявлений. Это усложнит нашу работу и повысит вероятность ошибок.
  • Используйте стандартный порядок выбора. Мы не только ограничиваем энтропию таблицы стилей, но и, поскольку новые правила «автоматически» попадают в четко определенные места, получаем естественную линию защиты от повторения селектора. И мы не хотим, чтобы в статьях, подобных этой, селекторы оставались «сухими». Подумайте, можете ли вы использовать мой дизайн упорядочивания селекторов, тем самым помогая сообществу веб-разработчиков стандартизировать его, или создать свой собственный.

Требования к инструментам
Хотя мы продолжаем изучать эффективность этого подхода и способы его улучшения, есть также несколько задач, решение которых наши инструменты могут облегчить.
  • Редакторы могут помочь нам избежать повторяющихся объявлений, выделяя их. Лично я думаю, что небольшой символ «!» в конце строки, настраиваемый в каждом редакторе, был бы замечательным решением, как и возможность игнорировать или отключать уведомления для определенных строк. Это значительно упростило бы работу по оптимизации: не только для отслеживания избыточности, но и для получения представления о том, насколько проблематичен тот или иной случай. некоторых случаях таблицы стилей на 90% состоят из повторений.
  • Я уверен, у вас остались вопросы; но надеюсь, что их осталось меньше, чем раньше, когда мы в течение многих лет пренебрегали этой оптимизацией. С моей точки зрения, DRY CSS позволил бы нам более трезво взглянуть на переменные и другие функции, которые попали в спецификации CSS.

Эти вопросы, конечно, следует принимать во внимание, и я надеюсь, что вы поможете нам всем поработать над ними. Пример с Яндексомпоказал, что отсутствие повторяющихся объявлений — не панацея. Это помогает сделать CSS компактнее и управляемее, но всё же есть крайние случаи, когда он усложняется. Нам будет полезно изучить эти моменты.
Наконец, я считаю, что избегание повторяющихся объявлений является важным способом работы с CSS. Фактически, я не вижу никакого другого метода оптимизации, помимо создания ваших личных рекомендаций по коду, потому что без систематического подхода к на предотвращению повторения вся наша работа просто увеличивает энтропию, которая не помогает писать качественный код. Но именно к нему мы стремимся как профессионалы. Давайте уделим больше внимания качеству кода и парадигме DRY CSS, и посмотрим, что мы можем автоматизировать, не забывая о своем мастерстве.
===========
Источник:
habr.com
===========

===========
Автор оригинала: Jens Oliver Meiert
===========
Похожие новости: Теги для поиска: #_css, #_klientskaja_optimizatsija (Клиентская оптимизация), #_frontend, #_css, #_optimization, #_dont_repeat_yourself, #_blog_kompanii_domklik (
Блог компании ДомКлик
)
, #_css, #_klientskaja_optimizatsija (
Клиентская оптимизация
)
Профиль  ЛС 
Показать сообщения:     

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

Текущее время: 26-Ноя 01:05
Часовой пояс: UTC + 5