3

I have a ReactJS app, with CSS styles set for the placeholder values inside of text inputs using SASS. The following code works without problem (I've ommitted styles for other browser vendors, so I'll only show webkit):

*::-webkit-input-placeholder {
    color: rgb(126, 126, 126);
    transition: color .25s linear;
}

input:focus::-webkit-input-placeholder {
    color: rgb(187, 187, 187);
}

... others emitted for brevity ...

But because I have the same style for other browser vendors, ie *:-moz-placeholder, *::placeholder, etc., I wanted to use an @extend directive to keep my code DRY. However, the following code does not work:

%shared-placeholder {
    color: rgb(126, 126, 126);
    transition: color .25s linear;
}

%shared-placeholder-focus {
    color: rgb(187, 187, 187);
}

*::-webkit-input-placeholder {
    @extend %shared-placeholder;
}

input:focus::-webkit-input-placeholder {
    @extend %shared-placeholder-focus;
}

... others emitted for brevity ...

There is no compilation error, and I am using the @extend directive in other places in my app without problem, it just doesn't seem to work with the placeholder inputs. I don't understand why, as I assume the SASS compiler simply replaces the @extend directive with the actual style. EDIT: Turns out my assumption was wrong, see my answer below on how SASS compiles @extend directives to css.

dippas
  • 58,591
  • 15
  • 114
  • 126
sme
  • 4,023
  • 3
  • 28
  • 42
  • You can only @extend rulesets, not selectors. – connexo Mar 09 '18 at 10:37
  • It is extending a ruleset. the `shared-placeholder` is the name of the extend directive, not the selector – sme Mar 09 '18 at 10:41
  • `@extend`ing those `%placeholders` should definitely work. the problem might be with your CSS selectors - those pseudo-elements aren't standard yet. – jayly Mar 09 '18 at 11:00

2 Answers2

4

You need to understand what @extend does first. Extending groups all the rules. If you want to keep your code DRYed, which is fine, maybe you could do some @mixin to @include desired attributes.

@mixin shared-placeholder($isFocus) {
  @if ($isFocus) {
    color: rgb(187, 187, 187);
  }@else{
    color: rgb(126, 126, 126);
    transition: color .25s linear;
  }
}


$vendors: (':-webkit','-moz',':-moz','-ms');

@each $vendor in $vendors{
  input:#{$vendor}-input-placeholder{
    @include shared-placeholder(false);
  }
  input:focus:#{$vendor}-input-placeholder{
    @include shared-placeholder(true);
  }
}
llobet
  • 2,672
  • 23
  • 36
  • Good explanation, and the article makes it more clear what is going on. Using mixins seems to be the only way to keep it DRYed. I'm out of votes today so I'll give you a +1 tomorrow haha. – sme Mar 09 '18 at 11:37
2

I found out the issue. After compiling, I took a peek at my main.css file, and saw the following code:

.root *::-webkit-input-placeholder, 
.root *:-moz-placeholder, 
.root *::-moz-placeholder, 
.root *:-ms-input-placeholder, 
.root *::-ms-input-placeholder, 
.root *::placeholder {
    color: #7e7e7e;
    transition: color 0.25s linear; 
}

The issue is that with these pseudo selectors, they cannot be grouped. Their ruleset must be seperate, even if the exact same for each selector. So it is an 'issue' with the SASS compiler, as a group of selectors that contain an invalid one is invalid.

In other words, as of the time of this answer, you can't use the @extend directive with these particular selectors.

sme
  • 4,023
  • 3
  • 28
  • 42