RegEx simple parser of css selectors - css

I want to add scope to my selectors.
A good way to achieve it in my opinion is to select css selector and return mySelector + oldSelector
For example I have .old { background: black; }, I would transform it into .mySelector .old { background: black; }
Let's say I have this CSS
.a
{
background: red;
}
#b {
background: green;
}
input {
background: blue;
}
[type=custom] {
background: white;
}
I would do .+?{, but it selects not needed parts. Inverse of {.+?} would work, but I don't know how to inverse it. Any ideas ?

I figured out I can use String.match({.+?}) to get all rules and String.split({.+?}) to get selectors in JavaScript.
Also I've found a library to easily parse CSS in JavaScript https://github.com/reworkcss/css

Related

scss prepend selector to current selector

Is there a way to prepend a selector directly to the current selector in scss. Consider the following:
.object-fit {
object-fit: cover;
height: 100%;
width: 100%;
overflow: hidden;
}
is there a way to prepend img so that the output is img.object-fit?
The only way I have seen for prepending is to add & after like so:
.object-fit {
img & {
}
}
but this would turn it into a parent child selector: img .object-fit
The normal way would be just to append the second selector with &img but as this has no dot before the selector, that ends up with a different class name: .object-fitimg
So basically the question is is there anyway inside the object fit class to prepend a bare element selector?
If you use #at-root and & with interpolation syntax:
.object-fit {
#at-root img#{&} {
color: blue;
}
}
Your output will be:
img.object-fit{
color: blue;
}
Complete answer here is #at-root selector-append(), which will also work for multiple parent selectors.
Source: https://github.com/sass/sass/issues/2059#issuecomment-218862922
.object-fit,
.non-fit {
#at-root #{selector-append("img", &)} {
color: blue;
}
}
Output
img.object-fit, img.non-fit {
color: blue;
}

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

LESS: Extend a previously defined nested selector

I've been trying like a mad man to get the following LESS statement to work, but now i am fearing that it's not gonna happen :/ So I am turning now to you guys in the end for help!
I have the following statement:
.top{
&-first{
background:black;
&-item{
color:white;
}
}
&-second{
background:green;
&-item:extend(.top-first-item){}
}
}
I was hoping for to achive the following output:
.top-first {
background: black;
}
.top-first-item,
.top-second-item{
color: white;
}
.top-second {
background: green;
}
But unfortunately it does not compile that but this instead:
.top-first {
background: black;
}
.top-first-item{
color: white;
}
.top-second {
background: green;
}
LESS currently does not support extending a "concatenated name" selectors (basically, .top &-first &-item is interpreted as three distinct selector elements and never found by extend looking for a single selector).
A workaround for your particular case:
.top {
&-first {
background: black;
}
&-second {
background: green;
}
&-first, &-second {
&-item {
color: white;
}
}
}
Another option is to break the designations into separate classes:
LESS
.top{
&.first{
background:black;
&.item{
color:white;
}
}
&.second{
background:green;
&.item:extend(.top.first.item){}
}
}
CSS Output
.top.first {
background: black;
}
.top.first.item,
.top.second.item {
color: white;
}
.top.second {
background: green;
}
Which of course requires a change in your html designation from class="top-first-item" to class="top first item".
This is obviously something that should be working in LESS. I have a few months ago put an issue on the LESS.js github regarding exactly this.
Link to Github issue
In the mean time, i recommend using seven-phases-max's solution by simply putting the classes together like so:
&-first, &-second {}
But then you cant abstract the second out into another file.
Another solution would to make an "extends.less" file, in which you can have small snippets you find your self using time from time.
Just use 'all' suffix. Example: &:extend(.top-first-item all);

testing two classes don't exist with less css

I have an element lets say it could have .foo or .bar or both or none as a class:
<div class="foo bar">green</div>
<div class="foo">green</div>
<div class="bar">green</div>
<div class="something-else">red</div>
How can I test that the element doesn't have either class.
I tried something like this, but it doesn't work as expected:
div {
background: green;
&:not(.foo) and &:not(.bar) {
background: red;
}
}
I don't see many examples using less and not(), only 1 in their docs.
To say not to multiple conditions in a CSS selector, you need to chain them together: div:not(.foo):not(.bar)
div {
background: green;
&:not(.foo):not(.bar) {
background: red;
}
}
I was able to do it by nesting two &:not() rules, but I'm not sure this is the best way.
div {
background: green;
&:not(.foo) {
&:not(.bar) {
background: red;
}
}
}
There is always the pure css alternative.
div { background: red; }
div.foo, div.bar { background: green; }

How do you define attribute selectors in SASS?

In CSS, you can do this:
input[type=submit] {
// properties
}
It's a very useful for styling form buttons.
How do you do the same thing in SASS?
You can also nest it like this
input
&[type="submit"]
....
&[type="search"]
....
This converter website says:
input[type=submit]
// properties
I use the one below in my project.
.bg-brand-3 {
background-color: black;
&[type="button"]:enabled {
&:hover {
background-color: orange;
}
&:active {
background-color: green;
}
}
&[type="submit"] {
// css
}
}
The :enable has the same meaning as :not(:disabled)

Resources