Does sass support to use parent selector as follows? - css

Problem
I mainly use the following methods. (SASS)
.person {
&.man {
.head { A }
}
&.woman {
.head { B }
}
.head { C }
}
But I want to use the following method. (SASS)
.person {
.head {
C
<parent_selector.man> {
A
}
<parent_selector.woman> {
B
}
}
}
compiled result (CSS)
.person .head { C }
.person.man .head { A }
.person.woman .head { B }
I want to know if there is such a function. Thank you.
My result
I got the idea from #falsarella's #at-root approach. It seems a bit crude, but this is also possible. (I actually used deeper selectors than the example, so it was hard to solve with at-root and #{$} alone.)
.person {
$person: &;
.head {
C
#at-root #{$person}.man .head {
A
}
#at-root #{$person}.woman .head {
B
}
}
}
Or it would be more convenient and readable(If the parent selector is not a simple selector.) to use it by naming $parent and overriding the previous $parent.
When I think about it once, the current selector is named $parent, so it is confusing. It might be better to ignore '>', ':after', ... of a parent selector and just name it as $person. (or create naming conventions.)
.earth {
$parent: &;
.person {
$parent: &;
.head {
C
#at-root #{$parent}.man .head {
A
}
#at-root #{$parent}.woman .head {
B
}
}
}
}
As a result of further Googling, postcss seems to support parent selectors I want.

There's no "parent" selector in Sass, but, in your case, you can use a tricky #{&} interpolation together with #at-root, like this:
.person {
.head {
color: white;
#at-root .man#{&} {
color: blue;
}
#at-root .woman#{&} {
color: pink;
}
}
}
Resulting in the following CSS:
.person .head {
color: white;
}
.man.person .head {
color: blue;
}
.woman.person .head {
color: pink;
}

Unfortunately, not. I think the first example that you give is the best way to achieve this. Another option might be:
.head {
.person & {
color: red;
}
.person.man & {
color: blue;
}
.person.woman & {
color: green;
}
}
It will produce the same compiled result as you desire. But beware of nesting the .head class. It will trip you up.

The following does not really uses a parent selector. Just uses a SASS #mixin to give same CSS output.
#mixin personHead($gender) {
#if $gender == man {
&.man .head{
property: A;
}
}
#if $gender == woman {
&.woman .head{
property: B;
}
}
#if $gender == "" {
.head{
property: C;
}
}
}
.person { #include personHead(man); }
.person { #include personHead(woman); }
.person { #include personHead(""); }
/* Compiled CSS Output */
.person.man .head {
property: A;
}
.person.woman .head {
property: B;
}
.person .head {
property: C;
}

Related

SASS mixin that applies some rules when we call it

I would like to create a SASS/LESS mixin that asks if a variable is equal to some value then apply some CSS rules.
#mixin myTest($myVar: $num) {
#if ($myVar == $num) {
/* Apply rules if $myVar is set $num - I DO NOT KNOW WHAT SHOULD BE THERE */
} #else {
/* Do nothing */
}
}
And then I would like to use my mixin this way:
$num: 1;
#include myTest(1) {
h1 {
color: blue;
background: red;
}
}
#include myTest(2) {
h1 {
color: yellow;
background: green;
}
}
So that only the rules inside parentheses of #include myTest(1) { ... } are applied.
The problem is I dont know how to do that.
myTest checks the value of $myVar variable and applies passed css rules via #content - see documentation.
#mixin myTest($myVar: $num) {
#if ($myVar= $num) {
#content;
}
}
$num: 1;
#include myTest(1) {
h1 {
color: blue;
background: red;
}
}
#include myTest(2) {
h1 {
color: yellow;
background: green;
}
}
You neeed to use #content inyour mixin to get every thing that was in your mixin to be pushed through
$num: 1;
#mixin myTest($myVar: $num) {
#if ($myVar == $num) {
/* Apply rules if $myVar is set $num - I DO NOT KNOW WHAT SHOULD BE THERE */
#content; // this is how you get it in here
} #else {
/* Do nothing */
}
}
#include myTest(1) {
h1 {
background:red;
}
}
#include myTest(2) {
h1 {
background:blue;
}
}
https://codepen.io/anon/pen/YEJKRm
hopes this helps
I'm not quite sure I've understood your question fully, but it seems like what you need to do is move your CSS rules inside your mixin:
#mixin myTest($num) {
#if $num === 1 {
color: blue;
background: red;
} #else {
color: yellow;
background: green;
}
}
$num: 1;
h1 {
#include myTest($num);
}

how to extends only specific rules in parent class to child class, rather than all of them in sass?

I have a parent class called .parent-form and I want to extend some of its rules in the child class, not all of them. Is that possible in SASS?
.parent-form {
padding: 20px 10px;
.form-control:focus {
border-color: #2BBBAD;
}
.row {
/*some css rules goes here*/
}
}
.child-form {
#extend .parent-form;
/* I only need padding and .form-control, but not .row */
}
Is there any way to do that kind of thing in sass?
You cannot selectively extend rules in a class while not taking the others. However you could do something like this:
.parent-form {
padding: 20px 10px;
.form-control:focus {
border-color: #2BBBAD;
}
}
.child-form {
#extend .parent-form;
}
.needs-row {
#extend .parent-form;
.row {
}
}
.child-form-with-row {
#extend .needs-row;
}
Alternatively, you could do this with a mixin:
#mixin need-row($needRow) {
#extend .parent-form;
#if $needRow == true {
.row {
}
}
}
.child-form-with-row {
#include need-row(true);
}

How to extend in scss from parent (in case of BEVM)

I try to understand BEVM+SCSS philosophy.
I don't know how to extend V from BE in this case.
What I want to achieve:
.block {
&__element {
background-color: black;
&--variation-a {
#extend &__element; //won't work
color: red;
}
&--variation-b {
#extend &__element; //won't work
color: green;
}
}
}
What I want to avoid:
.block {
&__element {
background-color: black;
&--variation-a {
#extend .block__element; //work but ugly
color: red;
}
&--variation-b {
#extend .block__element; //work but ugly
color: green;
}
}
}
The only way I've found it's to have a kind of %element { ... } aside and extends from it, but it's not exactly what I want.
You can use variables. $b to store block name and $e to store element name.
Sassmeister demo.
.block {
$b: &;
&__element {
$e: #{$b}__element;
background-color: black;
&--variation-a {
#extend #{$e};
color: red;
}
&--variation-b {
#extend #{$e};
color: green;
}
}
}
But it's bad practice to nest element styles by modifier. Modifier must only override styles.

Sass referencing parent selectors using the ampersand character within nested selectors

Just when I thought Sass was the coolest thing since sliced bread, it had to go and let me down. I'm trying to use the ampersand to select a parent of a nested item. It's a complex selection and its returning some unexpected results...
My sass:
.page--about-us {
a {
text-decoration:none;
}
.fa-stack {
.fa {
color:pink;
}
a & {
&:hover {
.fa-circle-thin {
color:red;
}
.fa-twitter {
color:blue;
}
}
}
}
}
Outputted CSS:
.page--about-us a {
text-decoration: none;
}
.page--about-us .fa-stack .fa {
color: pink;
}
a .page--about-us .fa-stack:hover .fa-circle-thin {
color: red;
}
a .page--about-us .fa-stack:hover .fa-twitter {
color: blue;
}
Expected Output (Note the placement of the a tag):
.page--about-us a {
text-decoration: none;
}
.page--about-us .fa-stack .fa {
color: pink;
}
.page--about-us a .fa-stack:hover .fa-circle-thin {
color: red;
}
.page--about-us a .fa-stack:hover .fa-twitter {
color: blue;
}
Demo:
http://sassmeister.com/gist/8ed68bbe811bc9526f15
You can store the parent selector in a variable!
Take the following BEM-like SASS:
.content-block {
&__heading {
font-size: 2em;
}
&__body {
font-size: 1em;
}
&--featured {
&__heading {
font-size: 4em;
font-weight: bold;
}
}
}
The selector inside of .content-block--featured is going to be .content-block--featured .content-block--featured__heading which might not be what you're after.
It's not as elegant as the single ampersand but you can stash the parent selector into a variable! So to get what you might be after from the above example without hard-coding the parent selector:
.content-block {
$p: &; // store parent selector for nested use
&__heading {
font-size: 2em;
}
&__body {
font-size: 1em;
}
&--featured {
#{$p}__heading {
font-size: 4em;
font-weight: bold;
}
}
}
So, OP, in your case you might try something like this:
.page--about-us {
$about: &; // store about us selector
a {
text-decoration:none;
}
.fa-stack {
.fa {
color:pink;
}
#{$about} a & {
&:hover {
.fa-circle-thin {
color:red;
}
.fa-twitter {
color:blue;
}
}
}
}
}
This is the normal behavior, as described in Sass documentation (link):
& will be replaced with the parent selector as it appears in the CSS. This means that if you have a deeply nested rule, the parent selector will be fully resolved before the & is replaced.
Meaning:
.foo {
.bar {
.baz & {
color: red;
}
}
}
Will render as:
.baz .foo .bar {
color: red;
}
And not:
.baz .bar {
color: red;
}
The right way to get your expected result is this one:
.page--about-us {
a {
text-decoration:none;
.fa-stack:hover {
.fa-circle-thin {
color:red;
}
.fa-twitter {
color:blue;
}
}
}
.fa-stack {
.fa {
color:pink;
}
}
}

Sass #extend base/default without also extending pseudo-classes?

I know I can #extend .foo:hover, but is there a way to #extend the .foobar base/default properties without also extending the definitions for pseudo-classes like :hover, :active, etc?
For example, how would I change the following such that .foobar extends only .foo's default state?
.foo {
& {
color:blue;
}
&:hover {
background-color: black;
}
}
.foobar {
#extend .foo;
&:hover {
//As is, I have to override. Any better way?
background-color: transparent;
}
}
(If there is no way to do this with Sass, is there a preferred way to achieve the same effect?)
You have to rewrite your selectors in such a way that you only extend exactly the part you want:
%foo {
color:blue;
}
.foo {
#extend %foo;
&:hover {
background-color: black;
}
}
.foobar {
#extend %foo;
&:hover {
background-color: transparent;
}
}
However, depending on how you are going to be extending/reusing your .foo class, the new #content directive might be the better way to go.
#mixin foo {
color: blue;
&:hover {
#content;
}
}
.foo {
#include foo {
background-color: black;
}
}
.foobar {
#include foo {
background-color: transparent;
}
}

Resources