SVG: why does external css override inline style for text?

rolfsf picture rolfsf · Jun 18, 2014 · Viewed 10.9k times · Source

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!

Answer

Ben Lesh picture Ben Lesh · Jun 18, 2014

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>