Parent Selector nested inside &:hover - css

I am using the Less parent selector to shorten my selectors:
.module-name {
// styles go here
&__sub-module-1 {
//styles go here
}
}
Now my problem is how to continue to use the parent selector for adding the module-name inside a nested :hover statement. E.g. on hover of sub-module-1 I want to change something in sub-module-2. Inside the &:hover statement, what does the parent selector refer to?
.module-name {
&__sub-module1 {
&:hover {
&__sub-module2 {
// on hover of .module-name__sub-module1 change something in .module-name__sub-module2
}
}
}
}
If i write it like this it works, but it defeats the purpose of using the parent selector to automatically fill in the name of the module:
.module-name {
&__sub-module1 {
&:hover {
.module-name__sub-module2 {
// on hover of .module-name__sub-module1 change something in .module-name__sub-module2
}
}
}
}
I hope I could adequately express my problem; any help is appreciated.

The parent selector (&) will always refer to the full parent based on the level at which you are. For example at the first level of nesting, & refers to .module-name. In the second level, it refers to .module-name__sub-module1 and in the third level, it refers to .module-name__sub-module1:hover.
Extract from Less Website: Note that & represents all parent selectors (not just the nearest ancestor or the overall root ancestor)
The emphasised part in the above statement is my inclusion based on the context
For this particular case, you could assign the module-name to a variable and use selector interpolation like below to form the selectors.
The variable value would never change unlike the parent selector (&) irrespective of how many levels of nesting you have and at which level of nesting you are using it.
#module-name: mod-name;
.#{module-name} {
&__sub-module1 {
&:hover {
& .#{module-name}__sub-module2 {
// on hover of .module-name__sub-module1 change something in .module-name__sub-module2
color: blue;
}
}
}
}

Related

How I exclude more than one element with CSS selector group? [duplicate]

I'm trying to select input elements of all types except radio and checkbox.
Many people have shown that you can put multiple arguments in :not, but using type doesn't seem to work anyway I try it.
form input:not([type="radio"], [type="checkbox"]) {
/* css here */
}
Any ideas?
Why :not just use two :not:
input:not([type="radio"]):not([type="checkbox"])
Yes, it is intentional
If you're using SASS in your project, I've built this mixin to make it work the way we all want it to:
#mixin not($ignorList...) {
//if only a single value given
#if (length($ignorList) == 1){
//it is probably a list variable so set ignore list to the variable
$ignorList: nth($ignorList,1);
}
//set up an empty $notOutput variable
$notOutput: '';
//for each item in the list
#each $not in $ignorList {
//generate a :not([ignored_item]) segment for each item in the ignore list and put them back to back
$notOutput: $notOutput + ':not(#{$not})';
}
//output the full :not() rule including all ignored items
&#{$notOutput} {
#content;
}
}
it can be used in 2 ways:
Option 1: list the ignored items inline
input {
/*non-ignored styling goes here*/
#include not('[type="radio"]','[type="checkbox"]'){
/*ignored styling goes here*/
}
}
Option 2: list the ignored items in a variable first
$ignoredItems:
'[type="radio"]',
'[type="checkbox"]'
;
input {
/*non-ignored styling goes here*/
#include not($ignoredItems){
/*ignored styling goes here*/
}
}
Outputted CSS for either option
input {
/*non-ignored styling goes here*/
}
input:not([type="radio"]):not([type="checkbox"]) {
/*ignored styling goes here*/
}
Starting from CSS Selectors 4 using multiple arguments in the :not selector becomes possible (see here).
In CSS3, the :not selector only allows 1 selector as an argument. In level 4 selectors, it can take a selector list as an argument.
Example:
/* In this example, all p elements will be red, except for
the first child and the ones with the class special. */
p:not(:first-child, .special) {
color: red;
}
Unfortunately, browser support is somewhat new.
I was having some trouble with this, and the "X:not():not()" method wasn't working for me.
I ended up resorting to this strategy:
INPUT {
/* styles */
}
INPUT[type="radio"], INPUT[type="checkbox"] {
/* styles that reset previous styles */
}
It's not nearly as fun, but it worked for me when :not() was being pugnacious. It's not ideal, but it's solid.
If you install the "cssnext" Post CSS plugin, then you can safely start using the syntax that you want to use right now.
Using cssnext will turn this:
input:not([type="radio"], [type="checkbox"]) {
/* css here */
}
Into this:
input:not([type="radio"]):not([type="checkbox"]) {
/* css here */
}
https://cssnext.github.io/features/#not-pseudo-class

SASS: Conditional values of CSS property based on that if an element with certain value of the same property has been present already in the page

I want to have different values of a css property (I am using SASS), based on that whether a element with a certain property's value '$additionalNavHeight' is present on the page. In some pages there is no such element, in other - there is. I wrote a SASS mixin:
#mixin top-position($navHeight, $additionalNavHeight)
{
#if $additionalNavHeight == true {
.loadingAnimation {
top: $navHeight + $additionalNavHeight;
}
}
#else {
.loadingAnimation {
top: $navHeight;
}
}
}
And I included the mixin in the selector:
#include top-position($navHeight, $additionalNavHeight);
I thought this should change the value of the property 'top' of the element with the class 'loadingAnimation', based on that if in the page already is present the element with the value of its 'top' property '$additionalNavHeight'. The compiler doesn't show any error, but the code doesn't change anything. What am I doing wrong? Any help would be very appreciated.
Тhe simplest solution. You must check with JavaScript if element exists or not
and to apply the second class to element. In the second case (element existing)
you must add adittionnal height. In this case the mixin is redundant.
.loadingAnimation {
top: $navHeight;
}
.loadingAnimation.additinnalHeight {
top: $navHeight + $additionalNavHeight;
}
Here is example jsfiffle:
https://jsfiddle.net/ra9r8rk8/
In this case element will receive class newClass when the first div exists. (the element)
Edit: This is second improved solution. In fact there is no need for regular expression. We can just use classList:
https://jsfiddle.net/ra9r8rk8/1/

How to reference a parent but attach a tag to it in sass?

If I have this
.A {
}
input.A {
}
how can I use sass to factor out the parent .A? I tried
.A {
input.& {
}
}
but it didn't work.
Sass always seems to have a problem when appending the parent selector at the end. It doesn't have any problems when the parent selector is added at the start or in the middle.
One possible solution would be to use the #at-root directive. The #at-root directive tells compiler to move the selector to the root level (instead of being an inner nested block) and then appending the parent selector through selector interpolation produces the expected output.
.A {
#at-root input#{&} {
property: value;
}
}
(Using just selector interpolation without #at-root directive would end up producing .A input.A.)

Wildcard nested selector

I have the following bit of Sass code :
.c-panel-menu-c {
&.grid_6 {
float: right;
}
}
i need to have float right applied to all grids that start with grid_ . The float should only be set when the grid class is applied to an element that also has c-panel-menu-c.
I wanted to use a wildcard selector like
div[class*='grid_'] {
float:right
}
But am not sure if it's possible the way i need it. Something like
.c-panel-menu-c {
&.div[class*='grid_'] {
vertical-align: top;
}
}
Which doesnt work.
Thank you for any tips/advice.
the problem is the tag name ... you can not concatenate a tag name, for example div, at the end of another selector, like you would with a class name. Let's look at your example:
.c-panel-menu-c {
&.grid_6 {
...
}
}
will return
.c-panel-menu-c.grid_6 { ... }
which is a valid selector. But attaching 'div' at the end (lets leave out the attribute selector part for now)
.c-panel-menu-c {
&div {
...
}
}
does not make sense (and it also isn't possible in Sass, hence you get an error) as the tag name should always be before the class or id selector. This does not change if we add an attribute selector statement, so that's why it does not work the way you tried &div[class*='grid_'].
What you can do, is add the attribute selector directly to the preceding class name, like so:
.c-panel-menu-c {
&[class*='grid_'] {
...
}
}
which would compile to:
.c-panel-menu-c[class=*'grid_'] { ... }
and select everything that has the class .c-panel-menu-c and a class containing with grid_.

Can the :not() pseudo-class have multiple arguments?

I'm trying to select input elements of all types except radio and checkbox.
Many people have shown that you can put multiple arguments in :not, but using type doesn't seem to work anyway I try it.
form input:not([type="radio"], [type="checkbox"]) {
/* css here */
}
Any ideas?
Why :not just use two :not:
input:not([type="radio"]):not([type="checkbox"])
Yes, it is intentional
If you're using SASS in your project, I've built this mixin to make it work the way we all want it to:
#mixin not($ignorList...) {
//if only a single value given
#if (length($ignorList) == 1){
//it is probably a list variable so set ignore list to the variable
$ignorList: nth($ignorList,1);
}
//set up an empty $notOutput variable
$notOutput: '';
//for each item in the list
#each $not in $ignorList {
//generate a :not([ignored_item]) segment for each item in the ignore list and put them back to back
$notOutput: $notOutput + ':not(#{$not})';
}
//output the full :not() rule including all ignored items
&#{$notOutput} {
#content;
}
}
it can be used in 2 ways:
Option 1: list the ignored items inline
input {
/*non-ignored styling goes here*/
#include not('[type="radio"]','[type="checkbox"]'){
/*ignored styling goes here*/
}
}
Option 2: list the ignored items in a variable first
$ignoredItems:
'[type="radio"]',
'[type="checkbox"]'
;
input {
/*non-ignored styling goes here*/
#include not($ignoredItems){
/*ignored styling goes here*/
}
}
Outputted CSS for either option
input {
/*non-ignored styling goes here*/
}
input:not([type="radio"]):not([type="checkbox"]) {
/*ignored styling goes here*/
}
Starting from CSS Selectors 4 using multiple arguments in the :not selector becomes possible (see here).
In CSS3, the :not selector only allows 1 selector as an argument. In level 4 selectors, it can take a selector list as an argument.
Example:
/* In this example, all p elements will be red, except for
the first child and the ones with the class special. */
p:not(:first-child, .special) {
color: red;
}
Unfortunately, browser support is somewhat new.
I was having some trouble with this, and the "X:not():not()" method wasn't working for me.
I ended up resorting to this strategy:
INPUT {
/* styles */
}
INPUT[type="radio"], INPUT[type="checkbox"] {
/* styles that reset previous styles */
}
It's not nearly as fun, but it worked for me when :not() was being pugnacious. It's not ideal, but it's solid.
If you install the "cssnext" Post CSS plugin, then you can safely start using the syntax that you want to use right now.
Using cssnext will turn this:
input:not([type="radio"], [type="checkbox"]) {
/* css here */
}
Into this:
input:not([type="radio"]):not([type="checkbox"]) {
/* css here */
}
https://cssnext.github.io/features/#not-pseudo-class

Resources