Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

no-duplicate-selectors Sass mixed declarations deprecation #7893

Open
portikM opened this issue Jul 31, 2024 · 8 comments
Open

no-duplicate-selectors Sass mixed declarations deprecation #7893

portikM opened this issue Jul 31, 2024 · 8 comments
Labels
status: needs discussion triage needs further discussion

Comments

@portikM
Copy link

portikM commented Jul 31, 2024

What is the problem you're trying to solve?

Starting from version 1.77.7 Sass is deprecating support for mixed declarations. Fixing and addressing warnings produced by Sass requires wrapping nested declarations in & {}:

Old way

.example {
  color: red;

  a {
    font-weight: bold;
  }

  font-weight: normal;
}

New way

.example {
  color: red;

  a {
    font-weight: bold;
  }

  & {
    font-weight: normal;
  }
}

In this case Stylelint considers the & {} to be a duplicate selector (expected behaviour). For now I disable the no-duplicate-selectors rule for next line whenever I need to use the above selector, but I would like to discuss a more sophisticated solution.

Screenshot 2024-07-31 at 12 09 49 PM
Screenshot 2024-07-31 at 12 10 48 PM

What solution would you like to see?

allowMixedDecls secondary option in no-duplicate-selectors rule (or something similar) that would allow the nested & {} selector.

@Mouvedia
Copy link
Member

related: #7873

@Mouvedia Mouvedia added the status: needs discussion triage needs further discussion label Jul 31, 2024
@romainmenke
Copy link
Member

Hi @portikM,

Out of curiosity, can you give a real world example where you really need/want declarations after nested rules?

So you really need this:

.example {
  color: red;

  a {
    font-weight: bold;
  }

  font-weight: normal;
}

But can't rewrite to:

.example {
  color: red;
  font-weight: normal;

  a {
    font-weight: bold;
  }
}

The CSSWG thoroughly checked this to make sure it wouldn't cause issues on existing sites and found that in practice CSS authors didn't write declarations after rules in a way that actually affected the outcome. As is also the case in your example.

I am not sure why Sass is giving the guidance to use & {} when moving the declarations seems like a simpler way to resolve this issue.

@portikM
Copy link
Author

portikM commented Jul 31, 2024

Hi @portikM,

Out of curiosity, can you give a real world example where you really need/want declarations after nested rules?

So you really need this:

.example {
  color: red;

  a {
    font-weight: bold;
  }

  font-weight: normal;
}

But can't rewrite to:

.example {
  color: red;
  font-weight: normal;

  a {
    font-weight: bold;
  }
}

The CSSWG thoroughly checked this to make sure it wouldn't cause issues on existing sites and found that in practice CSS authors didn't write declarations after rules in a way that actually affected the outcome. As is also the case in your example.

I am not sure why Sass is giving the guidance to use & {} when moving the declarations seems like a simpler way to resolve this issue.

The screenshots I attached is actually a real world use-case for this. 100% of impacted lines I've fixed over past couple days since we started using Sass 1.77.7 were declarations that follow one or more mixins. Often times we'll have some generic mixin that comes with nested rules and then we'll want to override/extend that mixin with some specific to use-case declarations. High-level example:

@mixin genericButtonMixin {
  background-color: transparent;

  .icon {
    stroke: currentColor;
  }
}

button.primary {
  @include genericButtonMixin;

  background-color: blue;
  color: red;
}

@Mouvedia
Copy link
Member

There's also a case for automatic migration tools on big codebases to avoid introducing regressions.
e.g. https://sass-lang.com/documentation/cli/migrator/

@romainmenke
Copy link
Member

Ah, yes, with mixins you can write an at-rule that actually represents both declarations and/or more rules. This is also the primary reason that the CSSWG changed the behavior of nesting, they work in a more interesting way when nested rules and declarations preserve their order. Unfortunately native nesting is different from how Sass works.

I get that Sass wants to provide a way for CSS authors to opt-in to the standard CSS mechanics today and that writing & {} is a clean way to get this. Even when the same code written as standard CSS wouldn't really make sense. It isn't wrong, but just needlessly verbose.

But eventually Sass will update and work like native CSS for all nested delcarations and you will no longer need to write & {}, correct?

So if we add a plugin option to help Sass authors it will only be briefly useful.


Is there a wider use case for ignoring & {} specifically?

Have there been requests to ignore specific selectors or patterns for this rule? I couldn't spot any.

Is it better to use configuration comments to disable this rule in very specific cases?

@Mouvedia
Copy link
Member

Mouvedia commented Jul 31, 2024

related: #2198 (comment), #2199

@ybiquitous
Copy link
Member

I agree with @romainmenke. If this pattern helps only developers using Sass, it would be against our rule criteria:

- generally useful; not tied to idiosyncratic patterns

Also, this issue is related to stylelint-scss/stylelint-scss#1020. The stylelint-scss repo seems more suited for this discussion.

@c0d3x
Copy link

c0d3x commented Oct 1, 2024

How do I solve this:

@mixin col-2($defaultSpan: 1) {
    @include grid-layout();
    grid-template-columns: repeat(auto-fit, minmax(40%, 0.5fr));
    > * {
        grid-column: span $defaultSpan;
        @include breakpoints.tablet() {
            grid-column: span 1;
        }
    }
    .half-width {
        grid-column: span 1;
    }
    .full-width {
        grid-column: span 2;
    }
    @include breakpoints.mobile() {
        grid-template-columns: 1fr;
        .full-width {
            grid-column: span 1;
        }
    }
    @include browserhacks.ie_only {
        .half-width {
            width: 50%;
        }
        .full-width {
            width: 100%;
        }
    }
}

│ Module Warning (from ../.yarn/__virtual__/sass-loader-virtual-42d1bf09a7/4/.yarn/berry/cache/sass-loader-npm-16.0.2-eafa07389f-10c0.zip/node_modules/sass-loader/dist/cjs.js): │ Deprecation Warning on line 55, column 4 of file://src/css/layout/_grid.scss:55:4: │ Sass's behavior for declarations that appear after nested │ rules will be changing to match the behavior specified by CSS in an upcoming │ version. To keep the existing behavior, move the declaration above the nested │ rule. To opt into the new behavior, wrap the declaration in& {}. │ │ More info: https://sass-lang.com/d/mixed-decls │ │ 55 | grid-template-columns: repeat(auto-fit, minmax(40%, 0.5fr)); │ │ │ src/css/layout/_grid.scss 56:5 col-2()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: needs discussion triage needs further discussion
Development

No branches or pull requests

5 participants