Render comma separated selectors separately in SCSS - sass

I'm trying to style progress bars using SCSS. To get this working in both Webkit and Gecko browsers I need to use both -webkit and -moz prefixes:
progress {
height: 50px;
-webkit-appearance: none;
appearance: none;
background: cyan;
&::-moz-progress-bar,
&::-webkit-progress-value {
background-color: orange;
}
&::-webkit-progress-bar {
background-color: cyan;
}
}
which renders to
progress {
height: 50px;
-webkit-appearance: none;
appearance: none;
background: cyan;
}
progress::-moz-progress-bar, progress::-webkit-progress-value {
background-color: orange;
}
progress::-webkit-progress-bar {
background-color: cyan;
}
This works great in Firefox, but Chrome doesn't seem to like it. Compare the following two implementations:
Comma separated selectors
progress {
height: 50px;
-webkit-appearance: none;
appearance: none;
background: cyan;
}
progress::-moz-progress-bar, progress::-webkit-progress-value {
background-color: orange;
}
progress::-webkit-progress-bar {
background-color: cyan;
}
<progress max="1" value="0.5"></progress>
Entirely separate declarations
progress {
height: 50px;
-webkit-appearance: none;
appearance: none;
background: cyan;
}
progress::-webkit-progress-value {
background-color: orange;
}
progress::-moz-progress-bar {
background-color: orange;
}
progress::-webkit-progress-bar {
background-color: cyan;
}
<progress max="1" value="0.5"></progress>
The above code snippets render in Firefox and Chrome as shown below
Firefox
Chrome
comma separated
separate declarations
It seems like the problem comes from rendering the CSS with vendor-specific pseudos in comma-separated lists. Is there any way to force the SASS processor to render each selector in a comma separated list as its own declaration?
It would be nice to not use mix-ins, but if it's the only way it's the only way.

Yes, you are able to do so! If you want to render SASS to seperate CSS rules simply divide the comma seperated list into two seperate rules. SASS keeps different rules seperate and will not wrap them together. Example:
// ### > SASS
xprogress {
height: 50px;
appearance: none;
background: cyan;
//## divide comma seperated selectors
//## into different rules
&::-moz-progress-bar {
background-color: orange;
}
&::-webkit-progress-value {
background-color: orange;
}
&::-webkit-progress-bar {
background-color: cyan;
}
}
// ### > compiles to css
progress {
height: 50px;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
background: cyan;
}
//## when compiling CSS
//## different rules will survive
progress::-moz-progress-bar {
background-color: orange;
}
progress::-webkit-progress-value {
background-color: orange;
}
progress::-webkit-progress-bar {
background-color: cyan;
}

Related

BEM convention for naming multiple complex modifiers [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
i've been confused for finding the best way of naming multiple modifiers,
i know the basic rules of this methodology and i read the official BEM quick-start documentation ( bem.info/methodology/quick-start )
i have problem with naming modifiers when i have some modifiers in a block which one of these has some effects on another modifier ( in other word, a modifier in addition to modifying the main block, also is modifying another modifier of that block )
instead of explaining the problem i use a simple example for this situation, so please just tell me which one of this following examples is the correct and the best option:
Solution 1)
SCSS:
.btn {
font-size: 14px;
&--primary {
background: blue;
}
&--secondary {
background: black;
}
&--outline {
background: transparent;
}
&--outline#{&}--primary {
border: 1px solid blue;
}
&--outline#{&}--secondary {
border: 1px solid black;
}
}
Compiled CSS:
.btn {
font-size: 14px;
}
.btn--primary {
background: blue;
}
.btn--secondary {
background: black;
}
.btn--outline {
background: transparent;
}
.btn--outline.btn--primary {
border: 1px solid blue;
}
.btn--outline.btn--secondary {
border: 1px solid black;
}
Sample of usage in HTML:
<a href="#" class="btn btn--primary btn--outline>...</a>
Solution 2)
SCSS:
.btn {
font-size: 14px;
&--primary {
background: blue;
}
&--secondary {
background: black;
}
&--outline {
background: transparent;
}
&--outline#{&} {
&--primary {
border: 1px solid blue;
}
&--secondary {
border: 1px solid black;
}
}
}
Compiled CSS is same as solution 1
Sample of usage in HTML is also same as solution 1
Actually i just did a nesting in modifiers for prevent repeating the "outline",
Solution 3)
SCSS:
.btn {
font-size: 14px;
&--primary {
background: blue;
}
&--secondary {
background: black;
}
&--outline {
background: transparent;
&--primary {
border: 1px solid blue;
}
&--secondary {
border: 1px solid black;
}
}
}
Compiled CSS:
.btn {
font-size: 14px;
}
.btn--primary {
background: blue;
}
.btn--secondary {
background: black;
}
.btn--outline {
background: transparent;
}
.btn--outline--primary {
border: 1px solid blue;
}
.btn--outline--secondary {
border: 1px solid black;
}
Sample of usage in HTML:
...
Solution 4)
SCSS:
.btn {
font-size: 14px;
&--primary {
background: blue;
}
&--secondary {
background: black;
}
&--outline {
&--primary {
background: transparent;
border: 1px solid blue;
}
&--secondary {
background: transparent;
border: 1px solid black;
}
}
}
Compiled CSS:
.btn {
font-size: 14px;
}
.btn--primary {
background: blue;
}
.btn--secondary {
background: black;
}
.btn--outline--primary {
background: transparent;
border: 1px solid blue;
}
.btn--outline--secondary {
background: transparent;
border: 1px solid black;
}
Sample of usage in HTML:
...
As you see this solution is easier for usage in HTML, but we are duplicating same CSS property in each primary and secondary modifier ( in this case we are duplicating background: transparent; in other modifiers ), you may think it doesn't matter, but in real cases we may have lots of property which is duplicating in many places so definitely this solution will have important problems for the development of this component in the future
Solution 5)
SCSS:
.btn {
font-size: 14px;
&--primary {
background: blue;
&--outline {
background: transparent;
border: 1px solid blue;
}
}
&--secondary {
background: black;
&--outline {
background: transparent;
border: 1px solid black;
}
}
}
Compiled CSS:
.btn {
font-size: 14px;
}
.btn--primary {
background: blue;
}
.btn--primary--outline {
background: transparent;
border: 1px solid blue;
}
.btn--secondary {
background: black;
}
.btn--secondary--outline {
background: transparent;
border: 1px solid black;
}
Sample of usage in HTML:
...
We also have duplicated properties in this solution ( like the solution 4 )
So it doesn't have a good development structure and it will bother programmer in a large component
i just want to know which solution is the best choice, or if you have another solution for this problem please write base on this button example.
also i mention this point again:
I wrote that example in a very little scale of a real component, so any duplicating of properties or classes name may doesn't seem to care about in this example, but in the more complex cases in the real project it will be a serious problem for development of a component.
Chaining attribute selectors may seem a good fit for your special case.
let's say we have all the buttons containing a .btn at least.
This way you could both keep the logic for each modification case in a the dedicated css rule and also have the duplications to their minimum.
let's say you have a
<button class="btn--primary--outline"></button>
then you could probably write them css rules as follows:
[class^="btn"] {
font-size: 14px;
}
[class^="btn"][class*="--primary"] {
background: blue;
border-color: blue;
}
[class^="btn"][class*="--outline"] {
border: 1px solid;
}

In SASS, How to refer tag select?

In SASS's class selecter, I want to select parent's sibling.
.bw-textarea {
height: 150px;
padding: 10px;
overflow-y: auto;
background: white;
text-align: left;
width: 100%;
border: 1px solid #eeeeee;
font-size: 12px !important;
color: #666666;
// textarea:disabled & {
// background: #efefef;
// }
}
Compiled above sass code,
.bw-textarea textarea:disabled {
background: #efefef;
}
But I want to show result like this css code...
How to select like this in sass?
textarea.bw-textarea:disabled {
background: #efefef;
}
You gotta use #root in this case. It's pretty simple
This link will give a clear idea about this selector
.bw-textarea {
#at-root textarea#{&}:disabled{
background: cyan;
}
}
This will compile to
textarea.bw-textarea:disabled {
background: cyan;
}
See this PEN
This is what your looking for:
.bw-textarea {
height: 150px;
padding: 10px;
overflow-y: auto;
background: white;
text-align: left;
width: 100%;
border: 1px solid #eeeeee;
font-size: 12px !important;
color: #666666;
&:disabled {
background: #efefef;
}
}
Check out this SO answer for a lil more idea on the nested pseudo selectors
Sass parent selector and hover?
And of course check the sass docs
https://sass-lang.com/documentation/file.SASS_REFERENCE.html

Bubble up rules in SASS for variation / theme classes

How does one handle making "variation classes" in Sass? Example:
.bookshelf {
color: brown;
height: 100px;
.panel {
trimmed: no;
height: 10px;
}
.door {
height: 100px;
.knob {
shape: circle;
height: 10px;
}
}
}
You want to make a .bookshelf.small variation. Is there a way to write the variation code inside the main element using mixins or something that would "bubble up" the data?
.bookshelf {
color: brown;
height: 100px;
#include small-version {
height: 50px;
}
.panel {
trimmed: no;
height: 10px;
#include small-version {
height: 5px;
}
}
.door {
height: 100px;
#include small-version {
height: 50px;
}
.knob {
shape: circle;
height: 10px;
#include small-version {
height: 5px;
}
}
}
}
And the output of the mixin would be
.bookshelf.small {
height: 50px;
.panel {
height: 5px;
}
.door {
height: 50px;
.knob {
height: 5px;
}
}
Several things looked promising, such as the #at-root function and #content function, but neither would work for this scenario. I know if I write #media settings, they will bubble up. But I do not want this tied to a media query, I want this tied to a specific class (if .bookshelf also has the class small, apply these rules).
There is a small hack about it. But you should work with it really carefully. And it's not so good as you ask.
First of all, it prepends theme class to selector, so you can't use any element selectors. There is actually lot of selector helpers in docs but i didn't found any that could help with real parsing selector string.
Second it's not grouping out selectors. It inserts rules right where mixin were included. But it generates higher priority rules for your styles, so it could be a half a way solution.
You can dig for postcss parser or any other file post processing tool that could help you to separate your styles in a different files.
#mixin small-version {
#at-root .small#{&} {
#content;
}
}
.bookshelf {
color: brown;
height: 100px;
#include small-version {
height: 60px;
}
.panel {
trimmed: no;
height: 10px;
#include small-version {
height: 5px;
}
}
.door {
height: 100px;
.knob {
shape: circle;
height: 10px;
}
}
}
Gist link
You can qualify a selector by putting & to the right of the intended parent of the selector. Wrapping it in #{} allows you to place it directly beside that parent.
The #at-root rule causes everything proceeding it to be emitted at the root instead of using regular nesting.
If you use both, you can achieve what you are looking for.
.flashlight {
.light {
background: yellow;
#at-root .dead-battery#{&} {
background: transparent;
}
.daytime &{
background: transparent;
}
}
}
This would compile to:
.flashlight .light {
background: yellow;
}
.dead-battery.flashlight .light {
background: transparent;
}
.daytime .flashlight .light {
background: transparent;
}

Sass / Scss: Changing the order of nested psuedo selectors for :before and :hover in generated CSS?

Given the following Sass:
div.test {
display: inline-block;
background-color: #ffffff;
color: #000000;
&:before {
& {
&:hover {
border: 1px solid salmon;
}
}
width: 25px;
height: 25px;
content: "";
}
}
The resulting CSS compiles to:
div.test {
display: inline-block;
background-color: #ffffff;
color: #000000;
}
div.test:before {
width: 25px;
height: 25px;
content: "";
}
div.test:before:hover {
border: 1px solid salmon;
}
What I am attempting to do is generate div.test:hover:before (the current output is before:hover).
NOTE: I am able to generate the expected CSS by using the following Sass:
div.test {
display: inline-block;
background-color: #ffffff;
color: #000000;
&:hover {
&:before {
border: 1px solid salmon;
}
}
&:before {
width: 25px;
height: 25px;
content: "";
}
}
However I would like to know if it is possible using the first nested approach or some modification of it.
The goal was to avoid having to repeat &:before if there was such a way to do so using Sass syntax. I am also OK with knowing it isn't possible.
While initially the plan was to have '&' available in SassScript as a string that could be manipulated so that you could insert values wherever you wanted, those plans have been abandoned for 3.3 due to complication. Unfortunately you'll have to wait a while to be able to do this. At the moment '&' is immutable and just means "whatever the selector chain up to this point is".
EDIT (2020.02.15):
it is now technically possible to achieve this with recent versions of dart-sass:
#use "sass:selector";
#mixin unify-parent($child) {
#at-root #{selector.unify(&, $child)} {
#content;
}
}
div.test {
display: inline-block;
background-color: #ffffff;
color: #000000;
&:before {
width: 25px;
height: 25px;
content: "";
#include unify-parent(":hover") {
border: 1px solid salmon;
}
}
}
Sources:
https://sass-lang.com/blog/the-module-system-is-launched
https://sass-lang.com/documentation/style-rules/parent-selector#advanced-nesting

Custom directives within scss files? Perhaps for a new pseudo class?

Is it be possible to use some sort of #directive creation syntax, similar to creating #mixins? Secondly, is it possible to create a SASS-only pseudo class?
I'd like to declare my own SASS directive,although I'd prefer not to have to force my teammates to install an extra ruby gem to use it so I'd want to store it in a scss partial. I do understand that they are orders of levels in complexity, so perhaps it just isn't possible.
In addition to perhaps creating a new scss-only pseudo class (such as :parent, :clicked, :unchecked, etc) I'd be interested in a custom-made directive that assists with using checkboxes to direct css animations ("css checkbox hack"). Here is my scss pseudocode to generalize what I'm trying to do:
// this code monitors when a checkbox (#someinput) is checked,
// then applies style to div #target div. Basically an 'onClick' event in scss.
body {
#wrapper {
#targetdiv {
#spotcheck(#someinput) { #
color: red; border: 2px solid blue; # <-- move this ...
} #
color: blue; border: 0;
#someinput {
width: 20px; height: 20px;
}
}
}
}
// ... the above scss should be converted to this pre-compiled state, also scss
body {
#someinput:checked ~ #targetdiv { #
color: red; border: 2px solid blue; # <-- ..to here. it needs to be
} # above the #targetdiv
#wrapper {
#targetdiv {
color: blue; border: 0;
#someinput {
width: 20px; height: 20px;
}
}
}
}
Make your selectors only as specific as they absolutely need to be and no more. A mixin would only be more verbose with no real benefit.
#targetdiv {
color: blue; border: 0;
#someinput:checked ~ & {
color: red; border: 2px solid blue;
}
}
#someinput {
width: 20px; height: 20px;
}
Output:
#targetdiv {
color: blue;
border: 0;
}
#someinput:checked ~ #targetdiv {
color: red;
border: 2px solid blue;
}
#someinput {
width: 20px;
height: 20px;
}
Alternately, this would give the same result with the ability to overqualify as much as you want:
#targetdiv {
color: blue; border: 0;
}
#someinput {
width: 20px; height: 20px;
~ #targetdiv {
color: red; border: 2px solid blue;
}
}

Resources