SVG: why does external css override inline style f

2019-01-18 02:09发布

I'm playing with using an SVG gradientFill as a way to visually 'truncate' long text strings in a d3.js chart.

It seems that an external css style for fill will override the inline gradient fill style in the SVG... is that always the case? How can I enforce that gradient fill?

In this test case I've defined a linear gradient in the svg defs, and then apply the gradient fill to two groups of text. http://jsfiddle.net/rolfsf/uX2kH/3/

var labelColWidth = 200;
var svg =  d3.select('#test').append('svg')
            .attr('width', 500)
            .attr('height', 500);

var defs = svg.append('svg:defs');

var textgradient = defs.append('svg:linearGradient')
            .attr('gradientUnits', 'userSpaceOnUse')
            .attr('x1', 0).attr('y1', 0).attr('x2', 40).attr('y2', 0)
            .attr('id', 'theGradient')
            .attr('gradientTransform',  'translate(' + (labelColWidth - 40) + ')');

    textgradient.append('svg:stop').attr('offset', '0%').attr('style', 'stop-color:rgb(0,0,0);stop-opacity:1')
    textgradient.append('svg:stop').attr('offset', '100%').attr('style', 'stop-color:rgb(0,0,0);stop-opacity:0');


var data = [[0, "xyzzy xyzzy"], [1, "xyzzy xyzzy xyzzy xyzzy xyzzy"], [2, "xyzzy xyzzy xyzzy xyzzy xyzzy xyzzy"], [3, "xyzzy xyzzy xyzzy"], [4, "xyzzy xyzzy"], [5, "xyzzy xyzzy xyzzy xyzzy xyzzy xyzzy xyzzy xyzzy xyzzy xyzzy"]];

var testGroup = svg.append('g')
    .attr('transform',  'translate(50, 100)');

var testGroup2 = svg.append('g')
    .attr('transform',  'translate(50, 250)')
    .attr('class', 'group2');

testGroup.selectAll('text').data(data)
  .enter().append('svg:text')
  .attr('fill', 'url(#theGradient)')
  .attr('x', 0)
  .attr('y', function(d, i) { return (i+1) * 20; })
  .text(function(d, i) { return d[1]; });

testGroup2.selectAll('text').data(data)
  .enter().append('svg:text')
  .attr('fill', 'url(#theGradient)')
  .attr('x', 0)
  .attr('y', function(d, i) { return (i+1) * 20; })
  .text(function(d, i) { return d[1]; });

then in CSS, I define a fill for .group2 text

.group2 text {
    fill: #000;
}

the first group has the gradient fill, the second group does not.

Shouldn't the inline style take precedence?

Thanks!

3条回答
Anthone
2楼-- · 2019-01-18 02:44

Because in SVG, like HTML before it, styles trump attribute styling.

fill="red" below is NOT an "inline style", style="fill:green" IS an inline style.

<svg width="400" height="400">
  <text x="50" y="50" fill="red" style="fill:green">This will be green</text>
</svg>

Like wise, if you have a style defined outside, it will win.

<style>
  text { fill: lime; }
</style>
<svg width="300" height="300">
  <text x="50" y="40" fill="red">This will be lime</text>
</svg>

查看更多
在下西门庆
3楼-- · 2019-01-18 02:44

In my case it was as simple as replacing attr with style in the d3 chain:

.style('stroke', 'url(#gradient--min)')
查看更多
三岁会撩人
4楼-- · 2019-01-18 02:50

From the SVG specification

For user agents that support CSS, the presentation attributes must be translated to corresponding CSS style rules according to rules described in Precedence of non-CSS presentational hints ([CSS2], section 6.4.4), with the additional clarification that the presentation attributes are conceptually inserted into a new author style sheet which is the first in the author style sheet collection. The presentation attributes thus will participate in the CSS2 cascade as if they were replaced by corresponding CSS style rules placed at the start of the author style sheet with a specificity of zero. In general, this means that the presentation attributes have lower priority than other CSS style rules specified in author style sheets or ‘style’ attributes.

So you could use an inline style rather than a presentation attribute e.g.

.attr('style', 'fill : url(#theGradient)')
查看更多
登录 后发表回答