LESS svg-gradient() function with multiple variables - less

I cannot seem to send multiple variables to the svg-gradient() function in less.
If I don't use variables, the svg-gradient function works fine. (Except for the non-increment of ids - but that's something else entirely!) Or if I send the exact same data to the CSS property, linear-gradient(), which is the same format that the svg-gradient() function requires, it works also.
Can anyone tell me why the commented lines in the code below are not successfully compiling when the ones above and below are succesful?
/* Example 1 */
.my-mixin-gradient(#size: contain; #direction: to right; #color...){
background: svg-gradient(#direction, red 0, orange 20%, yellow 30%, green 50%, blue 70%, indigo 85%, violet 100%);
/* background: svg-gradient(#direction, #color); */ /* Why does this not compile ??? */
background: linear-gradient(#direction, #color);
background-size: #size;
}
.my-class{
.my-mixin-gradient(contain; to bottom; red 0, orange 20%, yellow 30%, green 50%, blue 70%, indigo 85%, violet 100%);
}
/* Example 2 */
.my-mixin-gradient2(#size: contain; #mygrad: to right, #000 0, #fff 100%){
background: svg-gradient(to bottom, #ff0000 0, #ffa500 20%, #ffff00 30%, #008000 50%, #0000ff 70%, #4b0082 85%, #ee82ee 100%);
/* background: svg-gradient(#mygrad); */ /* Why does this not compile either ??? */
background: linear-gradient(#mygrad);
background-size: #size;
}
.my-class2{
.my-mixin-gradient2(contain; to bottom, #ff0000 0, #ffa500 20%, #ffff00 30%, #008000 50%, #0000ff 70%, #4b0082 85%, #ee82ee 100%);
}

Related

how to use "sass:meta" in sass-loader on vue component

I have the next error on my component
SassError: Invalid CSS after "... $color in meta": expected expression (e.g. 1px, bold), was ".keywords($args) {"
on line 5 of src/assets/scss/components/_dMetricCircle.scss
from line 101 of src/components/UI/DMetricCircle.vue
#each $name, $color in meta.keywords($args) {
and this is my _dMetricCircle.scss
#use "sass:meta";
#mixin test-mixin($args...){
#each $name, $color in meta.keywords($args) {
.#{$name} {
background-color: map-get($color, "bgcolor");
border: 1px solid map-get($color, "border");
#if map-has-key($color, "pcolor") {
&.percent{
background: linear-gradient(var(--v), map-get($color, "pcolor") 50%, transparent 0) center/calc(var(--s) * 100%) border-box,
linear-gradient(var(--v), map-get($color, "bgcolor") 50%, transparent 0) center/calc(100% - var(--s) * 100%) border-box,
linear-gradient(to right, map-get($color, "pcolor") 50%, map-get($color, "bgcolor") 0) border-box;
}
}
}
}
}
and on my DMetricCircle component, I import and use the mixin like this
#include test-mixin(
$default: ("bgcolor": $gray-lighten-45, "border": $gray-lighten-30),
$success: ("bgcolor": $success-lighten-50, "border": $success-lighten-20, "pcolor": $gray-lighten-45),)
So, I don't know if sass-loader doesn't supper the use of meta or I'm doing a wrong use of sass compiler
"node-sass": "4.14.1","sass-loader": "10.0.2"

Dashing Change back ground color widget dynamically

I have a widget which brings the data from sonar and checks if there are any blockers or criticals. If the blockers and criticals are 0, background colors should be blue, else it is red which is default in scss.
My Job.rb has a logic to check if it is 0 and store the boolean value to a variable "failed".
And my coffee script has the below logic:
class Dashing.SonarColor extends Dashing.Widget
#accessor 'bgColor', ->
if data.failed
"#12b0c5"
else
"red"
ready: ->
if #get('unordered')
$(#node).find('ol').remove()
else
$(#node).find('ul').remove()
onData: (data) ->
if data.currentResult isnt data.lastResult
$(#node).fadeOut().css('background-color', #get('bgColor')).fadeIn()
Background color remains red which is the default set in .scss
$background-color: #FF0000;
$value-color: #fff;
$title-color: rgba(255, 255, 255, 0.7);
$label-color: rgba(255, 255, 255, 0.7);
$moreinfo-color: rgba(255, 255, 255, 0.7);
.widget-sonar-color {
background-color: $background-color;
vertical-align: top;
}

Smart margin mixin for LESS

I've created a .smartMargin() mixin for LESS CSS to be used in responsive design LESS.
I'm sharing it here for the benefit of others and also because I'm curious if there's any way to make it more efficient.
Idea
The mixin is designed to be called from within another mixin that represents a responsive design breakpoint. The idea is that you may want to override top, left, bottom, right margins individually by overriding one or more margins in each successive breakpoint.
In main mixin I just want one parameter for #videoMargin as opposed to #videoMarginLeft, #videoMarginRight etc so that's why I've called it 'smartMargin'.
Usage
In my main file I define a breakpoint like this, and then call this mixin several times:
.breakpoint(#width, #color, #labelsSize, #videoMargin)
{
video
{
.smartMargin(#videoMargin);
}
}
.breakPoint(10em, red, 3em, 1em auto 1em auto);
.breakPoint(10em, green, 3em, 2em unset unset unset);
.breakPoint(20em, blue, 3em, unset 3em unset unset);
Output css
So for a given value of #videoMargin here's the output css generated
generated css
-------------
.smartMargin(3em); margin: 3em;
.smartMargin(3em 1em 2em 4em); margin: 3em 1em 2em 4em;
.smartMargin(3em unset unset unset); margin-top: 3em;
.smartMargin(3em unset unset 4em); margin-top: 3em;
margin-right: 3em;
Implementation
The mixin is as follows. It works well but it just seems a little clumsy in places and you need to provide either 4 or 1 parameters. If anybody can optimize this I'd be very interested to see.
.smartMargin(#margin) when (length(#margin) = 4)
{
._smartMargin() when (extract(#margin, 4) = unset), (extract(#margin, 3) = unset), (extract(#margin, 2) = unset), (extract(#margin, 1) = unset)
{
.marginComponent(#name, #value)
{
& when not (#value = unset)
{
#{name}: #value;
}
}
.marginComponent(margin-top, extract(#margin, 1));
.marginComponent(margin-right, extract(#margin, 2));
.marginComponent(margin-bottom, extract(#margin, 3));
.marginComponent(margin-left, extract(#margin, 4));
}
._smartMargin() when (default())
{
margin: #margin;
}
._smartMargin();
}
.smartMargin(#margin) when (default())
{
& when not (#margin = ~'') and not (#margin = unset)
{
margin: #margin;
}
}
You could possibly rewrite it to something like:
.smartMargin(#margin) when (isem(#margin)),(isem(extract(#margin,1))) and (isem(extract(#margin,2))) and (isem(extract(#margin,3))) and (isem(extract(#margin,4))) {
margin: #margin;
}
.smartMargin(#margin) when (default()) and (4 = length(#margin)) {
#positions: top, right, bottom, left;
.setmargin(#position,#margin) when (isem(#margin)){
margin-#{position}: #margin;
}
.setmargins(#i:1) when (#i <= 4){
.setmargin(extract(#positions,#i);extract(#margin,#i));
.setmargins((#i + 1));
}
.setmargins();
}
But in the first place i don't think there is something wrong with your code. Personally is should consider the use of unset. I think you should use the initial keyword or even 0 in stead of unset. This enables you to do the following:
.smartMargin(#margin){
margin: #margin;
}
.one{
.smartMargin(3em);
}
.two{
.smartMargin(3em 1em 2em 4em);
}
.three{
.smartMargin(3em 0 0 0);
}
.four{
.smartMargin(3em 0 0 4em);
}
Or consider to use Passing Rulesets to Mixins, than you can use something like that shown below:
.breakPoint(#width, #color, #labelsSize, #videoMargin)
{
video
{
#videoMargin();
}
}
.breakPoint(10em, red, 3em, {margin: 1em auto 1em auto;});
.breakPoint(10em, red, 3em, {margin: 1em auto;});
.breakPoint(10em, green, 3em, {margin: 2em 0 0 0;});
.breakPoint(10em, green, 3em, {margin: 2em 0 0;});
.breakPoint(10em, green, 3em, {margin-top: 2em;});
.breakPoint(20em, blue, 3em, {margin: 0 3em 0 0;});
.breakPoint(20em, blue, 3em, {margin-right: 3em;});

Is there a generic way to add vendor prefixes in LESS?

I currently have a mixins.less file, where almost all mixins are basically the same:
.border-radius(#radius) {
-webkit-border-radius: #radius;
-khtml-border-radius: #radius;
-moz-border-radius: #radius;
border-radius: #radius;
}
.box-shadow(#value) {
-webkit-box-shadow: #value;
-khtml-box-shadow: #value;
-moz-box-shadow: #value;
box-shadow: #value;
}
Is there a way to create some kind of generic mixin, that I could call like this:
.vendor('border-radius', '3px');
.vendor('box-shadox', '10px 10px');
and which would produce the same result as above?
Notice:
The recommendation is to stop rely on this technique and consider using a dedicated prefixing tool (e.g. Autoprefixer, -prefix-free etc.). Hardcoding vendor prefixes via CSS pre-processor mixins (Less, SCSS or whatever) is a pure anti-pattern these days and considered harmful. Auto-prefixing tools will make your code clean, readable, future-proof and easily maintainable/customizable.
See for example: less-plugin-autoprefix
Original answer:
Well, currently LESS does not support "property name interpolation" so you cannot use a variable in property names. There's a hack however: How to pass a property name as an argument to a mixin in less
So if you don't mind "dummy" properties in the output CSS, here we go:
.property_(#property, #value) {
_: ~"; #{property}:" #value;
}
.vendor(#property, #value) {
.property_('-webkit-#{property}', #value);
.property_( '-khtml-#{property}', #value);
.property_( '-moz-#{property}', #value);
.property_( #property, #value);
}
#usage {
.vendor(border-radius, 3px);
.vendor(box-shadow, 10px 10px);
}
Output:
#usage {
_: ; -webkit-border-radius: 3px;
_: ; -khtml-border-radius: 3px;
_: ; -moz-border-radius: 3px;
_: ; border-radius: 3px;
_: ; -webkit-box-shadow: 10px 10px;
_: ; -khtml-box-shadow: 10px 10px;
_: ; -moz-box-shadow: 10px 10px;
_: ; box-shadow: 10px 10px;
}
Update:
Less v1.6.0 introduced Property Interpolation feature so now you don't need any hacks anymore:
.vendor(#property, #value) {
-webkit-#{property}: #value;
-khtml-#{property}: #value;
-moz-#{property}: #value;
#{property}: #value;
}
#usage {
.vendor(border-radius, 3px);
.vendor(box-shadow, 10px 10px);
}

Fallback background for browsers not supporting border-image

I'm trying to use CSS3 border-image for a simple button design: the left slice of the image should be the left border of the text, the right slice the right border, and the middle slice should be repeated (or stretched - it does not matter) as background. I need a fallback for browsers not supporting border-image - just using the middle slice as a background, without edges would be acceptable. The problem is, if I do this:
.button {
border: solid 1px white;
border-size: 0 5px;
background: ('button-slice.png') repeat;
border-image: url('button.png') 0 5 0 5 fill;
-moz-border-image: url('button.png') 0 5 0 5;
/* repeat for other vendor prefixes */
}
the image from the background property will overlap the borders and mess up the button for browsers which support border-image.
Is there a lightweight way of solving this problem (whithout introducing modernizr or similar javascript checks)?
change the border-image 0 5 0 5 to 1 1 5 1 :
border-image: url('button.png') 1 1 5 1 fill;
-moz-border-image: url('button.png') 1 1 5 1;
border-image generator online
border-image is tricky for fallbacks. Doing...
.button {
border: solid 1px white;
border-size: 0 5px;
background: ('button-slice.png') repeat;
background: rgba(0,0,0,0);
border-image: url('button.png') 0 5 0 5 fill;
-moz-border-image: url('button.png') 0 5 0 5;
/* repeat for other vendor prefixes */
}
Should work for all browsers except IE9.
Since you only have a left and right border, I would suggest using pseudo-elements...
.button {
border: solid 1px white;
background: ('button-slice.png') repeat;
position: relative;
}
.button:before, .button:after {
content: '';
width: 5px;
position: absolute;
height: 100%;
background: transparent url('button.png') 0 0 no-repeat;
top: 0;
}
.button:before {left: -5px;}
.button:after {right: -5px;}
This technique should show nice buttons in all modern browsers plus IE8. Older browsers fallback without the edges.
It seems that new versions of FF support both border-image parameters and one override another.
Try reversing the order of those lines as so:
-moz-border-image: url('button.png') 0 5 0 5;
border-image: url('button.png') 0 5 0 5 fill;
In this way, browsers that support both parameters and override one with the later will take the version with the fill.