Как писать более чистый CSS и рациональный SASS

Автор оригинала: Anthony Dispezio
  • Перевод
Sass заработал репутацию среди разработчиков интерфейсов благодаря переводу сложного CSS в разумный многоразовый код. Это бесспорно важно для масштабирования и поддержки, и позволяет разработчикам устранять недостатки, представленные в традиционном CSS.

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

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


Скромная примесь


Примеси – это основные «кирпичи» для построения Sass. Просто заверните группу свойств или селекторов в примеси, и код можно будет использовать повторно, включив примесь чуть позже.
Единоразовое написание общего кода позволяет вносить дальнейшие изменения в одном месте – ключевом участнике методологии DRY. Данный пример примеси кнопки содержит свойство border, которое потом используется различными классами кнопок:

SCSS
@mixin button {
    border-radius: 4px;
    border: 4px solid black;
}

.search-button {
    @include button;
    background-color: blue;
}

.cancel-button {
    @include button;
    background-color: red;
}


CSS
.search-button {
    border-radius: 4px;
    border: 4px solid black;
    background-color: blue;
}

.cancel-button {
    border-radius: 4px;
    border: 4px solid black;
    background-color: red;
}


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

SCSS
@include button('search', blue);
@include button('cancel', red);


CSS
.search-button {
    background-color: blue;
    border-radius: 4px;
    border: 4px solid black;
}
.cancel-button {
    background-color: red;
    border-radius: 4px;
    border: 4px solid black;
}


Даже в этом небольшом примере легко увидеть рост эффективности Sass.

Негативные аспекты и дублирование


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

«Сушим» код с помощью наследования


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

SCSS
.button {
    border-radius: 4px;
    border: 4px solid black;
}

.search-button {
    @extend .button;
    background: blue;
}


CSS
.button,
.search-button {
    border-radius: 4px;
    border: 4px solid black;
}

.search-button {
    background: blue;
}


Теперь у нашего вывода есть только одно значение свойств границы, которое поддерживают наши кнопки.

Счастливы вместе


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

SCSS
.button {
    border-radius: 4px;
    border: 4px solid black;
}

@mixin button($name, $background-color) {
    .#{$name}-button {
        background-color: $background-color;
        @extend .button;
    }
}

@include button('search', blue);
@include button('cancel', red);


Классы, которые наследуют общие свойства кнопки, сгруппированы с классом .button, что исключает дублирование свойств границы.

CSS
.buton, .search-button, .cancel-button {
    border-radius: 4px;
    border: 4px solid black; 
}

.search-button {
    background-color: blue; 
}

.cancel-button {
    background-color: red;
}


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

Ищем золотую середину


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

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

PAYSTO
38,17
Компания
Поделиться публикацией

Комментарии 36

    +2
    В тексте немного код сбился, не на месте. В разделе про наследование существующего класса блок с результирующим CSS улетел в предыдущий раздел, по-моему. Если это так, поправьте пожалуйста.
      +1
      Обычно CSS в данном случае выглядел бы так
      .buton {
          border-radius: 4px;
          border: 4px solid black; 
      }
      
      .search-button {
          background-color: blue; 
      }
      
      .cancel-button {
          background-color: red;
      }
      


      HTML так
      <button class="button cancel-button">Cancel</button>
      


      Чем это хуже того что получилось в SCSS я не понимаю.
      В данном конкретном случае
      Плюсы
      не вижу таких.

      Минусы
      1. Совершенно новый синтаксис, на изучение (запоминание) которого нужно тратить время.
      2. Если сосчитать число символов в коде, то в моем примере их меньше, а значит я потратил меньше времени, набирая код на клавиатуре.

      P.S. давно слежу за всеми этими новомодными SASS, LESS… но число объективных достоинств, которые могу назвать, никак не перевесят число недостатков использования этих инструментов.
        +2
        Ещё плюс:
        3. Сравните синтаксис и попробуйте его понять. В моем примере он читается очень быстро. В примере выше вызывает зависание на пару минут. Найти и что-то исправить в обычном CSS проще, чем в коде с mixin.
          0
          Академический интерес, а сколько строк css кода в ваших проектах?
            +1
            Частично вы правы. А вот насчёт провосходства минусов над плюсами вынужден не согласиться.

            Чего стоит лишь только вкладывание правил? Конечно, злоупотреблять ими не стоит (да и микс-ины дают очень большой CSS-ный выхлоп), но, как по мне, вкладывание давно пора сделать нативно поддерживаемым в CSS.

            Если бы LESS/SCSS парсился браузером без необходимости прекомпиляции в CSS — цены бы ему не было.
              +2
              >>как по мне, вкладывание давно пора сделать нативно поддерживаемым в CSS.

              Честно говоря это единственное, что мне нравится в инструментах подобных SASS. Остальное или очень редко используется, или можно сделать без создания нового языка.
                +1
                Я из препроцессоров вынес только три вещи:
                1) нахожу возможность писать media внутри класса более удобным и читаемым, чем классы внутри media.
                2) Переменные. Тут без комментариев.
                3) Игры с цветами. Хорошо для генерации всяких цветовых схем. Задал базовый цвет, а в других местах, все поменялось в зависимости от него. Но это спецефично.

                Что же до миксинов. То пример из статьи ужасен на мой взгляд. Сам делаю как у вас. Миксин позволяю себе, когда надо вынести несколько свойств в одну строчку, а в html он смысловой нагрузки не несет. Напимер, button button-succeed, примелимо. button-rounded — нет. То есть вякие вертикальные выравнивания, обтекания, спрос флоатов, выставления позиционирования – тут миксин полезен.
              0
              Пример здоровский. И он работает. Но когда у вас появятся как минимум 4 похожих кнопки, тогда SASS и LESS будут короче. Вспомните те же бутстраповские кнопки (дефаулт, примари, варн, дангер, линк, инлаин). Кстати, в бутстрапе все классы -варн, -дангер, -инфо и т.д. имеют свой цвет, что так же легче и быстрей сделать миксинами.

              По вашим минусам:
              1. Не увидел совершенно нового синтаксиса, особенно в SCSS (кто вам мешает писать чистый CSS на SCSS в конце концов?)
              2. «Набирая на клавиатуре» — да. «потратил меньше времени» — скорей всего нет. Написать код изящно и кратко занимает гораздо больше времени, чем на скорую руку намазать спагетти.
                0
                Эм, в бутстрапе как раз используется описанный выше вариант.
                <button class="btn btn-danger">Alert!</button>
                
                  0
                  Эм, исходники бутстрапа написаны на SASS/LESS.

                  Bootstrap ships with vanilla CSS, but its source code utilizes the two most popular CSS preprocessors, Less and Sass. Quickly get started with precompiled CSS or build on the source.
                    0
                    Bootstrap пишется cтрого на LESS, это потом из LESS он конвертится в Sass для аудитории пользователей Sass
                    Код с Sass lаже в отдельной репе
                  +1
                  Про бутстрап хороший пример. Но есть одна особенность: это массовый продукт. Сколько вы используете видов кнопок оттуда на своем проекте? (если все 6, то попрошу пруф). В одном конкретном проекте обычно используется 2 — 3 цветовых стиля кнопок. Поэтому выхлоп с использованием CSS процессоров ощутим только на массовых продуктах. (ИМХО) Я к тому, что инструменты надо использовать с умом, а не просто потому что это модно (часто такое встречал).
                    0
                    Бутстрап обычно использую для административных интерфейсов, поэтому все 6 зачастую задействованы (тогглы — серый, сохранение — синий, удалить — красный, добавить — зелёный, дебаг — оранжевый и т.д.). Но в целом, с вами согласен, т.к. львиная доля компонентов бутстрапа не используется.

                    Однако нашел для себя отличное решение — gridle. В каждом проекте включаешь именно те фичи, которые будут использоваться, как следствие даёт минимальные размеры для генерируемых css файлов (цветов и разукрашек там нет, только лейаут).
                  0
                  Мне нравится SASS, я люблю SASS, шикарные возможности, очень круто. Но не всегда понимаю, как с его «выхлопом» работать дальше. Сделал я проект, допустим, CSS написал на SASS, отдал клиенту. Проект развивается, пригласили разработчиков, которые не знают SASS, но знают LESS — как быть в такой ситуации. Выход один — править скомпиленный CSS.

                  В скорости разработки SASS — лучший помощник. Когда количество строк кода не превышает 2000. Потом ливрелодится компилл долго, Ctrl+S умножается на два с интервалом в 400мс. Может у меня машина слабая, но это немного раздражает.

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

                  На мой взгляд SASS подходит для быстрой разработки какого-нибудь LP, который ты потом отдашь клиенту и благополучно о нем забудешь, но преимущество у разработчика безусловное — в скорости разработки.
                    +1
                    Проект развивается, пригласили разработчиков, которые не знают SASS, но знают LESS — как быть в такой ситуации.

                    Выход — выучить уже наконец SASS.

                    А то может они CSS не знают, тогда выход — писать инлайн стили или теги ?
                  0
                  del
                    +1
                    Вообще в данном конкретном случае целесообразнее использовать плейсхолдеры, тогда не создаётся избыточный класс (если он, конечно, не используется, что довольно редко на практике SASS)
                    Код с плейсхолдерами
                    %button {
                        border-radius: 4px;
                        border: 4px solid black;
                    }
                    
                    @mixin button($name, $background-color) {
                        .#{$name}-button {
                            background-color: $background-color;
                            @extend %button;
                        }
                    }
                    
                    @include button('search', blue);
                    @include button('cancel', red);
                    

                    .search-button, .cancel-button {
                      border-radius: 4px;
                      border: 4px solid black;
                    }
                    
                    .search-button {
                      background-color: blue;
                    }
                    
                    .cancel-button {
                      background-color: red;
                    }
                    
                    



                    А для всей статьи можно сделать простое и короткое (как по мне, так ещё и очевидное) правило: если шаблон — наследование, если шаблон с переменными — примеси. Соответственно, если в большом шаблоне одна строка с переменными — их можно легко комбинировать.
                      0
                      На мой взгляд подобные возможности препроцессорных языков для css (less тоже это умеет), скорее костыль, которого стоит избегать. Это примерно как important. Понятно, что gzip обожмет такие повторения, но все же лучше избегать .extend там, где без этого можно обойтись. На пример в примере с button. Просто используйте 2 класса.
                        0
                        Всю статью не читал, потому что как обычно, очередная каша про то, как правильно писать SASS, но вот насчет первого примера в «Скромных примесях» выскажусь. Я считаю, что это чистейшей воды антипаттерн и правильно было бы сделать все на чистом CSS и не вы**ываться:

                        .button {
                            border-radius: 4px;
                            border: 4px solid black;
                        }
                        
                        .search.button {
                            background-color: blue;
                        }
                        
                        .cancel.button {
                            background-color: red;
                        }
                        


                        Не знаю, как с SASS, но LESS позволяет просто сделать так (и я считаю, что это элегантно):

                        .button {
                            border-radius: 4px;
                            border: 4px solid black;
                        
                            &.search {
                                background-color: blue;
                            }
                        
                            &.cancel {
                                background-color: red;
                            }
                        }
                        


                        Почему нужно делать именно так? Это банально интуитивнее. Потом, в HTML коде вы будете писать все естественным языком, не городить забор. Взгляните на пример:

                        <span class="search icon"></span>
                        <span class="icon-search"></span>
                        


                        Cогласитесь, первый вариант будет лучше второго, потому что это естественный язык, естественная подача информации. По большому счету, никакого существенного отличия вроде и нет, но разметку писать стало проще понятней и мы не стали плодить сущности с этими вашими миксинами. Миксины — это хороший пример того, как народ неверно интерпритирует концепцию. Изначально они создавались, чтобы выносить какие-то квирки (хаки/костыли/whatever) в отдельные функциональные единицы кода.
                          0
                          stylus:
                          .button
                            border-radius 4px
                            border 4px solid black
                          
                            .search&
                                background-color blue
                          
                            .cancel&
                                background-color red
                          

                          Раньше тоже пользовался и SASS и LESS но в последнее время Stylus применяю
                            0
                            Мне как питонисту очень удобен Stylus отсутсвием скобочек и привычные отступы))
                              0
                              Я тоже питонист, но искринне убежден, что определение семантики кода отступами — это самый худший антипаттерн, который когда либо был представлен в пайтоне. Но, опять-таки, все зависит от команды и инструментария. Ящитаю, что LESS лучше читается, чем стилус, хотя первый однозначно не без недостатков.
                                0
                                Ну я в Stylus нашел много хорошего, и выбрал его уже после того как несколько лет пользовался LESS/Sass.
                                Насчет отступов — я и шаблоны пишу на slm/jade в последнее время))
                                Python/Django,Flask или Golang, Erlang только для бэкенда с API, а фронт пишу отдельно, используя средства фронт-енд разработки и MVC-фреймворки(это я к тому, что могут возникнуть вопросы почему я пишу шаблоны на slm а не на jinja2 например)
                                  0
                                  Думаешь, стоит посмотреть в сторону stylus/slm? Я полгодика клепаю приложение на фласке (джанго вызывает у меня небольшое отвращение), от jinja2 люто-бешенно кончаю.
                            0
                            В вашем же примере LESS не получится того, что выше написано на СSS
                            У вас получится .button.search и .button.cancel а не как выше в CSS .search.button .cancel.button
                              0
                              Но ведь .button.search это тоже самое, что и .search.button. Мой способ же интуитивнее и проще пишется, без горождения заборов с @extend и прочими миксинами.
                                0
                                Мой со стилусом приятнее на вид)) без всех этих {:;}
                                0
                                А, я кажется понял, о чем ты. Да, конечный код будет не 1:1 c указанным листингом на CSS, но суть, я так понимаю, сохраняется. Согласись, это в любом случае лучше того, что автор проталкивает в статье.
                                  0
                                  мой тоже будет не 1:1 — стилус сгенерит цвета в hex типа black -> #000
                              +1
                              По поводу всего этого безобразия у меня есть единственный комментарий: «сами создаём себе проблемы, а потом благополучно их решаем».
                                0
                                Чрезмерное увлечение @extend ведёт к космическому росту количества селекторов и, возможно, проблеме 4096 селектора в IE.
                                  0
                                  Честно говоря, не понимаю проблемы размера css-файла при использовании примесей. Ведь gzip все это великолепно сожмет же? А большое количество @extend, как верно заметил vdv73rus, может привести к багам в итоге.
                                    0
                                    Верно, то что имеется куча примесей в less/stylus/sass это не значит что в результате css cкомпилится с кучей этих миксинов.
                                    Миксины имеет смысл создавать когда что-то очень часто повторяется.
                                    Как один из наиболее наглядных примеров плюсов использования миксинов в less/stylus/sass перед использованием чистого сss это конечно использование префиксов браузеров. Например можно сделать миксин типа:
                                    .blur(@blur) {
                                      -webkit-filter: blur(@blur);
                                      -moz-filter: blur(@blur);
                                      -o-filter: blur(@blur);
                                      -ms-filter: blur(@blur);
                                      filter: blur(@blur);
                                    }
                                    // и потом везде писать просто:
                                    .some-class {
                                      .blur(значение);
                                    }
                                    .another-class {
                                      .blur(значение);
                                    }
                                    .one-more-class {
                                      .blur(значение);
                                    }
                                    

                                    а не расписывать все в кучу строк для каждого браузера.

                                    В СSS это было бы:
                                    .some-class {
                                      -webkit-filter: blur(значение);
                                      -moz-filter: blur(значение);
                                      -o-filter: blur(значение);
                                      -ms-filter: blur(значение);
                                      filter: blur(значение);
                                    }
                                    .another-class {
                                      -webkit-filter: blur(значение);
                                      -moz-filter: blur(значение);
                                      -o-filter: blur(значение);
                                      -ms-filter: blur(значение);
                                      filter: blur(значение);
                                    }
                                    .one-more-class {
                                      -webkit-filter: blur(значение);
                                      -moz-filter: blur(значение);
                                      -o-filter: blur(значение);
                                      -ms-filter: blur(значение);
                                      filter: blur(значение);
                                    }
                                    


                                    Тут же вся фишка не в том какой в результате CSS будет по размеру, а как быстро ты его напишешь.
                                      0
                                      В 2015 году не надо так. Читайте про autoprefixer.
                                        0
                                        Это было лишь примером))
                                        вообще у меня в gulpfile автопрефиксер для стилуса стоит: prefixer = require 'autoprefixer-stylus'
                                          0
                                          Есть куда больше разнообразных квирков, которые автопрефиксеры не решают. В данном случае, это просто пример. Суть в том, что миксины не нужны для того, что показал в статье автор.

                                    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                    Самое читаемое