SCSS: Send Attribute and Value to Function - function

Note:
I'm new to web development and object oriented programming. I am brand new to SCSS and haven't yet grasped a solid understanding of the syntax. I have a basic understanding of how to use functions in SCSS.
Let me start off by defining the result I want to achieve.
_body.scss
body {
background-color: red;
}
Now I know if I wanted to obtain this result in Javascript I could:
Option 1: write a string of HTML code and replace the existing html tag.
Not going to code this, as this is a messy way of writing Javascript, but essentially using document.write() method.
Option 2: use the "setAttribute()" method
// assuming <head> and <body> are the only tags within <html>
var bodyTag = document.firstElementChild.lastElementChild;
bodyTag.setAttribute( "bgcolor", "red" );
I know there are additional ways to do this in Javascript, but for this example, I will focus on these two.
So I want to create a SCSS function that can return both the attribute and the value.
_body.scss ( Pseudocode string example )
#function makeAttribute( $attribute, $value )
{
#return $attribute + ":" + $value + ";";
}
body {
makeAttribute( background-color, red );
}
I have yet to find a built in function that addresses this ( similar to the "setAttribute()" method in Javascript ), or the string example above.
I know that functions can take: number, string, bool, color, list, map or null; but what I don't know is if an attribute fits into any of these value types ( for instance: string ).
I feel as if the article: Bringing Configuration Objects To Sass may be explaining what I am trying to do, but I'm having difficulty understanding this article ( so it may not be an explanation to a solution ).
My end goal is to create a function that would write the following css. I did not mention the browser support previously as it adds another layer of complexity that may or may not be easily explained.
body {
background-color: red;
-o-background-color: red;
-ms-background-color: red;
-moz-background-color: red;
-webkit-background-color: red;
}

i don't know if this have to be a function, i found it more logic use a mixin instead:
// Option 1
#mixin makeRule($value: red, $property: background-color) {
#{$property}: $value;
}
// Option 2:
#mixin makeRuleWithPrefixes($value: red, $property: background-color) {
#{-ms- + $property}: $value;
#{-o- + $property}: $value;
#{-moz- + $property}: $value;
#{-webkit- + $property}: $value;
#{$property}: $value;
}
/////////
body {
#include makeRule;
}
article {
#include makeRule(black);
}
p {
#include makeRule(2px solid blue, border)
}
span {
#include makeRuleWithPrefixes;
}
i changed the name, because is no right say - makeAttribute, when you are creating a cssRule ( selector + property name + property value ), well this is up to you ;)
ok the first,you need interpolation to use a variable as a property name.
The value is the first argument, so now you can use the default property, and just pass different values ( like the article :) )
or you can now set all the properties you want it, just pass the property as the second value ( like p )
body {
background-color: red;
}
article {
background-color: black;
}
p {
border: 2px solid blue;
}
span {
-ms-background-color: red;
-o-background-color: red;
-moz-background-color: red;
-webkit-background-color: red;
background-color: red;
}
I made the option two, because you ask it but i warn you, this is not a good approach. You could use a build tool ( webpack, gulp, grunt.. whatever ) than use a autoprefixer package that do this prefix automatically, this way is a pain because you have to be updating the #mixin eventually.

Related

Is possible create a css class name with numbers "from-to"?

I need to have 3 classes as follow:
.class-4, .class-5, .class-6 {
color: pink;
}
And it works perfectly.
Let's say I need the same but for 100:
.class-4, .class-5, .... .class-100 {
color: pink;
}
Is there anything similar to this or any other way to do this which I can use.
.class->3<101 {
color: pink;
}
To get the same result without writing 97 times the class and the comma?
There is nothing in pure CSS which will do this, but you could use JavaScript to create a stylesheet for you which has all that tedious repetition created automatically.
In this snippet you say what the ends of the class ranges are and what styling is to be put in each of the ranges.
If there is a range which you don't want to alter then you still need to include it but make its styles string just an empty string.
The snippet runs through each of the ranges creating the relevant style sheet entries and puts them in a style element in the head element of the document.
A few fairly random divs are shown here just to test that we are hitting the right ranges.
const rangeEnds = [4, 20, 35, 41, 48, 100];
const styles = ['color: pink;', 'color: red; background-color: black;', 'color: green;', 'color: yellow;', 'color: blue;', 'color: black; background: pink;'];
let lastRangeEnd = 0;
const styleEl = document.createElement('style');
for (let i = 0; i < rangeEnds.length; i++) {
for (let j = lastRangeEnd + 1; j < rangeEnds[i]; j++) {
styleEl.innerHTML += '.class-' + j + ',';
}
styleEl.innerHTML += '.class-' + rangeEnds[i] + '{' + styles[i] + '}';
lastRangeEnd = rangeEnds[i];
}
document.querySelector('head').append(styleEl);
<!doctype html>
<html>
<head>
<title>Classes</title>
</head>
<body>
<div class="class-1">ABCD</div>
<div class="class-19">ABCD</div>
<div class="class-21">ABCD</div>
<div class="class-40">ABCD</div>
<div class="class-41">ABCD</div>
<div class="class-48">ABCD</div>
<div class="class-100">ABCD</div>
</body>
If all elements will have the same property which is {color:pink}
You can create only one class (lets call it .pink)
.pink {
color: pink;
}
and then you can simply give your elements the .pink class.
One of class attribute's main purpose is to define a shared style reference name. It is rather not a very good practice to want to reference multiple class references and let them share the same styling.
The best way to get around this is to have a common class attribute name YourClassName. This way, any element you want the styling applied to can have that class appended to its class attribute through element.classList.add(YourClassName) with JS. And, that would solve all the hussle of having to worry about putting multiple classe names and I cannot think of any 1 situation that would force you to declare each element class separated by commas provided that they are to receive the same styling.
The OP asks if it’s possible to have a ‘number range’ (array) at the end of CSS classes that shares the same name, but ending on 1, 2, 3, etc.
As #zer00ne pointed out; You can target multiple classes with one "class". When defining your class selector - leave out the numbers, but make the class name unique.
So, if the class names are i.e. my-row-class-1, my-row-class-2, etc., write the selector like this;
[class^="my-row-class-"] {
color: pink;
}
Pro tip: Instead of using class^= selector, it's possible to do this for id^= as well - and more. Check out the MDN web docs for more info.

Random background image for each class instance

I have a sass function which returns a random url from a given set of urls as follows:
#function randomUrl(){
$images: (
"/images/watermarks/area-watermark.png",
"/images/watermarks/bar-watermark.png",
"/images/watermarks/line-watermark.png",
$img: nth($images, random(length($images)));
#return $img;
}
and i am assigning it to a class as follows:
.myClass{
background-image: url(randomUrl());
}
What i want now is to get a random image FOR EACH class instance, i.e, if i have 10 divs with class "myClass" in my HTML, i want the background images of each div to be different. My approach till now just gives me one random image which appears in all the divs everytime i compile.
The random() function does exactly what it sounds like: it generates a random number between 2 specified numbers. There is no guarantee that the numbers will be different each time the function is called because that's not how random works.
What you need is a way to shuffle your list, but there is no such function to do that in the Sass standard library. There are a couple of 3rd party libraries that do:
https://github.com/at-import/SassyLists (sl-shuffle)
https://github.com/mknadler/randomize.scss (shuffle)
The implementation in both libraries is nearly identical (this one was lifted from randomize.scss):
#function shuffle($list) {
$list-length: length($list);
#while($list-length > 0) {
$rand: random($list-length);
$temp: nth($list, $rand);
$list: set-nth($list, $rand, nth($list, $list-length));
$list: set-nth($list, $list-length, $temp);
$list-length: $list-length - 1;
}
#return $list;
}
If you're intentionally avoiding iterating over a list, you could use it like this:
#import "SassyLists";
$last-pos: 0;
$images: sl-shuffle(
"/images/watermarks/area-watermark.png"
"/images/watermarks/bar-watermark.png"
"/images/watermarks/line-watermark.png");
#function randomUrl(){
$last-pos: if($last-pos == length($images), 1, $last-pos + 1) !global;
#return nth($images, $last-pos);
}
.myClass {
background-image: url(randomUrl());
}
.myClass {
background-image: url(randomUrl());
}
.myClass {
background-image: url(randomUrl());
}
Output:
.myClass {
background-image: url("/images/watermarks/line-watermark.png");
}
.myClass {
background-image: url("/images/watermarks/area-watermark.png");
}
.myClass {
background-image: url("/images/watermarks/bar-watermark.png");
}
Though I recommend just using iteration instead and cut out the use of the function all together:
#import "SassyLists";
$images: sl-shuffle(
"/images/watermarks/area-watermark.png"
"/images/watermarks/bar-watermark.png"
"/images/watermarks/line-watermark.png");
#for $i from 1 through length($images) {
.myClass-#{$i} {
background-image: url(nth($images, $i));
}
}
http://sassmeister.com/gist/d0c65d02be52aa31f836

Jade: Best practice with classes and ids

I've searched for a while now, but I couldn't find an answer.
To create a div container with a class or id in Jade you can write:
.foo
#bar
or
div.foo
div#bar
Another thing is multiple classes:
div.foo.bar
or
div(class="foo bar")
What's best practice or is it just personal preference?
It is just a shorthand notation. Nothing wrong with it, just more readable for users who are unfamiliar with the shorter syntax to implicitly show that you are creating a div.
In some cases, using a shorthand syntax however causes the interpreter to perform better, because it works a bit different under the hood.
I'm not familiar with how Jade works, but maybe using just the dot notation saves some work behind the scenes, whilst using the more explicit instructions takes more time to parse.
Same as something similar in css:
border-style: solid;
border-width: 1px;
border-color: red;
/* shorthand */
border: 1px solid red;
Or javascript:
var foo;
if (true){
foo = "bar";
} else {
foo = "not bar";
}
// shorthand
var foo = true ? "bar" : "not bar";
var x = x + 1;
// shorthand, and might uses the processor or engine differently
var x += 1;

Why won't this LESS css sizing mixin compile?

I'm trying to create a mixin that'll take two parameters and output sizing in px and rem. This is the code:
.sizing (#cssProperty; #sizeValue) {
#cssProperty: ((#sizeValue * #basefont) * 1px);
#cssProperty: (#sizeValue * 1rem);
}
Usage would be like:
h2 {
.sizing(font-size; 1)
}
Which should output (depending on what basefont size is defined):
h2 {
font-size: 12px;
font-size: 1rem;
}
But simpLESS won't compile it, and says there's an error in these two lines:
.sizing (#cssProperty; #sizeValue) {
.sizing(font-size; 1);
What am I doing wrong? Is it because of the variable property names?
Just noticed that you are trying to use variables as property names instead values which is not supported by less.
There is a hack highlighted in this answer as workaround:
How to pass a property name as an argument to a mixin in less
.mixin(#prop, #value) {
Ignore: ~"a;#{prop}:#{value}";
}
LESS does not allow to use a variable as a CSS property name.
In your code above #cssProperty: ((#sizeValue * #basefont) * 1px); is actually a definition of the new #cssProperty variable and not a CSS property: value statement, hence it produces no CSS output.
There's a workaround for what you want to achieve though, see 14868042, 18558368 etc...

Can I use a variable for a function name?

I'm trying to loop through a list which automates several functions. Unfortunately the function is not evaluated.
For example:
$colors:
red,
blue,
green;
#each $color in $colors{
.color-#{$color} {
value: $color(#F15258);
}
}
(I've simplified my example code to make it easier to illustrate).
Unfortunately this just outputs the value of $key and the color #F15258.
ie:
value: red #F15258;
Can I get SASS to pass in the variable as the function name so it actually evaluates `red(#F15258)?
It should output:
value: 241;
Any thoughts?
As of Sass 3.3 you can do this using the call() function:
$colors:
'red',
'blue',
'green';
#each $color in $colors{
.color-#{$color} {
value: call($color, #F15258);
}
}
Output:
.color-red {
value: 241;
}
.color-blue {
value: 88;
}
.color-green {
value: 82;
}
Note that your variables must be a string: red is a Color while 'red' is a String.
SASS does not allow dynamic names, and that's a good thing.
To use a dynamic name, you'll have to use a template to generate your SASS prior to compiling it. See how Compass does it: https://stackoverflow.com/a/16129685/901944
This increases the complexity of your project greatly and i strongly advise against.
Instead, use a function that accepts the name as a parameter:
#function parse-color($color) {
// Do whatever you want here
}
.color-red {
color: parse-color(red);
}
Note that instead of hardcoding the second color you can have it as an argument with a default value:
#function parse-color($first-color,
$second-color: #F15258) {
// Do whatever you want here
// For example:
#return mix($first-color, $second-color);
}
$colors:
red,
blue,
green;
#each $color in $colors{
.color-#{$color} {
color: parse-color($color);
}
}
See a demo: http://sassbin.com/gist/6193779/
The variable with multiple values are called as lists in sass.
so,
you can make a list like:-
$colors: red blue green; //list of colors
#each $color in $colors{
.color-#{$color} {
color: ($color);
}
}