Call a function in Compass/SASS - function

I want to create a function in SASS that generates different classes.
Something like this
#function test($class-name) {
#for $i from 1 through $tot-class {
.#{$class-name}-#{$i} {
//some rules
}
}
}
but i can't figure how to call this function.
I've tried with
#test(red);
or
test(red);
but it doesn't seem to work.
Which is the right way?

The main problem here is that you don't actually want to use a function, you want a mixin. The difference is that functions don't contain any CSS rules - they simply return a value (which you can assign to a variable or use in a CSS property declaration). Mixins, on the other hand, have no return value and can contain full-blown CSS rules to be added when that mixin is included into the SASS document. Here's what your example would look like as a mixin:
#mixin test($class-name) {
#for $i from 1 through $tot-class {
.#{$class-name}-#{$i} {
//some rules
}
}
}
You'd then include the mixin later by using:
#include test(red);

Related

Mixins exists check in scss which is imported dynamically is not working

For the implementation of RTL and LTR styles using scss I created two scss files _ltr.scss and _rtl.scss and based on the country selection of user in the application, I dynamically import the corresponding stylesheet.
_ltr.scss
$start-direction: left;
#mixin paddingStart($val) {
padding-#{$start-direction}: $val;
}
_rtl.scss
$start-direction: right;
#mixin paddingStart($val) {
padding-#{$start-direction}: $val;
}
main.js //where country switch happening
const root = document.documentElement;
root.classList.remove('rtl');
root.classList.add('ltr');
if (USER COUNTRY DIR VALUE === 'RTL') {
root.classList.remove('ltr');
root.classList.add('rtl');
}
_main.scss
html.ltr {
#import '_ltr.scss';
}
html.rtl {
#import '_rtl.scss';
}
#if mixin-exists(paddingStart) { //NOT WORKING
#include paddingStart(10px)
}
This is how I dynamically import the scss, and it works correctly. But the mixin exists if statement is always failing. Is there any ways to make the mixin work as expected in SCSS? Or any options to implement this LTR and RTL style better way. Because in my case user can change the country and based on his selection I have to load the styles dynamically.
SCSS is compiled before arriving to the browser and deployed, Javascript is run after it arrived to the browser. You are trying to modify SCSS with Javascript something that doesn't really exist.
What you need is to have both rtl.scss ltr.scss loaded at the same time, and apply the rules depending on the direction.
For rtl the easier way is to create a mixin where you can set/modify rules if the site is in rtl.
#mixin rtl {
body:dir(rtl) &{
#content;
}
}
You shouldn't type .scss when importing files. https://sass-lang.com/documentation/at-rules/import#importing-css
html.ltr {
#import 'ltr';
}
html.rtl {
#import 'rtl';
}

How do I pass an HTML `data-` string attribute into a SCSS mixin via attr()?

I am trying to set up a color scheme in SCSS where I can have the following HTML:
<div class="swatch" data-bg="green">...</div>
I have a SCSS mixin defined as such:
#function color($key: 'black') {
#return map-get($colors, $key);
}
So, if I pass it background-color: color('green'), it will look at the $colors: ( ... ) map, see 'green': #009900, and return background-color: #009900; as the CSS.
The problem comes when I try to pass the data-bg attribute value into the color() SCSS mixin, like so:
.swatch[data-bg] {
background-color: color(attr(data-bg));
}
This doesn't work. I would expect it to parse the value as such:
color(attr(data-bg)) → color('green') → #009900
However, SCSS won't even render that background-color line in the CSS at all.
I have a Codepen where you can see what I'm trying to go for. It's the "Brown" color swatch here: https://codepen.io/rbrum/pen/axZLxw
Any help would be greatly appreciated.
For anyone else who happens across this question, here is how I ended up resolving my issue.
Instead of relying on data- attributes, I just relied on class names instead. Whenever I want an element with a certain background color, for instance, I use a class name like .bg-amber or .bg-purple. My colors are defined as such:
$colors: (
'black': #000000,
'white': #FFFFFF,
// ...
'amber': #FFBF00,
'purple': #800080,
// ...
);
To make it easier to access a color, I have defined a function that calls any color by name:
#function c($key: 'black') {
#return map-get($colors, $key);
}
I then define a mixin that, given a color name, will apply it as the background color. I can also pass it a prefix that is used in the CSS attribute.
#mixin bg($color-name, $prefix: '') {
.#{$prefix}#{$color-name} {
background-color: c($color-name);
}
}
If I wanted to use it in a one-off situation, I would use it like so:
#include bg('amber', 'bg-');
...which would generate the following:
.bg-amber {
background-color: #FFBF00;
}
Finally, I use an #each loop to do this for all of my colors:
#each $color-name, $color-val in $colors {
#include bg($color-name, 'bg-');
}
I can also define a "foreground" version:
#mixin fg($color-name, $prefix: '') {
.#{$prefix}#{$color-name} {
color: c($color-name);
}
}
And then I can use it in the #each loop right below the bg() usage:
#each $color-name, $color-val in $colors {
#include bg($color-name, 'bg-');
#include fg($color-name, 'txt-');
}
It can also be extended for things like border colors, box shadows, and more.

How to change css style based on value

I have a boolean array that I am displaying in a razor foreach loop. Within the loop I am displaying the different values within the array. Is it possible,if so how, to change the css based on the value it is displaying?
For example
if (#status == true) THEN color = green; if (#status == false) THEN color = red.
If I understand your question correctly, you could add a data-attribute to the HTML element and alter the value (for example with Javascript) to/from "true/false" and use that in your CSS like so:
<element data-status="true">Content</element>
<element data-status="false">Content</element>
[data-status="true"] {
color: green;
}
[data-status="false"] {
color: red;
}
$('.test').each(function() {
if(parseInt($(this).css('font-size')) > 16) {
$(this).css('color', 'green');
}
});
.test {
font-size: 18px;
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p class="test">Javascript manipulation: Green when largen than 16px</p>
I came across this question having the same problem, however I have implemented another solution, using c#/razor/css and no javascript. Someone might like this better.
First: define the possible values as an enumeration:
public class enum MyRateTyp{
Level1,
Level2,
Level3
}
Second:
Find a place where, given the number on which the style will be based, the conversion will take place. In my case I added an extension method to the int type.
public MyRate Evaluate(this int i)
{
MyRate answer = MyRate.Level1;
if(i<50)
{
answer = MyRate.Level1;
}
.
//All if statements here
.
if (i>100)
{
answer = MyRate.Level3;
}
return answer;
}
Third: On your .css file, define the style for each possible value, like so:
.Level1{
/*Style here for level 1*/
}
.Level2{
/* Style here for level 2*/
}
/*
Other Styles here
*/
Finally On the Razor page, assign the extension method to the css class of the element you want to change the style based on the value.
For example.
The level is <p class="#(myInt_variable.Evaluate())"> #(myInt_Variable) </p>
It is possible to change the color by putting an event on the box. This is done in javascript "AddEventListener"

select all child elements except H1 and H2? [duplicate]

I'm trying to select input elements of all types except radio and checkbox.
Many people have shown that you can put multiple arguments in :not, but using type doesn't seem to work anyway I try it.
form input:not([type="radio"], [type="checkbox"]) {
/* css here */
}
Any ideas?
Why :not just use two :not:
input:not([type="radio"]):not([type="checkbox"])
Yes, it is intentional
If you're using SASS in your project, I've built this mixin to make it work the way we all want it to:
#mixin not($ignorList...) {
//if only a single value given
#if (length($ignorList) == 1){
//it is probably a list variable so set ignore list to the variable
$ignorList: nth($ignorList,1);
}
//set up an empty $notOutput variable
$notOutput: '';
//for each item in the list
#each $not in $ignorList {
//generate a :not([ignored_item]) segment for each item in the ignore list and put them back to back
$notOutput: $notOutput + ':not(#{$not})';
}
//output the full :not() rule including all ignored items
&#{$notOutput} {
#content;
}
}
it can be used in 2 ways:
Option 1: list the ignored items inline
input {
/*non-ignored styling goes here*/
#include not('[type="radio"]','[type="checkbox"]'){
/*ignored styling goes here*/
}
}
Option 2: list the ignored items in a variable first
$ignoredItems:
'[type="radio"]',
'[type="checkbox"]'
;
input {
/*non-ignored styling goes here*/
#include not($ignoredItems){
/*ignored styling goes here*/
}
}
Outputted CSS for either option
input {
/*non-ignored styling goes here*/
}
input:not([type="radio"]):not([type="checkbox"]) {
/*ignored styling goes here*/
}
Starting from CSS Selectors 4 using multiple arguments in the :not selector becomes possible (see here).
In CSS3, the :not selector only allows 1 selector as an argument. In level 4 selectors, it can take a selector list as an argument.
Example:
/* In this example, all p elements will be red, except for
the first child and the ones with the class special. */
p:not(:first-child, .special) {
color: red;
}
Unfortunately, browser support is somewhat new.
I was having some trouble with this, and the "X:not():not()" method wasn't working for me.
I ended up resorting to this strategy:
INPUT {
/* styles */
}
INPUT[type="radio"], INPUT[type="checkbox"] {
/* styles that reset previous styles */
}
It's not nearly as fun, but it worked for me when :not() was being pugnacious. It's not ideal, but it's solid.
If you install the "cssnext" Post CSS plugin, then you can safely start using the syntax that you want to use right now.
Using cssnext will turn this:
input:not([type="radio"], [type="checkbox"]) {
/* css here */
}
Into this:
input:not([type="radio"]):not([type="checkbox"]) {
/* css here */
}
https://cssnext.github.io/features/#not-pseudo-class

LESScss if condition when variable is not empty

I am trying to put font family for a div if the variable is not equal to null.
my less code is
div.content {
& when (isstring(#contentFont)) {
font-family: #contentFont;
}
}
the output that I get from css is
div.content when (isstring(#contentFont)) {
font-family: Abel;
}
my problem is, the style is not applying for the div.content, not sure what i am doing wrong. Any help would be greatly appreciated.
As discussed in the comments, you're using version 0.4.0 of lessphp – which doesn't seem to support the shorthand guard (when) syntax that you're trying to use.
It looks like it does support guards on mixins, however.
Try splitting your code into a mixin and a usage of this mixin, like this:
/* the mixin */
.fontIfString(#font) when (isstring(#font)) {
font-family: #font;
}
/* usage */
#contentFont: "hello";
div.content {
.fontIfString(#contentFont);
}