Using CSS class prefixes as namespaces - css

I was thinking of creating a LESS stylesheet where I'd have a given prefix which would work as a namespace.
I've got this (working) code so far:
.FormAdd { // common prefix to all of its children
&-buttons { // the real class in HTML is .FormAdd-buttons
display: block;
...
}
&-results { // the real class in HTML is .FormAdd-results
display: inline;
...
}
}
BUT I would rather have this code (just seems prettier to me):
.FormAdd {
buttons {
display: block;
...
}
results {
display: inline;
...
}
}
Is this somehow possible to achieve (preferably in LESS) without creating my own CSS preprocessor?

Related

Approach to reduce SASS generated lines

In my curently workflow, I use some mixins to easier responsive breakpoints code. I also use gulp to process and compress those generated CSS. Example below:
#footer {
.block-contacts {
.social_title {
display: block;
#include desktop() {
display: inline-block
}
&:before {
width: 100vw;
#include desktop() {
width: 50vw;
}
}
}
}
}
After the process of compile and minify, this code above ends up repeating the #media rule, like this:
#footer .block-contacts .social_title {
display: block;
}
#media(min-width: 64rem){
#footer .block-contacts .social_title {
display:inline-block
}
}
#footer .block-contacts:before {
width:100vw;
}
#media(min-width: 64rem){
#footer .block-contacts:before {
width:50vw
}
}
In this example I used only a "small" hierarchy and selector, but this in the whole project I guess it could be a negative impact for performance or assets size.
I know I can avoid this duplicity recreating the rule structure inner a single #include desktop() at the end of file.
My question is if there is another way, authomated, to reduce those lines creation, something I can do in the mixin that join all of this calls, or some gulp process/plugin, or even in the SASS...

Scss module (css modules): importing from other scss files

I'm currently converting my sass styles to use css modules to avoid style conflicts. My understanding is that it generates unique class names, which makes it hard if I want to target another component (e.g. a child component) defined in a different file.
Say I have a component Button, and it imports from a Button.module.scss file:
// Button.js
import styles from "./Button.module.scss";
export const Button () => <button className={styles.button} />;
// Button.module.scss
.button {
// relevant styles.
}
Now I have another component ButtonGroup. Say I want to make the button in the group have margin between them, I would have something like this:
// ButtonGroup.module.scss
.buttonGroup {
display: flex
&[class~=horizontal] {
& > .button:not(:first-child) { // still using the same class name
margin-left: 1rem;
}
}
&[class~=vertical] {
flex-direction: column;
& > .button:not(:first-child) { // still using the same class name
margin-top: 1rem;
}
}
}
Notice I'm still using the .button to target the individual buttons. But this won't work because the child component doesn't actually have .button as its class name since it's a generated unique class name.
I could use something like [class^=Button] but that feels hacky and hard to maintain once you have a lot of components. (Also realized it wouldn't work in production.)
css-modules is not related to SASS or SCSS and has its own set of supported features and keywords. Yes, they can be used together, which I actually do in most my projects. But I avoid having classname dependencies between different files. I'm aware of some features that could be used to share classnames, but avoiding the need for it is probably the best solution. I will in the following section list all potential solutions to your conundrum I can think of; choose what suits you best:
Solution #1: Never sharing classnames, co-locating styles that belong together and operate on the same classnames.
In your case this would mean that you only have one scss file relating to buttons buttons.modules.scss and both Button.js and ButtonGroup.js import it.
Solution #2: exempt shared classnames from the unique generated name mechanism by marking them as :global. This can be done thus:
// button.module.scss
// this will stay a global classname
:global(.button) {
// the button styles
}
// this will be treated as usual, generating a local name
.icon {
// some icon stuff
}
// buttongroup.module.scss
.buttonGroup {
display: flex;
// will be resolved as local classname
&.horizontal {
flex-direction: row;
// will be resolved as global classname
& > :global(.button):not(:first-child) { margin-left: 1rem; }
}
&.vertical {
flex-direction: column;
& > :global(.button):not(:first-child) { margin-top: 1rem; }
}
}
Solution #3: accept anonymous children. You can omit the classname of the children. no one places non-buttons in a button group (might even enforce it in your component code).
// buttongroup.module.scss
.buttonGroup {
display: flex;
&.horizontal {
flex-direction: row;
& > *:not(:first-child) { margin-left: 1rem; }
}
&.vertical {
flex-direction: column;
& > *:not(:first-child) { margin-top: 1rem; }
}
}
Solution #4: Reference content from another file. There seems to be some support for a syntax that can reference/import stuff from other files, but I perused the documentation and a few github issue discussions 'import className from fileName' 'more' 'and more' without getting any clear answer as to how one would import a local classname from another file. There might be something possible either along those lines see here:
#import button from './button.module.scss';
.buttonGroup {
display: flex;
&.horizontal {
flex-direction: row;
& > .button:not(:first-child) { margin-left: 1rem; }
}
&.vertical {
flex-direction: column;
& > .button:not(:first-child) { margin-top: 1rem; }
}
}
...or along those lines see here:
:import("./button.module.scss") {
imported-button: button;
}
.buttonGroup {
display: flex;
&.horizontal {
flex-direction: row;
& > .imported-button:not(:first-child) { margin-left: 1rem; }
}
&.vertical {
flex-direction: column;
& > .imported-button:not(:first-child) { margin-top: 1rem; }
}
}
Solution #5: Have your container component add a class .button-group-item to each child and use it to apply the margins instead of the .button class.

Which tool use to merge CSS and SCSS code

Since my code is difficult to read I want to merge some long regular css statements like this:
.aui #content .columns-1-2-equal .row-fluid #column-3 header {
prop1 ...prop2 prop3
}
with a current scss document.
So assuming i have a piece of CSS which looks like the previous statement and I have a scss file containing this for example:
.aui #content {
prop4
.columns-1-2-equal {
prop5
.row-fluid {
#column-3 {
.header {
}
}
}
I want as a result
.aui #content {
prop4
.columns-1-2-equal {
prop5
.row-fluid {
#column-3 {
.header {
// MERGED CODE
prop1 ...prop2 prop3
}
}
}
Is there an automatic way to do it without having to search for the equivalent element in the SCSS tree and copy paste all the properties?
In this case you have two files:
OLD.scss
div {
width: 300px;
}
and
NEW.scss
#import "OLD.scss";
div {
color: red;
}
First you should run sass NEW.scss COMBINED.css it will output:
COMBINED.css
div {
width: 300px;
}
div {
color: red;
}
Then sass-convert COMBINED.css COMBINED.sass and you will get:
COMBINED.sass
div {
width: 300px;
color: red;
}
You don't really have to because it will be compiled automatically. But, I get that it can be difficult to read the code in this very long format. I tested this tool and its basic function. Hope this helps for you.
https://www.css2scss.com/

"Resting" & in Sass

I'm importing sass classes from another project and want to provide a wrapper to keep these styles localised.
My wrapper looks like this
.my-wrapper {
#include "framework-main"
}
I first looked fine but then I noticed that some tiles are missing. The problem is that the framework sass files use heavily reference to parent: &. This works fine for them but when I apply the wrapper it's get injected everywhere.
How can I make the wrapper a prefix only?
To illustrate:
SASS:
.wrapper {
// reset here somehow, I have no control over the nested code.
.parent {
&--child1 &--child2 {
width: 10%;
}
}
}
What I want:
.wrapper .parent--child1 .parent--child2 {
width: 10%;
}
What I get:
.wrapper .parent--child1 .wrapper .parent--child2 {
width: 10%;
}
Is this even possible?
Yes, it is possible, there is just small mistake in your code - you don't need . in front of &--child so it will not break selector construction:
.wrapper {
// reset here somehow
.parent {
&--child {
&--grand-child{
width: 10%;
}
}
}
}
gives
.wrapper .parent--child--grand-child {
width: 10%;
}

less mixin for looping over a list without using extract and length functions, less version 1.3.3

I have been trying to loop over a list and generate some css, however i am stuck with version 1.3.3 which doesn't have "extract" and "length" methods. Also the less compiler in use doesn't support javascript, so 'backtick' is also not working.
To give an example
// The list of strings
#items: ~"#item1", ~"#item2", ~"#item3"
.desired-mixin(#parent-name, #items ) {
#{parent-name}{
.some-class {
#{current_item} { display: block }
}
}
}
.desired-mixin(~".parent-name", #items);
// Generated css
.parent-name .some-class #item1 { display: block; }
.parent-name .some-class #item2 { display: block; }
.parent-name .some-class #item3 { display: block; }
Some pointers on this would be great, let me know if additional details are required.

Resources