Mrchief
Mrchief

Reputation: 76258

How to keep this CSS code DRY along with satisfying no-descending-specificity

Here's my CSS block:

:global {
  table, .table {
    border-collapse: collapse;
    border-spacing: 0;
    width: 100%;
    font-size: 0.8em;
    font-family: var(--font-family-roboto);
    font-weight: normal;
    letter-spacing: .25px;

    &.fixed {
      table-layout: fixed;
    }

    &.disabled {
      opacity: 0.5;
    }

    > thead {
      border-bottom: 1px solid var(--grey-light);
    }

    > thead th {
      color: var(--blue);
      text-transform: uppercase;
      font-family: var(--font-family-simplon);
      font-weight: bold;
      letter-spacing: 1px;
      text-align: left;
      line-height: 12px;

      span {
        vertical-align: top;
      }
    }

    > thead th,
    > tfoot td,
    > tbody td {
      padding: 5px;
      word-wrap: break-word;
      vertical-align: middle;
      white-space: pre;

      &:last-child,
      &:first-child {
        padding-left: 20px;
      }
    }

    > tfoot {
      background-color: var(--grey-lighter);
      font-weight: var(--font-weight-bold);
      letter-spacing: 1.25px;
      text-transform: uppercase;
    }

    > caption {
      text-align: left;
      font-size: 1.2em;
      margin-bottom: 15px;
      padding: 0 2px;
    }
  }
}

stylelint complains about:

 39:5  ✖  Expected selector ":global table > thead th" to come before selector ":global .table > thead th"                           no-descending-specificity
 41:5  ✖  Expected selector ":global table > tbody td" to come before selector ":global .table > tfoot td"                           no-descending-specificity
 47:7  ✖  Expected selector ":global table > tbody td:last-child" to come before selector ":global .table > tfoot td:last-child"     no-descending-specificity
 48:7  ✖  Expected selector ":global table > thead th:first-child" to come before selector ":global .table > thead th:last-child"    no-descending-specificity
 48:7  ✖  Expected selector ":global table > tfoot td:first-child" to come before selector ":global .table > tfoot td:last-child"    no-descending-specificity
 48:7  ✖  Expected selector ":global table > tfoot td:first-child" to come before selector ":global .table > tbody td:last-child"    no-descending-specificity
 48:7  ✖  Expected selector ":global table > tbody td:first-child" to come before selector ":global .table > tfoot td:last-child"    no-descending-specificity
 48:7  ✖  Expected selector ":global table > tbody td:first-child" to come before selector ":global .table > tbody td:last-child"    no-descending-specificity
 48:7  ✖  Expected selector ":global table > tbody td:first-child" to come before selector ":global .table > tfoot td:first-child"   no-descending-specificity

It seems like it wants me to split table and .table declarations but that will only duplicate the styles. Not sure how to keep the code DRY and satisfy stylelint. Any ideas?

These errors can be reproduced in here https://stylelint.io/demo/.

Upvotes: 2

Views: 1883

Answers (1)

Mrchief
Mrchief

Reputation: 76258

Confirmed with stylelint authors that this behavior is as intended:

I believe the rule is behaving as documented. It compares the desugared CSS e.g. table > thead th:first-child has a specificity of 0,1,3 whereas .table > thead th:last-child has a specificity of 0,2,2. So the source order and the specificity order are not aligned. The desugared CSS has interwoven class selectors and element selectors. The rule is designed to warn against these.

I can think of two options, either refactor so they aren't interwoven or turn off the rules for this code block using /* stylelint-disable .. */ command comments.

The only viable solutions in this case is to refactor the code or turn off the rule. I'm opting for later.

Upvotes: 1

Related Questions