I am building charts with Raphael.js that have all sorts of styling attached to them, including different hover styling. The following works across browsers:
var bar = paper.rect(x, y, width, height)
.attr({"stroke-width": 0, fill: #baeadd; "fill-opacity": 0.3})
In an attempt to fully separate the appearance from the functionality, I am trying to target my Raphael elements with CSS and add all the styling from there.
I used the technique outlined here to be able to target my shapes in all browsers, using unique ID-s:
bar.node.id = "bar-" + id;
-
*[id^="bar"] {
// Attributes listed here seem to work in modern browsers
// http://raphaeljs.com/reference.html#Element.attr
fill: #baeadd;
fill-opacity: 0.3;
}
*[id^="bar"]:hover {
fill-opacity: 0.5;
}
The above does not work on IE8, where Raphael injects vml shape elements instead. I am able to specify standard CSS properties such as background-color, and the shape element will get the styling fine, but I would like to know how to apply attributes such as fill-opacity, stroke-width, and the likes.
Is it possible to set fill and stroke colors and opacity on VML paths using CSS? explains the role of behavior: url(#default#VML). I can see that Raphael already adds a .rvml class to all the shape elements it creates, and applies this behavior property, but it doesn't seem to take effect as soon as I stop applying attributes via JS and start specifying them in the CSS.
There isn't a way of doing this since IE8 requires setting the attributes on the VML elements.
Based on my answer to Is it possible to set fill and stroke colors and opacity on VML paths using CSS?, you should be able to use a DHTML behaviour file to read the SVG styles applied in your style sheet and map them to the corresponding VML attributes.
Start by creating the behavior file, eg: vmlcss.htc
<PUBLIC:COMPONENT>
<SCRIPT LANGUAGE="JScript">
var currentStyle = element.currentStyle;
if (currentStyle)
{
// Apply stroke style
element.stroked = currentStyle["stroke"] && currentStyle["stroke"] != "none";
if (element.stroked)
{
element.strokecolor = currentStyle["stroke"] || "none";
element.strokeweight = currentStyle["stroke-width"] || "1px";
}
// Apply fill style
element.filled = currentStyle["fill"] != "none";
if (element.filled)
{
element.fillcolor = currentStyle["fill"] || "Black";
}
}
</SCRIPT>
</PUBLIC:COMPONENT>
Then add this block to your pages in order to apply this new behavior to the VML elements:
<style>
.rvml
{
behavior: url(#default#VML) url(vmlcss.htc);
}
</style>
That's all. The stroke color and fill color specified in your CSS should now be applied to the VML elements when running IE<9.
You may further extend the behavior file to map other SVG styles to VML attributes as needed.
In my opinion, Raphael should offer the possibility to specify either identifiers or class names for the created shapes, making styling via CSS much easier.
Note: I was not able to test this code, please let me know if there are issues with it so that we can improve the answer.
Related
I'm using this example:
https://bl.ocks.org/mbostock/raw/3306362/
How do I add a hover to the counties? I've tried:
.counties:hover {
fill:red;
}
path d:hover {
fill:red;
}
and some several others. no luck.
Thanks.
Two problems:
counties is the class of the <g> element, not the paths. So, first set a class (like county) for each path;
This is your main problem here: there is a style() for those paths in the D3 code, which is therefore a subsequent rule. So, if you want your CSS rule to override that subsequent rule, use !important:
.county:hover {
fill: red !important;
}
Or, alternatively, change that style() in the code for an attr().
Don't use path:hover, since there are paths for the states as well. Also, there is no d element (path d:hover in your question) neither in HTML nor in SVG. d is a path's attribute.
Here is the updated bl.ocks with those two changes: https://bl.ocks.org/anonymous/9ebef1b8e2a11bd170c50bb4a3440628/8923484fd3715aa474f1eb31184d11da863e24dc
I'm looking into custom CSS properties and have come up with the code below.
If I put the CSS inline using a STYLE attribute on the canvas tag (like this: style="--rgLinewidth: 3" ) then I can get the custom CSS values using the script shown below.
But using a tag, as below, then it doesn't show the custom CSS properties.
Is it possible to? And if so how?
<html>
<head>
<style>
canvas#cvs {
--rgLinewidth: 3;
background-color: red;
}
</style>
</head>
<body>
<canvas id="cvs" width="600" height="250">[No canvas support]</canvas>
<script>
canvas = document.getElementById("cvs");
styles = window.getComputedStyle(canvas);
alert(styles.getPropertyValue('background-color'));
alert(styles.getPropertyValue('--rgLinewidth'));
for (var i=0; i<styles.length; i++) {
if (canvas.style[i].indexOf('--rg') === 0) {
var value = styles.getPropertyValue(canvas.style[i]);
alert([canvas.style[i], value]);
}
}
</script>
</body>
</html>
It does not work because you query for computed style and then attempt to retrieve values of corresponding properties from the inline style, where they do not exist -- your canvas does not define an inline style. You need to query the values through the same styles object where you find the properties.
Consider the following function which when passed an element, will search through its computed style and return the value of the first CSS variable whose name starts with --rg:
function find_first_rg_value(el) {
var styles = getComputedStyle(el);
for (var i = 0; i < styles.length; i++) {
if (styles[i].startsWith('--rg')) {
return styles.getPropertyValue(styles[i]);
}
}
}
(Use like find_first_rg_value(canvas))
The difference between my approach and yours is, as I said, that you attempt to fetch the value from canvas.style[i], but canvas.style is effectively empty. Use styles instead.
Computed style (getComputedStyle), as the name implies, contains "summary" style computed per CSS cascading, inheriting, and so on, with inline style, if any, applied on top (overriding priority). Assigning inline style therefore affects the computed style, but querying inline style only gives you inline style you assigned, no more.
This means that in most cases like yours one would want to use getComputedStyle. Additionally, since CSS variables cannot be queried using style.fontName syntax, you need to use getPropertyValue function for these (all dashes intact in the passed property name), regardless if you are dealing with an inline or computed style object.
Is there an equivalent for the jQuery $.css function in dart?
I can read the (computed) style of an element, but as far as I can see there is no way of setting a style.
Using Element.style isnt enough ?
myDiv.style.backgroundColor = 'red';
myDiv.style.setProperty('-webkit-cssexperimental','value');
It's also working with a multi elements selector:
querySelectorAll('div').style.backgroundColor = 'green'; //color every div
On a web page that contains an eternal CSS style sheet (loaded via <link rel="stylesheet">), I would like to modify the selector of one of its CSS rules. I can reference the rule with:
var rule = document.styleSheets[…].cssRules[…];
(where … are numbers).
Once selected, I can read its selector and other values:
rule.cssText // 'em { color: red }'
rule.selectorText // 'em'
rule.style.color // 'red'
However, when I try to write one of these, it only lets me write the style object:
// These won’t work
rule.cssText = 'em.foo { color: red }';
rule.selectorText = 'em.foo';
// This will work
rule.style.color = 'blue';
Why doesn’t it let me write .cssText or .selectorText? From what I see in the spec, they are not readonly.
Update: I’ve checked for inline style sheets, too. It doesn’t work either.
At least Firefox implements them read-only.
https://developer.mozilla.org/en-US/docs/Web/API/CSSRule.cssText
https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleRule/selectorText
I create widgets for sites which I don't own.
After injecting html, I do the following to style the widget:
var style = document.createElement('style'),
stylesString = 'minified css with a prefix for each selector eg. .my-prefix p {... }',
rules = document.createTextNode(stylesString);
style.type = 'text/css';
if(style.styleSheet) {
style.styleSheet.cssText = rules.nodeValue;
} else {
style.appendChild(rules);
}
document.getElementsByTagName('head')[0].appendChild(style);
But on some sites my styles are overridden.
Is there a way to apply the styles more precisely?
I don't want (can't) to use:
iFrame
!important on every property
This is most likely caused by the elements in question either having inline styles on them (for which you will have to use !important to override, if you want to use your current method of adding styles), or having styles with a higher selector precedence.
My suggestion would be to make your selectors more specific by adding at least an id to them - although this is still no guarantee your selectors will still be the most specific. It is entirely down to the quality of the stylesheet on the original site.