Using :extend() in LESS with pseudo-elements - css

I would like to code a simple alert component that has color variations as well as font icon variations. The icons are coded with :before. I can write it fine in in vanilla CSS but I want to do it in LESS as compact as possible and I am stuck with using :extend() which I rarely used :(
.base-alert {
color: red;
...
&:before {
content: 'base-icon-unicode';
...
}
}
In vanilla CSS the code for the variation classes would be like:
.alert-warning {
color: red;
}
.alert-warning:before {
content "warning-icon-unicode";
}
But then the HTML should be class="base-alert alert-warning". I would like to code the variation classes in LESS, using :extend() so in HTML I would only write class="alert-warning" or class="alert-succes" and so on. Something like:
.alert-warning {
&:extend(.base-alert);
color: orange;
&:before {
content "warning-icon-unicode";
}
}
But it the :before doesn't apply anymore.

It seems like you are looking for the following:
.alert-warning:extend(.base-alert all) {
color: orange;
&:before {
content: "warning-icon-unicode";
}
}
This basically just extends .alert-warning from .base-alert using the all keyword. Then the content value for the pseudo-element is changed to warning-icon-unicode and the color is changed to orange.
Based on your comment about extending to multiple classes, I guess you could use the following, which will essentially just alias the selector:
.alert-warning, .alert-warning2 {
&:extend(.base-alert all);
color: orange;
&:before {
content: "warning-icon-unicode";
}
}
Alternatively, depending on your preferences, you could also use the following, which will produce the same desired results.
.alert-warning:extend(.base-alert all),
.alert-warning2:extend(.base-alert all) {
color: orange;
&:before {
content: "warning-icon-unicode";
}
}
..this will work the same as well:
.alert-warning:extend(.base-alert all) {
color: orange;
&:before {
content: "warning-icon-unicode";
}
}
.alert-warning2:extend(.alert-warning all) {}

Related

What does `&#my-id` mean in CSS or SASS?

I inherited some CSS code, which is making use of the & character prior to the id name to style it. It looks something like this:
&#my-id {
// Content and attributes
}
There are also other instances of it, such as:
&:before {
// content and attributes
}
and
&:hover {
// content and attributes
}
What do those mean? I can't find a good way to express this in a search, so I can't find anything. My apologies if this is a duplicate.
It refers to the parent selector.
Input:
.parent {
&.child {
color: red;
}
}
Output:
.parent.child { color: red }
It's really helpful if you're writing CSS in BEM format, something like:
.block {
&__element {
width: 100px;
height: 100px;
&--modifier {
width: 200px;
}
}
}
.block__element { width: 100px; height: 100px;}
.block__element--modifier { width: 200px;}
<div class="block__element"></div>
<div class="block__element block__element--modifier"></div>
And finally, all examples I've shared have been concatenating the class names, but you can also use it as a reference, like:
.parent {
& .child {
color: red;
}
}
.parent {
.child & {
color: blue;
}
}
.parent .child { color: red }
.child .parent { color: blue }
Additional references:
http://lesscss.org/features/#parent-selectors-feature
https://blog.slaks.net/2013-09-29/less-css-secrets-of-the-ampersand/
Using the ampersand (SASS parent selector) inside nested selectors
It's a built-in feature of Sass: https://css-tricks.com/the-sass-ampersand/
You can use it when you're nesting selectors and you need a more specific selector, like an element that has both of two classes:
If your CSS looks like this:
.some-class.another-class { }
And you wanted to nest, the Sass equivalent is:
.some-class {
&.another-class {}
}

How to reference SCSS sibling?

Assuming that I have the following HTML:
<div class="navigation__item">
<span class="navigation__item__icon"></span>
</div>
I want to apply some rules to an icon, when hovering an item, which can be described with the following CSS:
.navigation__item__icon {
color: black;
}
.navigation__item:hover .navigation__item__icon {
color: white;
}
I can achieve this using the following SCSS:
.navigation__item {
&:hover {
.navigation__item__icon { <-- here
color: white;
}
}
&__icon {
color: black;
}
}
Here, is there any way to avoid writing navigation__item? Something like "parent rule \ element".
I like Sass for logical structure so that if I want to rename the whole navigation block with elements, I can simply change navigation class name in the root, and everything is renamed. This case breaks this advantage.
Update: Actually, I have found a way to do this without using {} braces. & can be repeated more than once:
.navigation__item {
&:hover &__icon {
color: white;
}
&__icon {
color: black;
}
}
It is great, but it doesn't make much sense if I have many rules and rules for &:hover itself. The question is still open - is this possible to access sibling element definition from within the {} block.
In Stylus there is a Partial reference but I don't know anything similar in SASS. One solution could be using a variable for the parent selector:
.navigation__item {
$selector: &;
&:hover {
#{$selector}__icon {
color: white;
}
}
&__icon {
color: black;
}
}
Is usefull is you change navigation__item class for another.
EDIT: I had used a wrong example, it's OK now.

Condensing CSS class rules

I have code like:
#header button active:hover, #footer button active:hover {
color: purple;
}
Instead of having to list all the sub-classes/elements when only #header/#footer are different, is it possible to do something like:
(#header|#footer) button active:hover {
color: purple;
}
Yeah there's a matches pseudo class, but if you're hoping it will save you some typing it still needs vendor prefixes you'd have to duplicate and the support isn't great.
:matches(#header, #footer) button active:hover {
color: purple;
}
:-webkit-any(#header, #footer) button active:hover {
color: purple;
}
:-moz-any(#header, #footer) button active:hover {
color: purple;
}
So as you can see it ends up being more verbose than just adding the comma and another selector at the moment.

Scoping CSS / Prepend selector with LESS

I have a chunk of CSS that I want to "scope" to a specific block of HTML. I'm generating a unique ID and then setting it on the block of HTML and then would like to wrap the chunk of CSS with the same ID so that those selectors can't match sibling or parent elements. I don't know the contents of the chunk of CSS. Given a chunk of CSS:
.container {
background-color: black;
}
.container .title {
color: white;
}
.container .description {
color: grey;
}
I need it to come out like this:
.theme0 .container, .theme0.container {
background-color: black;
}
.theme0 .container .title, .theme0.container .title {
color: white;
}
.theme0 .container .description, .theme0.container .description {
color: grey;
}
Is there any way to do this with LESS? The first selector is easy, just wrap the CSS chunk with '.theme0 {' + cssChunk + '}'. But I haven't been able to figure out a way to prepend '.theme0' to all of the selectors without the space.
EDIT:
So I should clarify that our intentions are to build such a system into our build process / dependency system. We're attempting to scope a chunk of css to a react component. We have a couple different approaches we're trying out, this is just one of them. Point is, the CSS and HTML we're trying to scope could be anything, we have no control or knowledge of it. The first pattern can easily be achieved by prepending .uniqueID { and appending }. This gives .uniqueID .someSelector {}. I'm wondering if it's possible to do a similar thing but get .uniqueID.someSelector {}? Ideally without having to write the original chunk of CSS with knowledge of our scoping system.
Assuming the component styles are in a separate CSS file, i.e.:
// component.css
.container {
background-color: black;
}
.container .title {
color: white;
}
.container .description {
color: grey;
}
The wrapper code could be:
.theme0 {
#import (less) "component.css";
&.container:extend(.theme0 .container all) {}
}
in less you can nest selectors for selecting inside that element like:
.theme {
color: black;
.container {
color: blue;
}
}
This wil generate:
.theme {
color:black;
}
.theme .container {
color:blue;
}
Creating elements that are connected is easy enof:
.test#badge will select a class test width an id badge
In less this is dont with the & symbol. (this selects the starting property)
.test {
color: blue;
&#badge {
color:black;
}
}
Compiles to:
.test {
color: blue;
}
.test#badge {
color: black;
}
And for the final selector:
To get the output of .test, .container use the function: .test:extends(.container);
.test {
color: black;
&:extends(.conatiner);
}
.container {
color: pink;
}
Compiles to:
.test {
color: black;
}
.test, .container {
color: pink;
}
You can even extend multiple ones in a single line:
.test:extends(.oclas, .tclss);
and its wil work as abose only for both classes. So outputed selectors would be .test, .oclass and .test, .tclass

Focused selector in variable . How to do that stuff in LESS like in SCSS

In SCSS i can do so:
and then
$selector-active: "&:hover, &:focus, &:active";
.class {
color: red;
#{$selector-active} {
color: green;
}
}
And its working.
How can i do this in LESS?
Hmm, interesting. Currently LESS does not expand its "&" within a selector interpolation, i.e. the straight-forward conversion DOES NOT work:
#selector-active: &:hover, &:focus, &:active;
.class {
color: red;
#{selector-active} {
color: green;
}
}
So you'll need some more tricky code... Using a callback/hook technique for example:
.selector-active() {
&:hover, &:focus, &:active {
.selector-active-properties();
}
}
.class {
color: red;
.selector-active();
.selector-active-properties() {
color: green;
}
}
You can get it even shorter:
.selector-active() {&:hover, &:focus, &:active {.-}}
.class {
color: red;
.selector-active;.-() {
color: green;
}
}
However there's important thing to remember when using hackish names for a hook/callback mixins.
If at some point you need another mixin with the same technique then you'll also need another name
for its callback (not the one you used for .selector-active()). Otherwise you get into problems if you try to use both "utilities" in the same scope. More over if you define some .inside() or .-() in the global scope they will override those coming from within .class and the trick becomes broken...
In other words, using "long/descriptive/unique" hook/callback names are just "safer" in a long run.
Btw. there's also a shorter syntax for the "hover specialization":
// same as .selector-active(#arg) when (#arg = hover):
.selector-active(hover) {
&:hover {
.inside();
}
}
I liked #Max nice solution. And this give me a way to move further. So i did a tweek with words for my self.
.selector-active() {
&:hover, &:focus, &:active {
.inside();
}
}
.selector-active(#type) when (#type = hover) {
&:hover {
.inside();
}
}
In use:
.class {
color: red;
.selector-active(); .inside() {
color: red;
}
}
I also tried to work with classes. LESS is prety owkward in this stuff, in 1.4.1 i must use:
.smthElse(#string) {
&.class-#{string}-small,
&.class-#{string}-big,
&.class-#{string}-tall {
.inside();
}
}
in 1.3.1 i must to use:
(~".myclass_#{index}") {...
#see http://lesscss.org/
Enough compact, and could be in use. So i can still work with LESS :) yey.
P.S.: All above is for less.js v1.4.1

Resources