First a re-cap of the basic CSS Chain/Descendant Selector
1> Chain Selectors –
https://stackoverflow.com/questions/13444647/css-class-definition-with-multiple-identifiers
.class1.class2 will match only the elements that have both of the classes defined.
.class1.class2 { background: red; }
<div class="class1 class2"></div>
2> Descendant Selector
The descendant selector matches all elements that are descendants of a specified element.
And the Per Official doc
.class1 .class2 { background: red; }
3> Child Selector
The child selector selects all elements that are the children of a specified element.
The following example selects all
elements that are children of a
div > p {
background-color: yellow;
}
The meaning of a selector with more classes depends on how you combine them in your declarations:
dot notation vs ampersand
Basic Nesting with dot (“.”)
.parent {
.child {
}
}
This compiles to:
.parent .child {}
You can nest as deep as you’d like, but it’s a good practice to keep it only a level or two to prevent overly specific selectors (which are less useful and harder to override).
The & comes in handy when you’re nesting and you want to create a more specific selector, like an element that has both of two classes, like this:
.some-class.another-class { }
.some-class {
&.another-class {
}
}
This will compile to
.some-class.another-class
The & always refers to the parent selector when nesting. We can think of the & as a mechanism that allows us to place the parent selector wherever we need it in our child selector.
Using the & with pseudo classes
You can write pseudo classes on a class in a much less repetitive way with the &:
.button {
&:visited { }
&:hover { }
&:active { }
}
This compiles to:
.button:visited {
}
.button:hover {
}
.button:active {
}
The & in this case allows us to position .button directly next to pseudo classes without repetition in the authored code. If we left out the & from this example, basic nesting would put a space between them like this…
.button :hover
which isn’t the same.
And thats why at the root of the .scss file I can not have an ampersand &
&.sdk-ng-select .ng-dropdown-panel {
@include sdk-ng-select();
}
It will give me following error
SassError: Base-level rules cannot contain the parent-selector-referencing character
.pagination {
a {
&:hover,
&:focus {
color: red;
}
}
}
// in this case, the & represents .pagination a, and will compile to:
.pagination a:hover,
.pagination a:focus {
color: red;
}
Another example
.hoverable {
color: #fff;
&:hover {
color: #ff0;
}
}
The compiled CSS will be
.hoverable {
color: #fff;
}
// just replace the "&" with the parent selector (.hoverable)
.hoverable:hover {
color: #ff0;
}
Nested ampersand – Very useful
The cool thing about ampersands is that they don’t only have to be at the beginning of a nested style definition.
Wherever you put an ampersand into your Sass selector definitions, it is interpreted to mean the parent scope of the current style being defined.
An application of the above is – sometimes you need to define a style that takes the context of the existing style, but only applies in a special case. For example, what if we need a different border treatment for our .hoverableelement when the parent class is .special
The SASS without a nested “&” would be below
.hoverable {
color: #fff;
&:hover {
color: #ff0;
}
}
.special .hoverable {
border: 1px solid #f00;
}
Doing this required us to step out of our .hoverable selector and then re-define it inside a new selector. If there had been more levels of nesting, or more context that needed to be set, that could have been a fairly complex action.
But with the ampersand, Sass allows us to do the same thing without leaving the scope of the .hoverable selector:
.hoverable {
color: #fff;
&:hover {
color: #ff0;
}
.special & {
border: 1px solid #f00;
}
}
Both of these Sass snippets will result in the following CSS:
.hoverable {
color: #fff;
}
.hoverable:hover {
color: #ff0;
}
.special .hoverable {
border: 1px solid #f00;
}
Sass replaced the ampersand with the parent selector, defining a new selector inside of the .special selector. And note because here, there a single space before the “&” – so the generated css will also have a single space before the parent selector (i.e. before .hoverable )
Since & references the top-most selector, it can be extended with additional classes and/or an id like the pseudo class selectors. So let’s say there is a selector of .feature-class and we have an instance where it will be paired with .style-class, which changes the look of it. From within the .feature-class declaration block, we would have a child declaration that starts like this: &.style-class with its own declaration block.
Sass will replace “&” with .feature-class, which becomes feature-class.style-class in our generated CSS.
.feature-class {
color: #0090B2;
&:hover {
color: #FF7A00;
}
&:active {
color: #B25500;
}
&.style-class {
color: #00CEFF;
&:hover {
color: #0090B2;
}
&:active {
color: #FF7A00;
}
}
}
Generated CSS
.feature-class {
color: #0090B2;
}
.feature-class:hover {
color: #FF7A00;
}
.feature-class:active {
color: #B25500;
}
.feature-class.style-class {
color: #00CEFF;
}
.feature-class.style-class:hover {
color: #0090B2;
}
.feature-class.style-class:active {
color: #FF7A00;
}
css class definition with multiple identifiers in a single line – Understaning how it works
1> Chain Selectors –
https://stackoverflow.com/questions/13444647/css-class-definition-with-multiple-identifiers
.class1.class2 will match only the elements that have both of the classes defined.
.class1.class2 { background: red; }
<div class="class1 class2"></div>
.class1, .class2 (i.e. a comma and a space in between) will match the elements with .class1 or .class2
.class1, class2 { background: yellow; }
<div class="class1"></div>
<div class="class2"></div>
Chain selectors are not limited just to classes, you can do it for both classes and ids.
Classes
.classA.classB {
/*style here*/
}
Class & Id
.classA#idB {
/*style here*/
}
Id & Id
#idA#idB {
/*style here*/
}
2> Descendant Selector
.class1 .class2 will match only the elements with class2 within elements with class1.
.class1 .class2 { background: blue; }
<div class="class1">
<div class="class2"></div>
</div>
3> Child Selector
The child selector selects all elements that are the children of a specified element.
The following example selects all
elements that are children of a
div > p {
background-color: yellow;
}
I was working ng-select Angular package, and for my case here, I am trying to target both the below 2 classes
class="ng-select ng-dropdown-panel"
// And also
class="ng-dropdown-panel sdk-ng-select"
Note when I use component (which is the popular angular package) in .html file all ng-select related classes will have the ultimate parent ‘ng-select’
Here’s my overall structur of the @mixin in .scss file
@mixin sdk-ng-select {
...many styles here
.ng-dropdown-panel,
&.ng-dropdown-panel.sdk-ng-select {
.ng-dropdown-footer {
@extend .sdk-text-body-light-2;
display: flex;
align-items: center;
justify-content: center;
}
...many styles here
}
.sdk-ng-select {
@include sdk-ng-select();
}
Then in an .html file of Angular component was consuming the above style as below
<ng-select class=”sdk-ng-select”
The above will work, but its the wrong way to handle.
Problem with above
&.ng-dropdown-panel.sdk-ng-select should not be required.
I could simply do
.ng-dropdown-panel, &.ng-dropdown-panel
In the above, the first selector (.ng-dropdown-panel) matches “ng-dropdown-panel” inside the “ng-select”
The second selector (&.ng-dropdown-panel) matches
.ng-dropdown-panel.sdk-ng-select
Recollect, the way ampersand work, that it will replace “&” with .parent-class, which becomes
.ng-dropdown-panel.sdk-ng-select in our generated CSS.
The downside to repeating the .sdk-ng-select selector inside the mixing (as I was doing in the top of this page) is that mixin is made in a way where it does not know about the class .sdk-ng-select, instead, it is used inside it, like below.
.sdk-ng-select {
@include sdk-ng-select();
}
And having the selector .sdk-ng-select inside the mixin breaks this structure.
So the correct version would be
.ng-dropdown-panel,
&.ng-dropdown-panel {
.ng-dropdown-footer {
@extend .sdk-text-body-light-2;
display: flex;
}
The meaning of a selector with more classes depends on how you combine them in your declarations:
Relevant issue in Saas github repo
“This error has existed since 3.0 which was released in May 2010.
It’s nonsensical to refer to a parent selector at the base-level of a stylesheet. Inferring that & should be the universal selector at the root level is not at all a safe assumption. Additionally, this is often indicative of a coding mistake. So we consider it an error.”



