What does "#extend must be used with a %placeholder" mean? - css

While linting the following SASS statements, I get #extend must be used with a %placeholder warning.
.reg-text {
color: #202226;
font-family: $font-page;
font-size: 17px;
line-height: 25px;
}
.reg-text-header {
#extend .reg-text;
font-weight: 600;
}
What does warning mean and how do I fix it. Afaik, .extend exists for the purpose of extending classes.

This is referring to an opinion that using #extend with normal CSS selectors is a bad idea.
I personally agree with this opinion, but it is an opinion nonetheless. Using #extend with any sort of selector is what the Sass spec allows, so I would possibly get in touch with the maintainers of your linter and request that the terminology in your error explains this.
If you use #extend to extend the definition of a selector, every time the selector is extended is is compiled to CSS that includes a reference of the selector for every time the #extend keyword is used.
If, however, you use #extend with placeholder selectors starting with % (A.K.A. "Silent Classes"), the functionality is much more in line with best practices. First off, any unused placeholder selectors are not even rendered to the final CSS (great for building reusable design libraries).
For example, if you have a block of reusable content within a CSS selector, consider converting it to use a placeholder selector instead:
.reg-text {
color: #202226;
font-family: $font-page;
font-size: 17px;
line-height: 25px;
}
.reg-text-header {
#extend .reg-text; // this is inefficient and causes specificity issues!
font-weight: 600;
}
// Instead, do this:
%reg-text {
color: #202226;
font-family: $font-page;
font-size: 17px;
line-height: 25px;
}
div.your-actual-selector-on-the-page .reg-text {
#extend %reg-text;
}
div.your-actual-selector-on-the-page .reg-text-header {
#extend %reg-text; // This compiles much neater and doesn't get in the way of specificity.
font-weight: 600;
}

Related

What does span {} do in CSS syntax?

I got some example CSS code (well written and working) with many span statements inside, that I modified for my use. What exactly they do? VS Code shows me as an error, but browsers don't complain, and I couldn't find any references in the CSS documentation, as if this syntax does not exist.
Example:
h2 {
letter-spacing: 2vw;
font-size: 2vw;
font-weight: bold;
text-align: center;
span {
display: block;
font-size: 8vw;
letter-spacing: -1vw;
}
}
VS code complains:
"code": "css-colonexpected",
"severity": 8,
"message": "colon expected",
"source": "css",
If I add colon it would be suggesting keys right away, and would not accept anything in curly brackets{}
Thanks
the brackets { and } define scope so that
body {
color: #000;
}
Would define that the color (text color) of the body element type (css query selector) would be #000 (which is hex for black)
however, if you have an element in an element like this using a precompiler such as less for css using the less syntax.
body {
color: #000;
span {
color: #FF0000;
}
}
this would do as the previous css did, but in less you can create a hierarchy
the body's color will be set to black as before.
and then any span child of the body element will have its color set to red (#FF0000)
CSS/LESS are used in conjunction with the HTML DOM object model.
You're correct that this syntax doesn't exist for CSS, as it doesn't support nested selectors like this.
The correct syntax would be:
h2 {
letter-spacing: 2vw;
font-size: 2vw;
font-weight: bold;
text-align: center;
}
h2 span {
display: block;
font-size: 8vw;
letter-spacing: -1vw;
}
This syntax is of course perfectly acceptable if you use a CSS preprocessor, like SASS or LESS for example. CSS preprocessors compile CSS written like you've done into standard CSS syntax, and add extra functionality, like using variables and conditional statements.
I think that modern browsers are probably capable of understanding syntax like this in certain situations, but if you want to use to this sort of syntax then using a preprocessor is a safer option to avoid errors.

Sass/SCSS: Overwrite and only render the overwritten props [duplicate]

Ok so I have a placeholder with a nested selector:
%block {
.title {
font-size:12px;
}
}
I want to extend it and ADD to the .title class:
.superblock {
#extend %block;
.title {
font-weight:bold;
}
}
The answer I WANT is this:
.superblock .title {
font-size: 12px;
font-weight: bold; }
However, the answer I get is this:
.superblock .title {
font-size: 12px; }
.superblock .title {
font-weight: bold; }
Am I doing something wrong or is this just how it works? To clarify I want to merge it. If I add something directly inside the .superblock and add like another .superblock2 which also extends %block they merge without any problems.
Sass has no functionality for "merging" duplicate selectors. You'll need to find another utility to do this after the CSS has been compiled.
The #extend directive isn't just a way to use classes in place of mixins (similar to LESS style mixin calls). Why #extend works the way it does becomes clear when you're extending normal classes instead of extend classes:
.block {
font-size:12px;
}
.foo {
#extend .block;
font-weight: bold;
}
Output:
.block, .foo {
font-size: 12px;
}
.foo {
font-weight: bold;
}
Using an extend class just suppresses the emission of the original class name.
Now that you've seen why #extend works the way it does, do you still want what #extend offers? If the answer is no, then you need to use a mixin:
#mixin block {
// styles
.title {
font-size: 12px;
#content;
}
}
.superblock {
#include block {
font-weight: bold;
}
}
Output:
.superblock .title {
font-size: 12px;
font-weight: bold;
}
This is pretty much it. SASS produces extended declarations separately.
And it has no functionality of grouping declarations by selector, it's not that smart.
But you need not worry that much about CSS cleanness. Modern web servers serve CSS gzipped, all duplication will be nicely compressed.
LESS can do that. However you would write:
.superblock {
.title {
.block .title;
}
}
Not sure if it works with #extend too.
You can use a tools, I used it to clean the css
https://github.com/addyosmani/grunt-uncss
"A grunt task for removing unused CSS from your projects with UnCSS."

Using FontAwesome wrapped in own css rule [duplicate]

I am using Font Awesome 4.0.0, and want to do something like this in LESS:
.btn-github {
.btn;
.btn-primary;
margin-left: 3em;
i {
.#{fa-css-prefix};
.#{fa-css-prefix}-github;
.#{fa-css-prefix}-lg;
margin-right: 1em;
}
}
That doesn't compile with the error:
ParseError: Unrecognised input in - on line ...
Is it possible to accomplish this? It would certainly make a beautiful button for me.
There are at least 2 problems with what you are trying to do (for LESS >=1.6 see update bellow):
1) Unfortunately it is not possible to call a mixin using selector
interpolation.
With selector interpolation LESS expects the construct to be of
following format:
.#{selector-string} { property:value; }
(the interpolated selector can have also some static string pre or
post the interpolation)
so
.#{selector-string};
is Unrecognised by the LESS compiler. See more here:
How can I call a mixin by reference in LESS?
2) A ruleset with an interpolated selector gets directly printed to the CSS output and does not exist as a mixin that you could reuse in the LESS run
For example:
#foo: test;
.#{foo} {
length: 20px;
}
.bar {
.test;
}
will return:
Name error: .test is undefined
.bar { .test;}
See more on that here: LESS CSS: Reuse generated .#{name} class as a mixin
Possible solution for your problem would be redifinig the font awesome rules as some kind of reusable mixins (without using interpolation). Something like this:
#fa-var-github: "\f09b";
.fa-mixin() {
display: inline-block;
font-family: FontAwesome;
font-style: normal;
font-weight: normal;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.fa-mixin-lg() {
font-size: (4em / 3);
line-height: (3em / 4);
vertical-align: -15%;
}
.fa-mixin-icon(#icon){
#var: "fa-var-#{icon}";
&:before { content: ##var; }
}
i {
.fa-mixin;
.fa-mixin-lg;
.fa-mixin-icon(github);
}
If you don't really need the variables and just want to include the rules, the best way would be just to import the compiled CSS version of the FontAwesome (see answer here):
#import (less) 'font-awesome.css';
and then you can just use the CSS rules like LESS mixins or extend their selectors as you see fit and it should work perfectly.
Update:
As of LESS >= 1.6 rules with interpolated selectors can be accessed as mixins ... so the #2 limitation form above does not apply anymore (but you still can not call a mixin dynamically with interpolation). So you can simply call LESS mixins and variables from the imported font-awesome.less file like so:
i {
.fa;
.fa-lg;
&:before{
content: #fa-var-github;
}
}

LESS mixin a variable class name

I am using Font Awesome 4.0.0, and want to do something like this in LESS:
.btn-github {
.btn;
.btn-primary;
margin-left: 3em;
i {
.#{fa-css-prefix};
.#{fa-css-prefix}-github;
.#{fa-css-prefix}-lg;
margin-right: 1em;
}
}
That doesn't compile with the error:
ParseError: Unrecognised input in - on line ...
Is it possible to accomplish this? It would certainly make a beautiful button for me.
There are at least 2 problems with what you are trying to do (for LESS >=1.6 see update bellow):
1) Unfortunately it is not possible to call a mixin using selector
interpolation.
With selector interpolation LESS expects the construct to be of
following format:
.#{selector-string} { property:value; }
(the interpolated selector can have also some static string pre or
post the interpolation)
so
.#{selector-string};
is Unrecognised by the LESS compiler. See more here:
How can I call a mixin by reference in LESS?
2) A ruleset with an interpolated selector gets directly printed to the CSS output and does not exist as a mixin that you could reuse in the LESS run
For example:
#foo: test;
.#{foo} {
length: 20px;
}
.bar {
.test;
}
will return:
Name error: .test is undefined
.bar { .test;}
See more on that here: LESS CSS: Reuse generated .#{name} class as a mixin
Possible solution for your problem would be redifinig the font awesome rules as some kind of reusable mixins (without using interpolation). Something like this:
#fa-var-github: "\f09b";
.fa-mixin() {
display: inline-block;
font-family: FontAwesome;
font-style: normal;
font-weight: normal;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.fa-mixin-lg() {
font-size: (4em / 3);
line-height: (3em / 4);
vertical-align: -15%;
}
.fa-mixin-icon(#icon){
#var: "fa-var-#{icon}";
&:before { content: ##var; }
}
i {
.fa-mixin;
.fa-mixin-lg;
.fa-mixin-icon(github);
}
If you don't really need the variables and just want to include the rules, the best way would be just to import the compiled CSS version of the FontAwesome (see answer here):
#import (less) 'font-awesome.css';
and then you can just use the CSS rules like LESS mixins or extend their selectors as you see fit and it should work perfectly.
Update:
As of LESS >= 1.6 rules with interpolated selectors can be accessed as mixins ... so the #2 limitation form above does not apply anymore (but you still can not call a mixin dynamically with interpolation). So you can simply call LESS mixins and variables from the imported font-awesome.less file like so:
i {
.fa;
.fa-lg;
&:before{
content: #fa-var-github;
}
}

SCSS extend a nested selector and override the nested rulesets

Ok so I have a placeholder with a nested selector:
%block {
.title {
font-size:12px;
}
}
I want to extend it and ADD to the .title class:
.superblock {
#extend %block;
.title {
font-weight:bold;
}
}
The answer I WANT is this:
.superblock .title {
font-size: 12px;
font-weight: bold; }
However, the answer I get is this:
.superblock .title {
font-size: 12px; }
.superblock .title {
font-weight: bold; }
Am I doing something wrong or is this just how it works? To clarify I want to merge it. If I add something directly inside the .superblock and add like another .superblock2 which also extends %block they merge without any problems.
Sass has no functionality for "merging" duplicate selectors. You'll need to find another utility to do this after the CSS has been compiled.
The #extend directive isn't just a way to use classes in place of mixins (similar to LESS style mixin calls). Why #extend works the way it does becomes clear when you're extending normal classes instead of extend classes:
.block {
font-size:12px;
}
.foo {
#extend .block;
font-weight: bold;
}
Output:
.block, .foo {
font-size: 12px;
}
.foo {
font-weight: bold;
}
Using an extend class just suppresses the emission of the original class name.
Now that you've seen why #extend works the way it does, do you still want what #extend offers? If the answer is no, then you need to use a mixin:
#mixin block {
// styles
.title {
font-size: 12px;
#content;
}
}
.superblock {
#include block {
font-weight: bold;
}
}
Output:
.superblock .title {
font-size: 12px;
font-weight: bold;
}
This is pretty much it. SASS produces extended declarations separately.
And it has no functionality of grouping declarations by selector, it's not that smart.
But you need not worry that much about CSS cleanness. Modern web servers serve CSS gzipped, all duplication will be nicely compressed.
LESS can do that. However you would write:
.superblock {
.title {
.block .title;
}
}
Not sure if it works with #extend too.
You can use a tools, I used it to clean the css
https://github.com/addyosmani/grunt-uncss
"A grunt task for removing unused CSS from your projects with UnCSS."

Resources