What I want is concatenate two child inside the parent but without choosing the parent on output.
What I mean is here:
.parent {
.child {
color: green;
& + & {
margin-top: 6px;
}
}
}
On the output I have this:
.canvas-btn .canvas-btn__icon + .canvas-btn .canvas-btn__icon {margin-top: 6px;}
but if it's possible to make the next way without duplicating the code is Sass?
.canvas-btn .canvas-btn__icon + .canvas-btn__icon {margin-top: 6px;}
You need to use the parent selector (&) as a variable here and treat it like the list of lists that it is:
#function nest-adjacent-selector($sel) {
$new-sel: ();
#each $s in $sel {
$last: nth($s, -1);
$new-sel: append($new-sel, $s #{'+'} $last, comma);
}
#return $new-sel;
}
.parent {
.brother, .sister {
color: green;
#at-root #{nest-adjacent-selector(&)} {
margin-top: 6px;
}
}
}
Output:
.parent .brother, .parent .sister {
color: green;
}
.parent .brother + .brother, .parent .sister + .sister {
margin-top: 6px;
}
Note that this will not work if you're using certain versions of LibSass. For more information on how this works, see this question.
Related
This is the usual list where one of the items is .open
for this I want to check if the parent (in this case is .item but its not relevant i think) has a specific class.
I've tried > but it doesnt seem to work.
Essentially how to put this:
&.open .info {
display: none;
}
&.open .inner-info {
display: flex;
}
inside of the their specific classes:
.info {
display: flex;
/* some other stuff */
}
.inner-info {
display: none;
/* some other stuff */
}
all of this is inside an .item{} block
So how do i have it so that i only have two blocks inside the .item{}?
It seems overkill to me, but you can use a hacky way to do that using a mixin and various functions. Please note that this will work for your specific example but probably not for something else.
I used the helper functions str-to-list and nth-delete, which are not native to SASS.
#mixin parentWithClass($class) {
$parent: nth-delete(str-to-list(#{&}), -1);
#at-root #{selector.replace(&, $parent, #{$parent}#{$class})} {
#content;
}
}
.item {
.inner {
color: blue;
#include parentWithClass(".open") {
color: orange;
}
}
.inner-info {
color: red;
#include parentWithClass(".open") {
color: grey;
}
}
}
You can also nest -info in inner.
I have the following HTML <div class="parent green"></div>
The green class may or may not be added. It is dynamic. It may also be another name.
In SASS how do I give properties to a .child element of parent when class green is chained to it?
I tried:
.parent {
.child {
.green & {
color: green;
}
}
}
It doesn't work.
I also tried the following which works but I am looking for something similar to the sass above. The code will become repeatable below because I have to add child each time for every dynamic class.
.parent {
&.green {
.child {
color: green;
}
}
}
I'm trying to get a structure like this if possible with sass:
.parent {
.child {
.green & { /* when .parent.green */
color: green;
}
.blue & { /* when .parent.blue */
color: blue;
}
.text-align-right & { /* when .parent.text-align-right */
text-align: right;
}
etc...
}
}
& is treated as parent selector reference in Sass, because of this your code doesn't work since it refers wrong selector.
Use of & directly will not help here, but your goal can be achieved by using mixins, for example:
#mixin child($class) {
&.#{$class} {
.child {
#content;
}
}
}
.parent {
#include child(green) {
color: green;
}
#include child(blue) {
color: blue;
}
#include child(text-align-right) {
text-align: right;
}
}
This piece of code produces result that you want to get, you can check in by yourself on sassmeister.
In Sass/SCSS, is there any way to wrap an existing rule like this:
.foo {
color: red;
}
to produce output like this:
.foo,
.bar .foo {
color: red;
}
?
I know you can use the parent selector to accomplish this:
.foo {
&,
.bar & {
color: red;
}
}
but that requires modifying the existing rule. Ideally there'd be something magical like this that you could do at the root:
#noop,
.bar {
.foo {
color: red;
}
}
(I've tried #at-root but that doesn't work in list selectors, and just an ampersand & doesn't work at the root)
If you want to wrap a class without modifying it, you need to create a mixin which extends from that class.
The mixin I created here allows to pass a list as a parameter in order to put multiple selectors.
#mixin wrap($content){
#if (type-of($content) == string){
& #{$content} {
#extend #{$content};
}
}#else if (type-of($content) == list){
#each $class in $content{
& #{$class} {
#extend #{$class};
}
}
}
}
.red {
color: red;
}
.blue {
color: blue;
}
.wrap-1{
#include wrap('.red' '.blue');
}
.wrap-2{
#include wrap('.red');
}
Outputs:
.red, .wrap-2 .red, .wrap-1 .red {
color: red;
}
.blue, .wrap-1 .blue {
color: blue;
}
This question already has an answer here:
SASS Replicating nested selector
(1 answer)
Closed 7 years ago.
Ive tried searching for an answer, but I feel like I'm asking the wrong questions.
I'm trying to create a "base parent" class that I can use to split up my rules nicely and across multiple files. The structure of the parent would be something like this:
.parent {
.child {
//some rules here
}
I then want to be able to import that parent and child class to help define further elements (using faux-syntax here)
#[custom class name]:
.parent {
//some rules
.child {
color: #000
}
Then, using my custom class name, I can specify this as the parent of another selector, like:
#[custom class name] {
.grand-child {
background-color: #fff;
}
}
This would generate out the following rule
.parent .child .grand-child {
color: #000;
background-color: #fff;
}
One way of doing this could be to create a mixin that uses the #content directive, like so:
#mixin selectors {
.parent {
.child {
#content;
}
}
}
Then, any time you want to nest something under .parent .child, you would write:
#include selectors {
.grand-child {
color: #000;
}
}
Which would result in the following CSS output:
.parent .child .grand-child {
color: #000;
}
You could always make use of the & selector.
If .grand-child is in another file, you could do something like this:
.grand-child{
.parent .child & {
color: #000;
}
}
this will compile to
.parent .child .grand-child{
color: #000;
}
Or are maybe you are also looking for the #extend possibility?
where you would add
.grand-child{
#extend .parent .child;
color: #000
}
This would get the style from .parent .child and add it to the grand-child, but only the styling, it will not change the selector above.
I have the following sass code:
.class{
label{
color:#fff;
.disabled &{color:#333; }
}
}
which outputs
.disabled .class label
Is there a way to output the parent selector without any grandparent selectors being included? Like so:
.disabled label
There's no way I know of in SASS to pick and choose from ancestor selectors when using a parent reference. With your code, though, a little reorganization can get you the same result:
label {
.class & {
color: #fff;
}
.disabled & {
color:#333;
}
}
Compiles to:
.class label {
color: #fff; }
.disabled label {
color: #333; }
Even though hopper is not enterly wrong, you can actually select grand-parent with variables.
You can achieve what you want with this:
.class{
label{
color:#fff;
$selector: nth(&,1);
$direct-parent: nth($selector, length($selector));
#at-root #{$direct-parent} {
.disabled &{color:#333; }
};
}
}
Which will generate this css:
.class label {
color: #fff;
}
.disabled label {
color: #333;
}
The parent selector is always a reference to the entire resolved selector from the previous level of nesting. There is no concept of "parent" or "grandparent", especially when concatenating selectors or using the parent selector at the end muddies the water.
Disclaimer: I do not recommend doing this unless you really really need to.
Starting with Sass 3.4, you can extract portions of a selector by using & as a variable. When used this way, you'll get a list of list of strings (which can be looped over, etc.).
Extracting a part or slice of a selector
This function here uses the same style of arguments as the string-slice function:
#function selector-slice($sel, $start: 1, $end: -1) {
$collector: ();
#each $s in $sel {
// calculate our true start and end indices when given negative numbers
$_s: if($start > 0, $start, length($s) + $start + 1);
$_e: if($end > 0, $end, length($s) + $end + 1);
$c: ();
#for $i from $_s through $_e {
$c: append($c, nth($s, $i));
}
// prevent duplicates from creeping in
#if not index($collector, $c) {
$collector: append($collector, $c);
}
}
#return $collector;
}
/* complex example */
.one-a, .one-b {
two {
three {
color: red;
&:before {
#at-root #{selector-slice(&, 2, 3)} {
color: green;
}
}
}
}
}
/* your example */
.class {
label {
color:#fff;
#at-root #{selector-slice(&, -1, -1)} {
.disabled & {
color:#333;
}
}
}
}
Output:
/* complex example */
.one-a two three, .one-b two three {
color: red;
}
two three:before {
color: green;
}
/* your example */
.class label {
color: #fff;
}
.disabled label {
color: #333;
}
As an added bonus, you can use this function to reverse the order of the selectors by passing in the larger index before the smaller one.
.one-a, .one-b {
two {
three {
color: red;
&:before {
#at-root #{selector-slice(&, 3, 2)} {
color: green;
}
}
}
}
}
Output:
.one-a two three, .one-b two three {
color: red;
}
three:before two {
color: green;
}
Related: Modifying the middle of a selector in Sass (adding/removing classes, etc.)
Replacing one class with another
Alternately, you could just use the selector-replace function from the standard library if what you're looking to do is replace one class with another.
.class {
label {
color:#fff;
#at-root #{selector-replace(&, '.class', '.disabled')} {
color:#333;
}
}
}
Output:
.class label {
color: #fff;
}
.disabled label {
color: #333;
}