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."
Related
In one file, I have typography.css:
.p.xl {
font-size: 1.375rem;
}
.p.lg {
font-size: 1.25rem;
}
.p {
font-size: 1.125rem;
}
.p.sm {
font-size: 0.875rem;
}
And in another file, I want to apply .p.lg to my .links:
.link {
#apply p lg;
}
The following code is generated and shipped to the front end:
.link {
font-size: 1.125rem;
}
Even if I change the order of lg and p and even if I inline it in the link itself with class="p lg".
Hell, even if I specify for the p styles to explicitly NOT target the lg elements it STILL generates the incorrect CSS:
Input:
.p.xl {
font-size: 1.375rem;
}
.p.lg {
font-size: 1.25rem;
}
.p:not(.xxl):not(.xl):not(.lg):not(.sm):not(.xs):not(.xxs) {
font-size: 1.125rem;
}
.p.sm {
font-size: 0.875rem;
}
Output:
.link:not(.xxl):not(.xl):not(.lg):not(.sm):not(.xs):not(.xxs) {
font-size: 1.125rem;
}
It's just stupidly copying and pasting the rest of the paragraph selector rather than running the selector logic and determining whether or not to apply the styles.
I have this exact same problem hundreds of times in my project with seemingly no solution other than to completely abandon Tailwind for half the project or to install tailwind-plugins and then enter every single combination of every class I want to apply in my tailwind.config.js.
Help is greatly appreciated. I've searched online for a while without finding anyone even having the same problem; I only found people who don't know how #apply works (well perhaps I'm one of them...). Thanks in advance.
UPDATE:
I also have:
.p {
#apply font-light;
}
.p.subheading {
#apply font-normal;
}
And of course the same issue with applying p subheading where it applies the wrong font weight and even using .p:not(.subheading) still generates the wrong styles. Will I really have no way whatsoever of styling p font-weights without also giving every single .p ANOTHER class to tell it to use one font weight? In other words, are default styles impossible?
UPDATE 2
Even when using !important it still fails to override...
.p {
#apply font-light;
}
.p.subheading {
#apply !font-normal;
}
and
.p.xl {
font-size: 1.375rem !important;
}
.p.lg {
font-size: 1.25rem !important;
}
.p {
font-size: 1.125rem;
}
.p.sm {
font-size: 0.875rem !important;
}
I STILL get the wrong font sizes and font weights generated:
.link {
font-size: 1.125rem;
}
.link {
font-weight: 300;
}
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."
Let us say I have the following setup,
.block
.block__header
.block__content
.block__footer
Now I want to show an active state of this block. Let us say the block itself gets a green background and element 2 and 3 should get bold text. As I understand the philosophy of BEM, one should not use child selectors in order to keep the specificity as low as possible.
So is this really the way to do it?
.block.block--active
.block__header
.block__content.block__content--active
.block__footer.block__footer--active
Update: and how would I write that solution in SASS (very new to it)? This my setup so far... if I can use nested selectors, what is best practice here?
.block {
&--active {
}
&__header {
}
&__content {
// active modifier of content
&--active {
font-weight: bold;
}
// would be the same as
.block--active & {
font-weight: bold;
}
// but can i reference the active block somehow else in sass?
// & is a parent selector but i would need the parent of the parent here...
}
&__footer {
&--active {
}
}
}
The philosophy of BEM is about to keep blocks context free. The low specificity is just a good practice, not a golden rule. I give three valid solutions below.
If you're sure the block cannot be recursively included in itself, a simple cascade can be used:
.block--active {
background-color: green;
}
.block--active .block__element-2,
.block--active .block__element-3 {
font-weight: bold;
}
If the elements are directly located in the block, the children selector is valid:
.block--active {
background-color: green;
}
.block--active > .block__element-2,
.block--active > .block__element-3 {
font-weight: bold;
}
Or the flat solution (but not DRY):
.block--active {
background-color: green;
}
.block__element-2--active,
.block__element-3--active {
font-weight: bold;
}
With SCSS, there are several ways to write the first solution. Here is the one I use:
.block {
&--active {
background-color: green;
}
&--active &__element-2,
&--active &__element-3 {
font-weight: bold;
}
}
See another solution here.
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."
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;
}