Sass 子组件的上下文或基于状态的重写的最佳实践

Sass 子组件的上下文或基于状态的重写的最佳实践,sass,Sass,我将样式表分解为表示单个组件(nav、nav项等)。我试图理解允许家长基于其状态或上下文覆盖子样式的最佳方式(在导航打开时更改导航项,在主页上更改导航项,等等) 例如,假设我有一个包含导航项目的导航。它们被分为各自的样式表nav.scss和nav-item.scss。当.nav组件添加了.open类时,我想使.nav项背景变成红色。我可以这样做: /* nav.scss */ @import nav-item.scss .nav{ &.open{ .nav-ite

我将样式表分解为表示单个组件(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项的样式被应用于.nav项样式表之外,如果在多个位置发生这种情况,则很难跟踪哪个文件正在向.nav项添加哪些样式。另一种选择是:

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

}

 /* nav-item.scss */
.nav-item{
    background: blue;
    .nav.open &{
        background: red;
    }
}
此语法允许我访问父树,查看是否嵌套在.nav.open中,然后应用红色背景。这很好,因为所有导航项目样式现在都包含在同一个文件中,因此更容易查看所有可能的样式。但是,我仍然引用了一个外部类,这似乎是错误的,另外,如果我有很多变体,这个文件可能会很快变得糟糕:

 /* 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;
         }
    }
}
我们可以尝试使用mixin:

 /* 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.scs包含它自己的所有样式,并允许.nav指定要应用的样式,而无需直接在类上添加/修改样式属性。这似乎比其他解决方案更好,但如果我必须在每个混合中重复嵌套,可能会导致大量混合,并可能导致大量重复代码:

 /* nav-item.scss */
@mixin navItemLargeIcon() {
    .nav-item {
       .inner{
           .icon{
                font-size: 4rem;
           }       
       }
    }
}
@mixin navItemSmallIcon() {
    .nav-item {
       .inner{
           .icon{
                font-size: 1rem;
           }       
       }
    }
}
最后,如果有一个子组件的子组件需要从中提取mixin,那么这个问题就更加复杂了:

 /* 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;
    }
}
现在我有根文件导入子对象的子对象只是为了应用它们的mixin,而中间的子对象也在导入子对象,并可能应用覆盖的mixin,而while的东西就变成了不可维护的混乱


应用这些基于上下文或状态的样式和子组件重写的最佳实践是什么?

正如您所描述的,在SCS中有很多处理上下文的方法,但如果我必须选择一种,它将是基于混合的

//  -----------------------------
//  _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 { ... } }
使用mixin(用于一切)可以预测最终CSS中打印的内容作为编译样式。SCS将只包含导入和包含(汇编)

同样,没有一个答案——但我发现上面的答案是最有条理、最容易处理的

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 



@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