Лучшая практика для контекстных или основанных на состоянии переопределений дочерних компонентов - PullRequest
1 голос
/ 11 апреля 2019

У меня разбиты таблицы стилей для представления отдельных компонентов (nav, nav-item и т. Д.). Я пытаюсь понять, как лучше разрешить родительскому элементу переопределять дочерний стиль в зависимости от его состояния или контекста (изменить элемент nav, когда навигация открыта, изменить nav, когда он находится на домашней странице и т. Д.).

Скажем, например, у меня есть навигация, которая содержит элементы навигации. Они разделены на свои собственные таблицы стилей nav.scss и nav-item.scss. Когда к компоненту .nav добавлен класс .open, я хочу, чтобы фон элемента .nav стал красным. Я мог бы сделать это так:

/* nav.scss */
@import nav-item.scss
.nav{
    &.open{
        .nav-item{
            background: red;
        }
    }
}

 /* nav-item.scss */
.nav-item{
    background: blue;
}

Это работает нормально, но теперь стили, которые применяются к .nav-item, применяются вне таблицы стилей .nav-item, если это происходит в нескольких местах, это может затруднить отслеживание того, какой файл добавляется какие стили для .nav-элемента. Альтернатива такова:

 /* nav.scss */
@import nav-item.scss
.nav{

}

 /* nav-item.scss */
.nav-item{
    background: blue;
    .nav.open &{
        background: red;
    }
}

Этот синтаксис позволяет мне добраться до родительского дерева и посмотреть, вложен ли я в .nav.open, а затем применить красный фон. Это здорово, потому что все стили nav-items теперь содержатся в одном файле, что упрощает просмотр всех возможностей. Тем не менее, я все еще ссылаюсь на внешний класс, который кажется неправильным, плюс, если у меня есть много вариантов, этот файл может быстро испортиться:

 /* nav-item.scss */
.nav-item{
    background: blue;
    .nav.open &{
        background: red;
    }
    .nav.sticky.open &{
        background: blue;
    }
    .homepage .nav.open &{
        @media screen and (max-width: $break-small) {
             background: green;
         }
    }
}

Мы можем попробовать использовать миксины:

 /* nav.scss */
@import nav-item.scss
.nav{
    &.open{
        @include navItemRedWide();
    }
}

 /* nav-item.scss */
.nav-item{
    background: blue;
}
@mixin navItemRedWide() {
    .nav-item {
        background: red;
        width: 400px;
    }
}

Это эффективно позволяет nav-item.scss содержать все его собственные стили и позволяет .nav определять, какие стили применять, без возможности прямого добавления / изменения свойств стиля в классе. Это кажется лучше, чем другое решение, но может привести к большому количеству миксинов и, возможно, к большому количеству повторяющегося кода, если мне придется повторять вложение в каждом миксине:

 /* nav-item.scss */
@mixin navItemLargeIcon() {
    .nav-item {
       .inner{
           .icon{
                font-size: 4rem;
           }       
       }
    }
}
@mixin navItemSmallIcon() {
    .nav-item {
       .inner{
           .icon{
                font-size: 1rem;
           }       
       }
    }
}

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

 /* nav.scss */
@import nav-panel.scss
@import nav-item.scss
.nav{
    &.open{
        @include navItemRed();
        @include navPanelRed();
    }
}

 /* nav-panel.scss */
@import nav-item.scss
.nav-panel{
    background: blue;
    &.collapse{
       @include navPanelBlue();
    }
}
@mixin navPanelRed() {
    .nav-panel {
        background: red;
    }
}

 /* nav-item.scss */
.nav-item{
    background: blue;
}
@mixin navItemRed() {
    .nav-item {
        background: red;
    }
}
@mixin navItemBlue() {
    .nav-item {
        background: red;
    }
}

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

Каков наилучший способ применения стилей контекста или состояния и переопределений дочерних компонентов?

1 Ответ

1 голос
/ 12 апреля 2019

Как вы описываете, есть много способов обработки контекста в SCSS, но если бы мне пришлось выбрать один, это было бы на основе миксина

//  -----------------------------
//  _nav.scss
//  -----------------------------
//  Base styling
@mixin nav {
    .nav {
        ...
    }
}

//  Context overrides/add-ons
//  note! keep context overrides in the component scss - it makes 
//  it easier to track and provides an overview of variations 
@mixin nav-context-1 { .context-1 .nav { ... } }
@mixin nav-context-2 { .context-2 .nav { ... } }
@mixin nav-context-3 { .context-3 .nav { ... } }

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

//  -----------------------------
//  style.scss
//  -----------------------------
//  Imports
@import 
    '_reset.scss',
    '_typography.scss',
    '_nav.scss',
    ...
;


//  Assemble 
@include reset: 
@include typography;

@include nav;
@include nav-context-1;
@include nav-context-2;
//  @include nav-context-3;     we didn't need this anyway

Опять же, нет единого ответа - но вышеизложенный - тот, который я нашел наиболее структурированным и простым в обращении.

PS. Небольшое отклонение от вышесказанного может заключаться в том, чтобы контекстные миксины зависели от nav при включении включения. Таким образом, Sass выдаст ошибку, если вы попытаетесь включить переопределение без присутствия базы

@mixin nav {
    .nav {
        ...
        @content; //  contexts will go here
    }
}

//  note! we use & in the selector to disallow include at root level
@mixin nav-context-1 { .context-1 & { ... } }
@mixin nav-context-2 { .context-2 & { ... } }
@mixin nav-context-3 { .context-3 & { ... } }


//  Assemble
@include nav {
    @include nav-context-1;
    @include nav-context-2;
    @include nav-context-3;
}

@include nav-context-3;  // this will throw an error 



Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...