Using sass selector functions inside a reusable function - css

I'm looking at solving a specific problem with SASS - I want to append a pseudo-class to the selectors of a lot of old legacy styles, and ideally I'd like to do it in a DRY way.
I saw that sass enables you to append to a selectors using the selector-append function - however, I can't seem to figure out a way to write some sort of reusable function in sass that calls such a function to modify a selector.
Here's what I've tried:
#function optOut($selector) {
#return selector-append($selector, ":not(:where(*.opt-out))");
}
optOut(div) {
color: black;
}
But, depending on the sass compiler I use, it either does not compile or just compiles to:
optOut(div) {
color: black;
}
I'd like it to compile to this:
div:not(:where(*.opt-out)) {
color: black;
}
Any help is greatly appreciated - thank you so much for your time and knowledge.

You just need to interpolate the return value of the function like so:
#function optOut($selector) {
#return selector-append($selector, ":not(:where(*.opt-out))");
}
#{optOut(div)} {
color: black;
}

Related

How to combine LESS color functions and CSS Variables?

In my project I have a CSS custom variables like this:
:root {
--primary-color: #e04c4c;
--secondary-color: #2c2c5e;
--text-color: #d67900;
}
In my LESS files I have used LESS color functions to get more colors base on its primary and secondary. This is how its look like:
.component1 {
background: darken(--primary-color, 10%);
}
.component2 {
background: lighten(--secondary-color, 5%);
}
But when I compile this, it gives an error like this?
// Undefined_methodError: error evaluating function darken: //
Object # has no method 'toHSL'
When googling I found a solution for SASS, but not for LESS.
Can anybody tell me is there any possible workaround for this particular case?
Thank you.

extend from class name in another file sass

So I'm currently doing some styling, following the BEM standard.
An example of what I'm doing could be this:
.block{
&__element {
}
}
what i would like to do is this:
// file a
.block {
...
}
-
// file b
// add magic to reference the `block`class in file a
&__elelemnt {
...
}
What I'm currently doing:
// file a
.block {
...
}
-
// file b
.block__elelemnt {
...
}
(manually adding the block part to the name)
Is there any way to reference this in a smarter way?
Thanks in advance
You can have this file structure:
block-1/
--block-1.scss
--element-1.scss
--element-2.scss
block-2/
--block-1.scss
--element-1.scss
--element-2.scss
And import elements files info block files.
block.scss:
.block {
color: red;
#import "element-1.scss";
#import "element-2.scss";
}
element-1.scss:
&__element-1 {
color: green;
}
Compiles to:
.block {
color: red;
&__element-1 {
color: green;
}
}
This is perhaps the best you can do.
$namespace: "block";
.#{$namespace}-myClass {
...
}
OUTPUT
.block-myClass {
...
}
You can keep a variable $namespace at the top of your file or in a different file and import it. The advantage of using a variable is you can update it once and all your references will be updated.
SASS is all about DRY.
As in, if you want to modify anything, you should be able to modify it from one single place. If you need anything available across multiple files, consider defining its value in a _vars file and including it everywhere you need it. Also note this has nothing to do with code shortness, but with code maintainability and flexibility.
In fact, even if you do get to write more code (which, in practice, doesn't happen), the advantage of DRY far outweighs it.
Here's how it should be done:
/* _vars.scss: */
$block:block;
/* a.scss: */
#import _vars;
.#{$block} {
...
}
/* b.scss: */
#import _vars;
.#{$block}__element {
...
}
Now, whenever you need to change block value, you can do it from one place: _vars.scss.
But, in practice, most people use the initial technique (nesting):
.block {
...
&__element {
...
}
}
Chances are .block and .block__element are related and, overall, it makes more sense to put them in same file. As your app grows in complexity, you'll find it harder to keep track of your code if you over-complicate it.

Dynamic Variable Names in LESS CSS

I have been trying this for a while, looking at other answers, but to no avail. Hopefully someone can help me.
I am trying to generate some dynamic variable names within a mixin.
The variables are already defined:
#horizontal-default-color: #fff;
#horizontal-inverse-color: #000;
etc..
The mixin I want would be something like this:
.horizontal-variant(#variant) {
color: #{horizontal-#{#variant}-color}
}
And the result I am expecting, when called:
.horizontal-default{
.horizontal-variant(~"default");
}
.horizontal-inverse{
.horizontal-variant(~"inverse");
}
is
.horizontal-default {color: #fff}
.horizontal-inverse {color: #000}
Unfortunately I run into errors every time.
I know this can be done, I have seen it being used in Font Awesome LESS where #{fa-css-prefix} is defined in variables. I am just having trouble transporting the same solution in my project.
You can try testing the code at http://lesstester.com/
You can use Variable Names. And I've tested the code at http://lesstester.com/, it works.
#horizontal-default-color: #fff;
#horizontal-inverse-color: #000;
.horizontal-variant(#variant) {
#color: "horizontal-#{variant}-color";
color: ##color;
}
.horizontal-default{
.horizontal-variant(default);
}
.horizontal-inverse{
.horizontal-variant(inverse);
}

How to override mixins in LESS CSS 1.4+

I've been using what I thought was a very elegant pattern for defining the styles of reusable components/widgets, using LESS. It works beautifully in LESS 1.3-, but after upgrading recently, my whole library is broken. Does anyone know a way to accomplish something like this in 1.4+?
Here's a very simple example of a component:
#componentName {
.loadMixins(){
.text() {}
.header() {}
}
.apply(){
> h3 {
// markup-specific styles
padding: 3px;
margin-bottom: 0;
// custom styles
.header();
}
> div.body, > div.popup p {
color: red;
// custom styles
.text()
}
}
}
And here's how it would be used:
.coolWidget {
#componentName.loadMixins();
// override mixins here
.text(){
color: green;
}
#componentName.apply();
}
This keeps all the markup-dependent styles abstracted from the user. I could completely change my markup and the user's styles would still work. According to the less.js changelog, 1.4.0 Beta 1 has a line "variables in mixins no longer 'leak' into their calling scope"
Is there any way around this?
Strictly speaking nested variables and mixins are still expanded into calling scope unless this scope already has those names defined.
Your example above results in a error:
SyntaxError: .header is undefined...
and it's expected as no .header() is actually defined within the .coolWidget (or anywhere else).
This can be fixed by providing "default" definitions for .text and .header somewhere inside #componentName.
For example if you modify .loadMixins() to:
.loadMixins() {
.text();
.header();
// default properties in case a caller does not provide its own:
.text() {}
.header() {}
}
then the example compiles OK and all text/header properties are overridden as expected.
I can imagine how your library may become broken because of new scope rules but this particular example you gave above does not illustrate the problem.

Declare a global CSS property ? Is this possible?

I have a very wierd question, I dont know wether if its possible in css or not
Suppose I have say 3 different css classes as shown below, as you can see I have a common property of all these classes, I want to declare this color somewhere else and pass a reference to it here, so if next time I want to change the color I can simply change at one place rather than changing in all the 5 classes.
I know that you can use body{}, or a wrapper for this but that would affect the colors of the entire site right ? Is there a way to do this ?
Is this even possible ?
.abc {
color:red;
}
.abc2 {
color:red;
}
.abc3 {
color:red;
}
.abc4 {
color:red;
}
.abc5 {
color:red;
}
The bad news: you can't do it in CSS.
The good news: you can write in a meta-CSS language like LESS, which then processes a LESS file to pure CSS. This is called a "mixin".
In LESS:
#errorColor: red;
.error-color {
color: #errorColor;
}
#error-1 {
.error-color;
}
.all-errors {
.error-color;
}
More info: http://lesscss.org/#-mixins
if you want to declare all of them at a time, you can use:
.abc, .abc2, .abc3, .abc4, .abc5 {
color:red;
}
Or you can declare an additional class & add to all the .abc, .abc2.... & make its color:red;.
This can not be done with CSS, but that is still a very popular thing to do by using a CSS preprocessor such as LESS, SASS, SCSS, or Stylus.
A preprocessor will let you define a variable (say $red = #F00). It will replace the variable in your CSS document with the variable value for you, allowing you to write very DRY and module CSS.
This functionality is referred to as "CSS variables", which is part of the future spec, but not yet implemented on any browsers.
For now, the best way to do this in pure CSS is to declare an additional class for the desired "global", and then add that class to all relevant items.
.abc_global { color: red; }
.abc1 { /* additional styling */ }
.abc2 { /* additional styling */ }
<div class="abc1 abc_global"></div>
<div class="abc2 abc_global"></div>
With LESS
You are able to define that red color once:
.myRedColor {
color:red;
}
Now you can call that red on any CSS styles. Even NESTED styles! It's a wicked tool!
.abc1 {
.myRedColor;
}
.abc2 {
.myRedColor;
}
.abc3 {
.myRedColor;
}
.abc4 {
.myRedColor;
}
NESTED EXAMPLE:
.abc {
.itsEasyAsOneTwoThree{
.myRedColor;
}
}
Now all of our "itsEasyAsOneTwoThree" classes that are properly nested inside of an "abc" class will be assigned the red style. No more remembering those long #867530 color codes :) How cool is that?!
You can also use PostCSS with the plugin postcss-preset-env and support custom properties/variables, then use the :root selector to add global css variables.
:root {
--color-gray: #333333;
--color-white: #ffffff;
--color-black: #000000;
}

Resources