joeyhoer
joeyhoer

Reputation: 3767

SVG Fill and Transform

I understand that fill is applied after transform, but I don't understand why. I've looked in the spec and cannot find information about why this might be.

I'd like to know if there is a way to have the fill applied to a group of elements, some using transform: rotate in a consistent manner. To illustrate the problem see the example code below:

<svg width='38' height='18' viewBox='0 0 38 18' xmlns='http://www.w3.org/2000/svg'>
    <defs>
        <linearGradient id='gradientFill' x2='0' y2='100%' gradientUnits='userSpaceOnUse'>
            <stop stop-color='hsl(0, 0%, 0%)' />
            <stop offset='100%' stop-color='hsl(0, 0%, 100%)' />
        </linearGradient>
        <path id='shape' d='M0,0m9,0c-3.92,0,-7.24,2.51,-8.48,6h3.29c0.83,-1.92,2.8,-3.56,5.19,-3c2.52,0.59,3,3.55,3,6c0,3.6,-0.6,6,-3,6s-3,-2.4,-3,-6h-6c0,4.97,4.03,9,9,9c4.97,0,9,-4.03,9,-9s-4.03,-9,-9,-9z'/>
        <g id='test'>
            <use xlink:href='#shape'></use>
            <use transform='translate(20,0) rotate(180,9,9)' xlink:href='#shape'></use>
        </g>
    </defs>
    <use class='logo' xlink:href='#test' fill="url(#gradientFill)"></use>
</svg>

As you see, on the non-rotated element the gradient runs top to bottom, as expected. However on the rotated element the gradient is also rotated so that it runs from bottom to top. This seems inconsistent to me, as the fill is applied to a group and not the individual objects.

My ultimate desire is to have the linear gradient flow from top to bottom on both shapes, but I'd like to continue using the use and transform method, if possible.

Can someone point me in the right direction in regards to the spec, and also suggest a solution to accomplish my goal?

Upvotes: 1

Views: 1625

Answers (3)

Michael Mullany
Michael Mullany

Reputation: 31715

You should define your shape as a clip-path and then apply it to a rect that is filled with the gradient you want. You could also do it with a filter, although that's a little more complicated.

Upvotes: 1

Robert Longson
Robert Longson

Reputation: 123995

That you apply transforms first is stated in the SVG specification for gradients when it talks about gradientUnits...

If gradientUnits="userSpaceOnUse", ‘x1’, ‘y1’, ‘x2’ and ‘y2’ represent values in the coordinate system that results from taking the current user coordinate system in place at the time when the gradient element is referenced (i.e., the user coordinate system for the element referencing the gradient element via a ‘fill’ or ‘stroke’ property) and then applying the transform specified by attribute ‘gradientTransform’.

If you apply a transform to the element it changes the element's co-ordinate system and that therefore affects the gradient too.

Upvotes: 1

Paul LeBeau
Paul LeBeau

Reputation: 101800

Attributes like "fill" are not commands that operate on an object, they are properties that are used by the object when rendering and are inherited by an object's children. Just the same as CSS rules.

To achieve the effect you want, use Michael's solution, or create a second gradient that has it's x,y and x2,y2 flipped to match the 180 degree rotation.

Upvotes: 1

Related Questions