node-sass icon indicating copy to clipboard operation
node-sass copied to clipboard

@extend produces incorrect CSS when :nth-child(n+4) is present

Open ericwong3 opened this issue 5 years ago • 0 comments

Problem

(I know the template says compilation error should go and open issue in libsass, but this problem is only happening in node-sass, and does not occur in sassmeister even if libsass is selected as the compiler, so I believe the issue lies in node-sass)

The problem apparently has to do with :nth-child, @extend and the magic number n+4 (huh but yes)

Following is the code that will result in the wrong result. For context, this is sort of a polyfill for CSS grid on IE that simulates column gap, row gap, and cell auto-placement. Column gap is done with empty column, row gap with cell's margin-top, and cell placement with @for loop. (There is a more minimal example below)

$grid-gutter-width: 40px;

%ie-grid {
  display: -ms-grid;
  -ms-grid-columns: 1fr $grid-gutter-width 1fr $grid-gutter-width 1fr;

  // simulate row-gap on IE
  > *:nth-child(n + 4) {
    margin-top: $grid-gutter-width;
  }

  @for $i from 1 through 99 {
    $row: floor( ($i + 2) / 3); // (1,2,3) => 1 ; (4,5,6) => 2 ...
    $column: $i % 3; // (1,4,7,...) => 1 ; (2,5,8,...) => 2 ; (3,6,9,...) => 3 ...

    @if $column == 0 {
      $column: 3;
    }

    > *:nth-child(#{$i}) {
      -ms-grid-column: ($column - 1) * 2 + 1; // (1,2,3) => (0,1,2) => (0,2,4) => (1,3,5)
      -ms-grid-row: $row;
    }
  }
}

.test {
  @extend %ie-grid;
}

This will produce the following CSS:

.x {
  display: -ms-grid;
  -ms-grid-columns: 1fr 40px 1fr 40px 1fr;
}

.x > *:nth-child(n + 4) {
  margin-top: 40px;
}

.x > *:nth-child(1) {
  -ms-grid-column: 1;
  -ms-grid-row: 1;
}

.x > *:nth-child(n + 4) { /* !!! */
  -ms-grid-column: 3;
  -ms-grid-row: 1;
}

.x > *:nth-child(3) {
  -ms-grid-column: 5;
  -ms-grid-row: 1;
}
/* .... */

As seen, :nth-child(2) is mistakenly rendered as :nth-child(n+ 4), same also happens for 25 and 44, which is replaced with n+4.

Here are some tests that I have done that give a slightest hint:

  • @extend is very likely the culprit, if I remove the .x {} block and change %ie-grid to .ie-grid, everything renders as normal.
  • If I just change %ie-grid to .ie-grid and update the @extend %ie-grid to @extend .ie-grid, both of them will inherit the n+4 weirdness.

Below is a further trim down of the above example, but I am not sure if this covers the whole issue though.

%ie-grid {
  > *:nth-child(n + 4) {
    margin-top: 1px;
  }

  > *:nth-child(44) {
    -ms-grid-column: 15;
    -ms-grid-row: 3;
  }
}

.x {
  @extend %ie-grid;
}

Renders:

.ie-grid > *:nth-child(n + 4) {
  margin-top: 1px;
}

.ie-grid > *:nth-child(n + 4) { /* !!! */
  -ms-grid-column: 15;
  -ms-grid-row: 3;
}

Environment

  • NPM version (npm -v): 6.14.5
  • Node version (node -v): v12.18.2
  • Node Process (node -p process.versions): { node: '12.18.2', v8: '7.8.279.23-node.39', uv: '1.38.0', zlib: '1.2.11', brotli: '1.0.7', ares: '1.16.0', modules: '72', nghttp2: '1.41.0', napi: '6', llhttp: '2.0.4', http_parser: '2.9.3', openssl: '1.1.1g', cldr: '37.0', icu: '67.1', tz: '2019c', unicode: '13.0' }
  • Node Platform (node -p process.platform): win32
  • Node architecture (node -p process.arch): x64
  • node-sass version (node -p "require('node-sass').info"):
node-sass       4.14.1  (Wrapper)       [JavaScript]
libsass         3.5.5   (Sass Compiler) [C/C++]
  • npm node-sass versions (npm ls node-sass):
[email protected] C:\Users\eric_\Desktop\my-project
`-- [email protected]
  `-- [email protected]

ericwong3 avatar Oct 19 '20 06:10 ericwong3