This question applies to both SASS and LESS.
I have a bunch of classes that are generated with mixins.
Inside my SASS or LESS code I want to extend those classes.
In LESS it doesn't work complaining that no such class exists (the classes show up in CSS, but obviously they are not in LESS code).
I found this feature request so I guess LESS doesn't support it.
How about SASS?
Example (LESS but I'll switch to SASS if it can do that):
.errorLevels(#x){
.level-#{x} {
font-size: unit(8 + #x,px);
}
}
.errorLevels(1);
.errorLevels(2);
.errorLevels(3);
.seriousError {
&:extend(.level-1);
}
I expect:
.level-1 {
font-size: 9px;
}
.level-2 {
font-size: 10px;
}
.level-3 {
font-size: 11px;
}
//this part is missing from output
.seriousError {
font-size: 1px;
}
You could do the following to extend a class that was generated in a mixin:
#mixin classGenerator {
.error {
color: red;
font-size: 9px;
}
}
#include classGenerator;
.seriousError {
#extend .error;
font-size: 20px;
}
EDIT
According to the changes in your question:
#mixin errorLevels($x){
.level-#{$x} {
font-size: #{12 + $x}px
}
}
#include errorLevels(1);
.seriousError {
#extend .level-1;
}
Related
How do I extend a Less class which is dynamically formed using & combinator?
Less which generates expected output:
.hello-world {
color: red;
}
.foo {
&:extend(.hello-world);
font-size: 20px;
}
Expected CSS output:
.hello-world,
.foo {
color: red;
}
.foo {
font-size: 20px;
}
Less does not generate expected output:
.hello {
&-world {
color: red;
}
}
.foo {
&:extend(.hello-world);
font-size: 20px;
}
Unexpected CSS output:
.hello-world {
color: red;
}
.foo {
font-size: 20px;
}
Extending a dynamically formed selector (loosely using the term) like that is currently not possible in Less. There is an open feature request to support this. Till it is implemented, here are two work-around solutions to it.
Option 1:
Write the contents of .hello and .hello-world selectors into a separate Less file (say test.less), compile it to get the CSS. Create another file for the rules of .foo, import the compiled CSS as a Less file (using the (less) directive) and then extend the .hello-world as you had originally intended to.
test.less:
.hello {
&-world {
color: red;
}
}
extended-rule.less:
#import (less) "test.css";
.foo {
&:extend(.hello-world);
font-size: 20px;
}
Compiled CSS:
.hello-world,
.foo {
color: red;
}
.foo {
font-size: 20px;
}
This method would work because by the time the test.css file is imported, the selector is already formed and is no longer dynamic. The drawback is that it needs one extra file and creates dependency.
Option 2:
Write a dummy selector with rules for all properties that need to be applied to both .hello-world and .foo and extend it like:
.dummy{
color: red;
}
.hello {
&-world:extend(.dummy) {};
}
.foo:extend(.dummy){
font-size: 20px;
}
This creates one extra selector (dummy) but is not a big difference.
Note: Adding my comment as an answer so as to not leave the question unanswered and also because the work-around specified in the thread linked in comments doesn't work for me as-is.
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."
I am trying to customize scss of foundation to have a two different classes for topbar. I have limited knowledge of scss therefore changing _settings.scss was very easy first step, which has the problem that it changes global style. I would like to do something like following without messing up global styles.
.my-topbar-first {
$topbar-bg-color: $red;
#extend .top-bar;
}
.my-topbar-second {
$topbar-bg-color: $green;
#extend .top-bar;
}
Whats the elegant way to achieve this?
when you are using $topbar-bg-color: $red; it set the $topbar-bg-color variable to what you have in $red variable.when you are using it again, it messed up the last setting.
so instead,
you have to do like this :
.my-topbar-first {
background-color: $red;
#extend .top-bar;
}
.my-topbar-second {
background-color: $green;
#extend .top-bar;
}
First of all you are duplicating code when extending .top-bar in both class names . A more DRY approach would be like this :
.my-topbar-first,
.my-topbar-second {
#extend .top-bar;
}
.my-topbar-first {
background-color: $red;
}
.my-topbar-second {
background-color: $green;
}
When using #extend or #include they should always be on the first line were you declare your properties , example:
my-topbar-second {
#extend .top-bar;
background-color: $green;
color: $white;
font-size: $top-bar-fontsize;
}
If you have more instances of .top-bar-foo you can actually write a for loop, example :
$class-slug: top-bar;
#for $i from 1 through 2 {
.#{$class-slug}-#{$i} {
background-color: $color-#{$i};
}
}
You get :
.top-bar-1 {
background-color: $color-1;
}
.top-bar-2 {
background-color: $color-2;
}
Hope this helped . If you want to learn more about Scss go on Hugo Giraudel's blog http://hugogiraudel.com/ and learn from the best .
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."
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."