control nested mixin behavior based on parent mixin - css

Here are two mixins
#mixin parent {
.parent & {
#content;
}
}
#mixin child($child) {
.#{$child} & {
#content;
}
}
Both mixin works fine independently.
Things which am looking for:
child can be independent
Also child mixin can be included in parent but opposite
should not be allowed.
In case someone tries to include parent into child there should
be some error message.
In css output .parent should come before .child(see example below for this point)
Point 4 example:
.test {
//some css properties
#include parent {
#include child(childboy) {
color: red;
}
}
}
as you can see this will give following output
.childboy .parent .test {
color: red;
}
As you can see .parent class is coming after .childboy.
How can we make it .parent class to come before .childboy
.parent .childboy .test {
color: red;
}
Is it possible to do with scss??
Please answer only in scss.
Thank you.

I don't think you can do it that way.
Check out this CSS-tricks post:
The & doesn't allow you to selectively traverse up your nested
selector tree to a certain place and only use a small portion of the
compiled parent selector that you want to use.
If I understand correctly, the reason why you're trying to do this with SCSS is because you want to group the .parent .childboy .test selector within .test root selector.
Here's a different way to do this with SASS:
.test {
#at-root .parent .childboy & {
color: red;
}
}
Codepen demo
Note: the trailing & appends the selectors from root downwards - here, just the .test class
From the SASS docs:
The #at-root directive causes one or more rules to be emitted at the
root of the document, rather than being nested beneath their parent
selectors.

Related

Correct usage of &. in SCSS

What is the correct usage of &. in SCSS
In an SCSS file, what is the difference when you are using &. instead of .
.text-field {
.loading {
-----
}
&.error {
------
}
}
& will join whatever follows it to the parent class.
In your example, it means &.error will evaluate to .text-field.error - styles that will be applied to any elements with both the text-field and error classes.
the .loading class however will evaluate to .text-field .loading - so elements with the loading class that have a parent element with the text-field class.
you can use & without the . as well, for example:
.text-field {
&--loading {
// styles
}
}
will evaluate to a single text-field--loading class.
If you use
&.error
The css is compiled as:
.text-field.error
While if you do not use & (as in your loading example) the compiled result is:
.text-field .loading
Which means the in the first example you are expecting the error class on the same 'parent' dom element, while in the latter you expect a child inside which is supposed to have the class loading.
So, there is no correct usage, it is a matter of what you want to achieve.
The above answers are good, but limited.
The use can be of other means.
Consider using the ampersand also to qualify context like so:
.child {
.parent &{
}
}
// gives .parent .child
This can also be used multiple times, while not rarely helpful and readable, this is still valid:
.child {
& &{
}
}
// gives .child .child
But can become nice with lists:
.a,.b{
& + &{
}
}
// gives .a + .a, .a + .b, .b + .a, .b + .b

Increase specificity weight with double selector via Sass

As mentioned here on Stack Overflow in another question and MDN tells about the specificity of selectors, I want to slightly increase the weight of my selector via Sass to override some existing styles. Here's an example of the (compiled) CSS.
.parent .parent__child.parent__child { color: red; }
It is more specific than just using .parent .parent__child as a selector.
I have a way to do this via Sass, but I think there should be a better way to do this:
.parent {
&__child.parent__child { color: red; }
}
Ideally, this would be the best possible setup (the ampersands have to be directly attached to each other since it's not a child selector):
.parent {
&__child&__child { color: red; }
}
This throws an error and adds a dot between the 'child' selectors. The Sass documentation doesn't say anything about this particular case. Any ideas on how to achieve this?
edit
I know about the interpolation brackets method, but what if the selector is more profound than three or four layers deep? I only want its parent selector to be duplicated, not the whole selector tree.
There's a special trick in SASS for doubling specificity using interpolation brackets (more on that here and here) since two &'s next to each other is invalid SASS syntax.
.parent {
&__child {
&#{&} {
color: red;
}
}
}
// compiles to
// .parent__child.parent__child { color: red; }
// You can also do this with deeper nested elements by
// prefacing the interpolation with the ancestor selectors:
.parent {
&__child {
.some .ancestor .elements &#{&} {
color: red;
}
}
}
// compiles to
// .some .ancestor .elements .parent__child.parent__child { color: red; }
For those of you who stumble upon this and use LESS, double &&'s are allowed:
.parent {
&__child {
&& {
color: red;
}
}
}

Less cascading & refactoring

I am trying to refactor some css looking like this:
path.myClass {
//some CSS
}
.someOtherClass.myClass {
//some other CSS
}
I am struggling to find the right syntax for the first part. I am trying to have something looking like this:
.myClass {
path.& {
// some CSS
}
.someOtherClass {
// some other CSS
}
}
How can I refactor this correctly?
You can do it like below. Since the top level selector already has . there is no need to add it again before the parent selector (&) in the inner selector. The second one is fairly straightforward as you can append the parent selector either at the start or at the end. The order of classes doesn't matter.
(Note: There should be no space before the parent selector as it would change the meaning.)
.myClass {
path&{
color: red;
}
.someOtherClass& { /* can do &.someOtherClass also, order doesn't matter */
color: blue;
}
}
Below is the compiled CSS output:
path.myClass {
color: red;
}
.someOtherClass.myClass {
color: blue;
}

Sass back nesting issue

I'm trying to figure out how to back nest specifically to the parent of the css nest I'm in. Meaning, my current set up is a parent class to a span to a before pseudo. I need to change a style on the pseudo based on a modifier on the parent. If I do this:
.parent {
span {
&:before {
// styles
.modifier & {
// Other styles
}
}
}
}
The output is .modifier .parent span:before What I need is .parent.modifier span:before
Isn't there a way to do this without adding the modifier to the parent and pathing to the pseudo again? This is what I want to avoid.
.parent {
span {
&:before {
// styles
}
}
&.modifier {
span {
&:before {
// Other Styles
}
}
}
}
This is certainly possible, it does require the use of some of the less known sass functions #at-root, & ampersand and string interpolation #{}.
Basically it works in the following manner;
Use #at-root to jump outside of the class, to the 'root'.
We place our class after that, I've used .--modifer-is-red.
We attach the classes that we jumped outside of by using interpolation of the &, #{&}.
Live Example
Example used for clarity
.parent {
span {
&:before {
// styles
color: black;
// Modifiers attached to the parent
#at-root .--modifier-is-red#{&} {
color: red;
}
}
}
}
// output
// .--modifier-is-red.parent span:before {
// color: red;
// }
Exact example to reflect your code
.parent {
span {
&:before {
// styles
#at-root .modifier#{&} {
// Other styles
}
}
}
}
There is some limitations to this, also it does look slightly odd that the modifier is placed before the parent in the output, but the browser doesn't mind.
I hope this solves your problem.
Isn't there a way to do this without adding the modifier to the parent and pathing to the pseudo again?
No, because you only have the & variable to work with, which is always a single unit consisting of the entire complex selector. You can't specify where exactly in the middle of the complex selector you want your modifier to go. The best you can do is attach it as a compound selector or use it with a combinator.

How to reference multiple sub-classes on the same element with SASS

I'm using the SMACSS method of writing my SCSS code, and I have a subclass that I want to reference if it also has another subclass.
HTML
<div class="parent-class parent-class-subclass1 parent-class-subclass2">
SCSS
.parent-class {
&-subclass1.&-subclass2 {
//Styles here
}
}
Any idea how I can do this?
So, when parent element also has subclass1 && subclass2, apply styles?
#katniss.everbean Yes, but the way you wrote it makes you have to duplicate the code.
After searching around for a while I stumbled upon this solution that works perfectly by writing any & references after the first one like #{&}:
SASS
.parent-class {
&#{&}-subclass1#{&}-subclass2{
border: 1px solid red;
}
}
Compiles into (CSS)
.parent-class.parent-class-subclass1.parent-class-subclass2 {
border: 1px solid red;
}
I found it on the SASS GitHub page.
...and I have a subclass that I want to reference if it also has another
subclass.
So, when parent element also has subclass1 && subclass2, apply styles?
You only need one & to join the nested selector to the parent class as a sibling. Then write the two subclasses as a regular sibling selector (next to each other without a space in between to indicate they're both required sibling classes).
The SCSS would look like this:
.parent-class {
//some styles
&.parent-class-subclass1.parent-class-subclass2 {
//subclass styles
}
}
That's equivelant to the following CSS
.parent-class {
//some styles
}
.parent-class.parent-class-subclass1.parent-class-subclass2 {
//some other styles
}
To keep your modular naming structure and not have to write out the whole subclass name, you could try using wildcard selectors. I'm not sure it actually ends up looking any better than just writing out the whole class name though.
Here's a codepen that demonstrates:
http://codepen.io/anon/pen/vXKZYA
And the basic code in that pen for posterity:
<div class="parent-class parent-class-subclass1 parent-class-subclass2">
some text that has all the goods
</div>
.parent-class {
color: #0000ff;
&[class*="-subclass1"][class*="-subclass2"] {
font-size: 20px;
font-family: sans-serif;
}
}
you should do it like this
<div class="parent-class subclass1 subclass2">
.parent-class {
&.subclass1.subclass2 {
//Styles here
}
}
or you can even do it like this
.parent-class {
&.subclass1 {
//subclass1 Styles here
&.subclass2 {
//subclass1 & 2 Styles here
}
}
}

Resources