Declare a custom selector in scss? - sass

For example, I want to select element by attribute ng-controller (as in angularjs). I have a div with
<div ng-controller="foo1Ctrl"></div>
<div ng-controller="foo2Ctrl"></div>
<div ng-controller="foo3Ctrl"></div>
In scss, I would have to do:
[ng-controller="foo1Ctrl"] {}
[ng-controller="foo2Ctrl"] {}
[ng-controller="foo3Ctrl"] {}
To produce my scoped or nested css.
Is it possible for me to define some macro in scss?
(In C form, it would be something along this line)
#DEFINE ng(x) [ng-controller="x"]
ng(foo1Ctrl) {}
ng(foo2Ctrl) {}
ng(foo3Ctrl) {}
I just wonder if scss do have something along this line. If it doesn't have one, then I'll just use the original method.

The documentation shows pretty much everything you can do in Sass: http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#mixin-content
#mixin ng($value) {
[ng-controller="#{$value}"] {
#content;
}
}
#include ng('asdf') {
color: red;
}
Output:
[ng-controller="asdf"] {
color: red;
}

Related

Inline scss variable as the name part in the evaluation of another scss variable

Suppose I have the following scss variables:
$until-xs: "(max-width: 377px)";
$until-sm: "(max-width: 640px)";
...
$until-xl: "(max-width: 4000px)";
And based on them the following helper css classes are constructed:
.until-sm {
display: none;
#media #{$until-xs} {
display: block !important;
}
}
.until-md {
display: none !important;
#media #{$until-sm} {
display: block !important;
}
}
/* plus a lot of classes like this */
I am trying to create a mixin that would help me define those classes more easily by passing the $until-x variable as an input to the mixin, like so:
#mixin until($x) {
display: none;
#media #{'$until-'#{$x}} {
display: block !important;
}
}
Such that the classes above will be defined simply as:
.until-xs { #include until($until-xs); }
The problem is the media variable inlining part does not evaluate the way I wanted, like:
#{'$until-'#{$x}} (when x is 'xs') =>
#{'$until-xs'} =>
#{$until-xs} =>
(max-width: 377px)
Any way I can achieve this? Since this can be applied in multiple places in my project I am more interested in the possibility of inlining vars like this than the solution to the particular problem from the example.
Instead of defining lots of variables like $until-xs, $until-sm and so on, you can define a map that contains information of your medias like the code below:
#use "sass:map";
$until-var: ("xs": "(max-width: 377px)", "sm": "(max-width: 620px)", "md": "(max-width: 807px)");
#mixin until($x) {
display: none;
#media #{map.get($until-var, $x)} {
display: block !important;
}
}
/* using that in your classes */
.until-xs { #include until("xs"); }
.until-sm { #include until("sm"); }
I'm not sure what you mean by inlining vars! But if you want a single mixin that works for different medias, I think that works.

scss, same class, different elements html

I use scss,
I have a css class, I need some css property to be different, depending of the html element:
<a class="myClass">...</a><input class="myClass"/>
I've try, but it don't work:
.myClass {
&.someOtherClass{...}
&text-area{...}
&input{...}
}
Any idea?
for easy readinf, I need the element to be define INSIDE the class, I can't use something like
input{ &.myClass{...}}
text-area{ &.myClass{...}}
With the #at-root directive you can write your SCSS code in a nested fashion but the resulting CSS will not be nested.
.myClass {
#at-root input#{&} { color: red; }
}
will result in
input.myClass {
color: red;
}
But honestly I don't find this better readable than just doing it KISS:
.myClass { ... }
input.myClass { ... }

Combine raw selector with mixin into single query

I have the following SASS rules:
p {
margin: 0;
}
#include desktop() {
p {
margin: 0;
}
}
The mixin is like this:
#mixin desktop() {
#media screen and (min-width: 1200px) {
#content;
}
}
Elsewhere in the codebase there's a margin being set on desktop, hence in this case I need to explicitly remove it on the desktop breakpoint too, just having the first p selector rule doesn't cut it.
Is there a neat way to combine the selectors as it feels verbose having the same margin: 0 rule twice? I realise there's probably something more fundamentally wrong here with the inheritance, but that's outside the scope of the question. I don't want to use !important.
Many thanks.
Is there a neat way to combine the selectors? Sure there is… Just use another mixin:
#mixin para {
p {
margin: 0;
}
}
#include para;
#include desktop {
#include para;
}
You clearly already know how to use mixins, so I'm assuming your question is really about whether you can nest one mixin within another (yes), or whether you can include selectors within a mixin (yes).

Ampersand and mixins in SCSS

Searched but can't find an answer..
I have an element which gets generated (by an external platform) with the following classes: p-button and button.
Now the SCSS is like this:
.p-button {
&.button {
margin: 10px;
}
}
But I want to refactor using mixin includes (this is a big project so there is no other way of making this code better except using mixins). The mixin takes the given selector and applies a . to it. I can't change the mixin, as it is used by many other teams, so I can't pass the ampersand together with the selector. I tried this:
.p-button {
& {
#include button-appearance("button") {
margin: 10px;
}
}
}
But that doesn't work (puts a space between it). You can't do this:
.p-button {
&#include button-appearance("button") {
margin: 10px;
}
}
Anyone have a clue?
EDIT: Here is the mixin
#mixin button-appearance(
$appearance-class,
$show,
$background-color,
$background-image,
$background-position) {
$sel: $button-selector;
#if $appearance-class {
$sel: $sel + '.' + $appearance-class;
}
#{$sel} {
#include normalized-background-image($background-image);
#include show($show);
background-color: $background-color;
background-position: $background-position;
}
#content;
}
EDIT 2: Here is the $button-selector (I can not edit this in the platform, but maybe overwrite it in my own project?)
$button-class: 'p-button';
$button-selector: '.#{$button-class}';
Everyone, finally found the solution. I just removed the &.button from the .p-button mixin include and now it works:
#include button-appearance ("button") { *styles* }
#include button-appearance () { *styles* }
Edited the answer after the original question was edited adding the used and un modifiable mixin
The original mixin does not append the ‘#content’ passed to the mixin to the generated selector. So if you cannot modify the original mixin, the only way is to add your properties outside the mixin. According to the mixin the selector will match a predefined ‘$button-selector’ variable, so it won’t use your class.
So, if you want to use the same class defined in ‘$button-class’, try the following:
#{$button-selector}.button {
margin: 10px;
}
Will output:
.p-button.button {
margin: 10px;
}

What is the best SASS practice of writing child selector while parent has hover

I have a doubt of writing child selector when I have a hover event in parent.
say I have HTML like this,
<div class="root">
<div class="root__element">
<div class="root__sub-element" />
</div>
</div>
In sass,
.root {
$root: &;
&__element {
&:hover {
#{$root}__sub-element {color: red;} // question comes here, why
// not using .root_sub-
// element?
}
}
}
what I want is hover event happens in root__element, color change in root__sub-element.
Should I use ampersand to keep SASS or I would directly use '.root__sub-element'?
You should Keep SASS.
I noticed you tagged 'bem' in your question.
As per BEM, your block element class to continue with your prefix of last child class. http://getbem.com/naming/
POINT 1:
If you have another element with the same behavior. the hardcoded class .root__sub-element will break. please consider the following sass code with multiple root classes.
SASS Code :
$roots: root, newroot;
#each $r in $roots {
.#{$r}{
$root: &;
&__element {
&:hover {
#{$root}__sub-element {color: red;}
}
}
}
}
POINT 2:
This is very rare or not suggested practice, but suppose in case your root block class .root changed to .newroot. as per bem, your child classes will change with new prefix.
Here, hardcoded class .root__sub-element will break, you need to changes it to all area manually.
Otherwise:
CSS is:
.newroot__element:hover .root__sub-element {
color: red;
}
Expected CSS:
.newroot__element:hover .newroot__sub-element {
color: red;
}

Resources