We know the advantages of using CSS4 variables but what if we need to get these values from a SASS function like so?:
:root {
--gap-l: toRem(10);
}
toRem is a Sass function that I call to get the sizes dynamically:
$fontSize: 16;
#function toRem($val) {
#return $val / $fontSize * 1.6 + 0rem;
}
This won't fail but won't work either. To have this working we can just have the value directly on --gap-l or keep using SASS vars.
If I try something like --gap-l: #{toRem(10)}; this is the error I get:
It doesn't call the SASS function
You can definitely do that: what you're missing is simply using string interpolation, i.e.:
:root {
--gap-l: #{toRem(10)};
}
The reason is highlighted in their "breaking changes" documentation with regards to CSS variables:
To provide maximum compatibility with plain CSS, more recent versions of Sass require SassScript expressions in custom property values to be written within interpolation. Interpolation will also work for older Sass versions, and so is recommended for all stylesheets.
Try this --gap-l: #{toRem(10)};, the #{} syntax is called interpolation. In the experience of heading bugs myself, when you want to use a SASS expression's raw value along with normal CSS, if you can't use the concise syntax like just toRem(10), try adding interpolation to see if it works.
Another example:
$padding: 5px;
.element {
width: calc(100% - $padding); // will not work, it must be:
width: calc(100% - #{$padding});
}
Here is the code with the updated question: https://jsfiddle.net/bcw763en/.
Notice that if you put :root above the #function, it'll not work.
Related
In SASS my Calculation looks like calc(50% - 375px); But when it compiles the CSS output looks like that: calc(-325%), which is obviously not what I had in mind.
How can I force SASS to not do the maths (50% - 375px)?
Thank you for your help!
Use the SASS interpolation like this #{'calc(50% - 375px)'};
Using the unquote function worked for me:
.selector {
height: unquote("calc(50% - 375px)");
}
We still ran into compile issue using escaped strings, but using capitalized Min worked for us.
Ref: https://github.com/sass/sass/issues/2849#issuecomment-922070076
Use escaped string: ~"(50% - 375px)";
I have been going through the Stylus docs and looking at examples, but I can't seem to get a simple calculation to work when using a variable. For example:
Works
margin-right: (1200 / 2)px;
Doesn't work
$siteWidth = 1200;
margin-right: ($siteWidth / 2)px;
I've seen many examples about using variables inside calc and using % before the variable name, or {..} around the variable, but I've tried both and neither works. Am I missing something obvious here?
Update
I failed to mention that I am storing my variables in a separate stylus file. If I create the variable in the same file as I am using it within the calculation, it works fine, however if I try to call the variable when it is imported from another file, it doesn't work. The variables file is the FIRST thing that is included in my main styles.styl file, and I can use the variables site wide without issue - just not when using it in a division calculation for some reason.
Codepen
UPDATE:
Try this instead of parenthesis:
#{$site-width / 2}px;
http://sass-lang.com/documentation/file.SASS_REFERENCE.html#interpolation_
This was a bit of a tricky one, but I solved my problem using the below:
margin-right: 'calc(-%s / 2)' % $sitewidth;
I have actually changed my code a bit to include a new variable to get half the width of the site, as I might use it again:
$halfsitewidth = $sitewidth / 2;
margin-right: '-%s' % $halfsitewidth;
I'm having a strange issue I haven't seen occur. I am trying to do some basic addition to some variables like this:
#screen-break-sm: 768px;
#screen-break-md: 992px;
#screen-max-mobile: #screen-break-sm;
#screen-min-desktop: #screen-break-sm + 1;
Then, those values are being used in some media queries. When it is compiled using gulp-less (version ~3.0.0 in package.json) via Gulp, the output ends up being something like:
#media (min-width:768px + 1) {
// CSS
}
I'm expecting:
#media (min-width:769px) {
// CSS
}
I have tried doing the addition as both #screen-break-sm + 1 and also screen-break-sm + 1px. I've also tried removing the px part of the original values and doing the add and appending the px afterwards, but that doesn't add either.
In case it is relevant, this is one of the gulp scripts that builds a section where I first ran into this issue:
module.exports = function (build) {
return function () {
var pagesPath = build.options.styles.buildPath + '/pages/';
return build.gulp.src('./resources/assets/less/pages/**/*')
.pipe(build.plugins.less({
paths: [ build.plugins.path.join(__dirname, 'less', 'vendor', 'theme', 'bootstrap') ]
})).on('error', build.errorHandler)
.pipe(build.plugins.minifyCss()).on('error', build.errorHandler)
.pipe(build.plugins.extReplace('.min.css')).on('error', build.errorHandler)
.pipe(build.gulp.dest(pagesPath));
};
};
Any ideas why LESS is concatenating/appending instead of performing addition?
[EDIT]
While the solution is the same as the other question that was identified as a possible duplicate, that question does not discuss the problem that users will encounter directly, and therefore I think this question is much better suited for searching purposes. I never found that solution after an hour of Googling and only after getting the answer and the "strict math" verbiage did that other question show up.
Look at strict math option which default value is OFF. Are you sure that for some reason you don't have it set to ON?
lessc -sm=on
lessc --strict-math=on
I needed to create a function for some big color work on my Bootstrap variables. Unfortunately LESS doesn't allow you to create functions that can be called like theirs (ex. #myvar: darken(#color, 20%);).
The option provided on the doc site is to use a mixin that returns a variable. This worked well for me when I used it where the variable was declared as the property value, but I need to run my new mixin on many variables in the Bootstrap variable.less file. If I call the mixin multiple times there, it always returns the first color.
Part that works:
.mixin(#color) {
#var: #color;
}
.caller-1 {
.mixin(blue);
color:#var;
}
.caller-2 {
.mixin(red);
color:#var;
}
CSS
.caller-1 {
color:blue;
}
.caller-2 {
color:red;
}
What does not work:
.mixin(blue);
#color-1: #var; // My value is now blue
.mixin(red);
#color-2: #var; // My value is also blue
I thought I could get around this by building a unique variable in the mixin, but I can't find anyway to build one.
.mixin(#color; #num)
#var+#{num}: #color;
}
.mixin(blue; 1);
#color-1: #var1;
.mixin(red; 2);
#color-2: #var2;
Any idea on how to create a variable name in a mixin or other ideas on how to make one work like the LESS functions?
You can't define variables dynamically in LESS right now, but you can dynamically define selectors (as you probably knew). I will just give an example of that and leave it to you to apply it to the color/variables issue.
.towerMaker (#index) when (#index > 0) {
.block-#{index} {
z-index: #{index};
}
.towerMaker(#index - 1);
}
.towerMaker (7);
Variables are actually constants, and their scope is based only on context (where they appear in the block doesn't matter). It's only different when you call it within a selector block because of context. When you call the mixin at top-level, you define #var once for that level and it won't be overriden.
If you have to use variables, I suggest you try to find a solution taking advantage of the context. For example, you might be able to try something with mixin guards & when(condition) {...} (it's actually even simpler, as #seven-phases-max commented below). This is a way to run a mixin outside the context of a selector but still inside a context (updated example):
& {
.mixin(red);
.test1 { color: #var; }
}
& {
.mixin(blue);
.test1 { color: #var; }
}
You actually can define functions that will be called using Less by your Less runtime, but they can't be defined using Less. This is possible if you run your processor using Node.js, for example. But it's quite a hack and not trivial since you have to write them in JavaScript and wrap values in undocumented less.js types.
You can also call core JavaScript enclosing it within backticks (this is also undocumented). It's good for small blocks of code and for core functions:
length: unit(`Math.log(#{value})`, px);
If you run your Less processor from a Node.js app you can call your own functions that way.
I have been searching in Google etc., but I couldnt find what I was looking for (I hope I didnt overlook something).. So I thought my best bet is to ask you guys :)
I am playing around with LESS-JS for the first time and I really like it. However I have a little problem now.
I am using the #arguments variable like this:
.basicBorder(#width:1px, #type:solid, #color:#black){
border:#arguments;
}
Which works as expected. Now when I want the border to be red, I am adding this to the element in my css:
.basicBorder(1px, solid, #red);
Which also works as expected. However I would like to avoid writing 1px, solid,, since these are my default values already, but when I try this:
.basicBorder(#red);
Or this:
.basicBorder(,,#red);
It doesnt work.
So I was wondering if any1 knows how I could "skip" the first 2 variables so that I can just input the color in case I dont want the border-width and type to be changed.
I hope you get what I am trying to say!
Regards!
You actually can name later parameters and skip the first ones. The syntax for your question is:
.basicBorder(#color:#red);
You can also use normal ordered arguments at the beginning and pluck out named arguments from the rest of the parameters:
.basicBorder(2px, #color:#red);
This sets #width to 2px, #type to the default, and #color to #red. Really nice if you have more seldom used arguments.
The parametric mixins in LESS works sorta like javascript functions, you can't skip the first parameters. So if you want to only change the color, you could rewrite the mixin like this:
.basicBorder(#color:#black, #width:1px, #type:solid){
border:#width #type #color;
}
Then you'd be able to call it like this:
.basicBorder(#red);
.basicBorder(#red, 2px, dotted);
edit
Using your original mixin, you could also create these
.basicBorderType(#type) {
.basicBorder(1px, #type, #black);
}
.basicBorderColor(#color) {
.basicBorder(1px, solid, #color);
}
Now you could overwrite any of the styles:
.basicBorderType(dotted); //1px dotted black;
.basicBorderColor(#red); //1px solid red;
.basicBorder(2px); //2px solid black;
A bit of a hack, but it's the only thing I can think of to help you out...