I am specifying the cytoscape.js style via css (and converting to the JSON format using this). I am trying to use a discrete mapper for the style. Similar to How to use a descreteMapper like on cytoscapeweb? but I don't want to just pass through the data(blah) value, I want to set different values based on different data(blah) values. Like this (which I based off what I found here)
node {
color : {
defaultValue: red,
discreteMapper: {
attr: n_phosphorylated,
mapped: {
true: blue
}
}};
}
I am getting TypeError: element._private.style.color.value is undefined. Do I have the syntax wrong or is this not supported?
Found the answer from this comment:
How to create custom style mapping in cytoscape.js?
The correct way is to use selectors based on the data:
node[?n_phosphorylated] {
color: blue;
}
Here the ? operator means (roughly) n_phosphorylated=true.
Thanks Max
Related
I have the following SCSS code:
#mixin foo($bar: 42) {
--xyzzy: $bar;
}
bar {
#include foo;
}
I would expect that I get CSS variable --xyzzy set to 42 on all bar elements. Instead of this, I get CSS stating bar { --xyzzy: $bar; }. The variable was not interpreted. I would need to use #{…} syntax instead to get the variable set.
Is this a feature of the SCSS/SASS? A bug? Can I get the interpretation working without enclosing the variable name in #{…}?
Actual result:
bar {
--xyzzy: $bar;
}
Expected:
bar {
--xyzzy: 42;
}
It's not a bug, it's how the Sass compiler works regarding CSS custom properties, known as CSS variables. The syntax #{…} is called interpolation, and it is the only way to inject dynamic values into a custom property. Here is a quote from the doc:
CSS custom properties, also known as CSS variables, have an unusual declaration syntax: they allow almost any text at all in their declaration values. What’s more, those values are accessible to JavaScript, so any value might potentially be relevant to the user. This includes values that would normally be parsed as SassScript.
Because of this, Sass parses custom property declarations differently than other property declarations. All tokens, including those that look like SassScript, are passed through to CSS as-is. The only exception is interpolation, which is the only way to inject dynamic values into a custom property.
That's the reason why you have that behavior, and only doing so works:
#mixin foo($bar: 42) {
--xyzzy: $bar; // does not work
--xyzzy: #{$bar}; // works
}
When using CSS Variables (CSS Custom Properties) why is the setting syntax and the getting syntax different?
If I wish to set a value for --my-custom-width, I will use:
:root {
--my-custom-width: 120px;
}
And if I wish to get a value for --my-custom-width, I will use a var() function to retrieve the same value:
.my-div {
width: var(--my-custom-width);
}
Why do we not simply write:
.my-div {
width: --my-custom-width;
}
Having been using CSS Custom Properties since late 2017, I've finally understood properly what they really are and why the var() function is necessary...
They are not (as they so often appear to be) variables intended to directly represent CSS values.
CSS Custom Properties are exactly what they say they are - they are new CSS properties which have not (yet) been assigned values.
In CSS, an example of something which really does approximate a variable representing a value is currentColor.
We see currentColor representing a value, here:
.my-div {
border: 1px dashed currentColor;
}
But CSS Custom Properties are not CSS variables which stand in for values like currentColor, .
Instead, CSS Custom Properties are newly invented, named, null-value-properties...
... and those newly-invented, named, null-value-properties are completely re-usable. Just like width, height, color etc. they may have values set and reset in different contexts.
E.g.
/* My custom property is --my-custom-width but I want this
property to hold different values in different contexts */
.left-two-thirds-of-page {
--my-custom-width: 120px;
}
.right-third-of-page {
--my-custom-width: 60px;
}
.my-div {
width: var(--my-custom-width);
}
That's why the var() function is necessary - it's not delivering "the custom property" - it's extracting the value that custom property is currently holding and then delivering that value.
Further Thoughts:
In hindsight, I wonder if the whole name-value relationship wouldn't have been a little clearer if CSS Custom Properties had been called:
CSS Custom Property Names
and the corresponding function had been called:
value()
so the syntax would have been written and read out as:
value(--my-custom-property-name)
By extension we could use the value() function (or var() function) not just on custom properties but on any property.
For instance:
width: value(height);
It seems that evaluated color strings are not working with some built-in LESS functions.
I have tried using e() and ~"" and any combination of both.
I might find a workaround for my particular case, I’m just asking if this is this expected behaviour, or if there is a fault in my reasoning? Any insight appreciated.
For example here, the color is created from an evaluated string; note the 'missing' # in the hex value that gets added later :
.broken-mixin(#hexcode: '9719e1') {
#color: e("##{hexcode}");
// this works as expected
background-color: #color;
// this does work too
.very-simple-mixin(#color);
// Undefined_methodError: error evaluating function `fade`:
// Object #<Object> has no method 'toHSL'
background-color: fade(#color,30%);
// SyntaxError: error evaluating function `red`:
// Cannot read property '0' of undefined
background-color: rgba(red(#color), green(#color), blue(#color), 0.5);
}
Otherwise built-in functions work normally work with variables in mixins, for example :
.mixin-works(#myColor: #00ff00) {
// works just fine
background-color: fade(#myColor,30%);
// or this, works too
background-color: rgba(red(#myColor), green(#myColor), blue(#myColor), 0.5);
}
What am I missing ?
Quoting the LESS website's Function Reference:
fade
Set the absolute transparency of a color. Can be applied to colors whether they already have an opacity value or not.
Parameters:
color: A color object.
amount: A percentage 0-100%.
The fade function requires a color object as input to it and hence passing an evaluated string as a parameter to the function doesn't work.
It can be solved by using the built-in color function which converts a string into an equivalent color object like below:
background-color: fade(color("#{color}"),30%);
The other built-in functions also are not working for the same reason (that is, they expect a color object as an input).
red:
Extracts the red channel of a color object.
Parameters: color - a color object.
I have a LESS loop in which I determine color values to use in CSS rules.
I get them through some quite complex vars evaluation, which forces me to use strings (If I remove the " I get a parse error).
So what I get is a variable containing a color value in form of string.
#color: "#{col_#{animal}}"
// this is in a loop, and #animal contains the name of a var ('dog', 'cat', ...)
// #col_dog, #col_cat contain a color
// #col_dog: #F9E2A0
// #col_cat: #094DD0
so if I try to assign this #color variable to a rule
.border { border-color: #color }
in CSS I get
.border {border-color: "#F9E2A0"}
Which obviously is ignored.
Is there a way to get rid of the "string" form, or a way to do the vars evaluation I need without using strings?
Thanks!
It's easy just use ##
I've been struggling with this myself for some time now. The solution is simple. Just use ## instead of # for the color. The color will then get parsed properly, and become an color object. For this to work I store the variable name 'color_cat' in a variable called #color first. The I use the variable variables technique ## to resolve the variable.
In your case this code works:
#color_dog: red;
#color_cat: yellow;
.animal-border(#animal){
#color: "color_#{animal}";
.#{animal}.border{
border-color: ##color;
}
}
.animal-border(dog);
.animal-border(cat);
Results:
.dog.border {
border-color: #ff0000;
}
.cat.border {
border-color: #ffff00;
}
Some errors associated with this problem. This one occurs when using the darken or lighten methods:
error evaluating function darken: Object # has no method 'toHSL'
Or this occurs when trying to supply the string value "#FF0000" to the color method:
error evaluating function color: argument must be a color keyword or 3/6 digit hex e.g. #FFF
Some related posts on SO:
Define variable name with variable in LESS operation
less undefined method error
Lighten color from parent in Less
Defining Variable Variables using LESS CSS
According to the docs http://lesscss.org/functions/#misc-functions-color
Parses a color, so a string representing a color becomes a color.
This should be doing what you want:
.border { border-color: color(#color) }
Inspired by COLORS: A nicer color palette for the web, I was wondering if there is way to override the default named color definition as defined in the HTML/CSS specification with these new colors.
I am aware that I can create custom CSS rules (and LESS) to define new colors and apply these to which ever elements, however the interest here is for example
h1{
/* #ff0000 is current definition of red, I want to redefine it to #FF4136 */
color: red;
}
Update
I was so inspired by my question, I ended up digging around in the Blink and WebKit source code and from what I can see, these colors are defined within code.
Webkit Line ~3299
static const ColorValue colorValues[] = {
{ CSSValueAqua, 0xFF00FFFF },
{ CSSValueBlack, 0xFF000000 },
{ CSSValueBlue, 0xFF0000FF },
{ CSSValueFuchsia, 0xFFFF00FF },
{ CSSValueGray, 0xFF808080 },
{ CSSValueGreen, 0xFF008000 },
{ CSSValueGrey, 0xFF808080 },
{ CSSValueLime, 0xFF00FF00 },
{ CSSValueMaroon, 0xFF800000 },
{ CSSValueNavy, 0xFF000080 },
{ CSSValueOlive, 0xFF808000 },
{ CSSValueOrange, 0xFFFFA500 },
{ CSSValuePurple, 0xFF800080 },
{ CSSValueRed, 0xFFFF0000 },
{ CSSValueSilver, 0xFFC0C0C0 },
{ CSSValueTeal, 0xFF008080 },
{ CSSValueTransparent, 0x00000000 },
{ CSSValueWhite, 0xFFFFFFFF },
{ CSSValueYellow, 0xFFFFFF00 },
{ CSSValueInvalid, CSSValueInvalid }
};
Blink ~ Line 157
Update 2
There may some hope for the future. FireFox Nightly build includes the concept of a CSS-variable. Although a vendor specific at this point, it 'almost' is related to my question. The related W3C specification : CSS Custom Properties for Cascading Variables Module Level 1 - see Example 4
No, these color keywords are pre-defined and there is no way to override their color mappings from outside the browser. This applies to all named color keywords defined in the spec that you link to, including the basic set of CSS keywords, the X11/SVG keywords and the deprecated system colors (although of course, system colors are taken from the system palette).
You won't be able to query computed styles of DOM elements and replace them on the fly either, because computed color values are always rgb() or rgba() triplets, even if the cascaded value is the keyword. This is stated in the spec that you link to:
The computed value for basic color keywords, RGB hex values and extended color keywords is the equivalent triplet of numerical RGB values, e.g. six digit hex value or rgb(...) functional value, with an alpha value of 1.
In your example CSS rule, the computed color of h1 elements would be rgb(255, 0, 0), not red. You cannot distinguish #ff0000 or red from rgb(255, 0, 0) in that case, which can pose problems if you're specifically only targeting the red keyword.
You could parse and modify the stylesheet directly using a script, but CSS parsing isn't easy. You have to account for shorthand declarations, URLs (e.g. background: red url(redimg.png) center center no-repeat;), and so on and so forth. That's probably out of the scope of your question.
Custom properties only allow you to specify a cascading variable in place of a keyword as a value. You won't be able to modify existing pre-defined keywords with custom properties, so you'd still have to replace every occurrence of red with something like var(red) where the var-red property corresponds to a user-defined red.