web3icons

fill-rule: nonzero vs evenodd

How nonzero and evenodd decide which parts of a path get filled, why holes in logos vanish in some tools, and how to make icons render the same everywhere.

5 min read

You export a coin logo with a hole in the middle. It looks right in the browser. Then a colleague imports it into another tool, or it goes through an icon font generator, and the hole is filled in solid. Or the reverse: two overlapping shapes in a mono logo suddenly show a gap where they cross.

Both problems come from the fill rule, a single property that decides which areas of a path count as "inside". Once you know how the two rules work, you can make icons that render identically no matter which one a tool applies.

The question a fill rule answers

For a simple shape like a circle or a diamond, inside and outside are obvious. It gets harder when one path contains several subpaths (a circle with a smaller circle inside it) or when a path crosses over itself. The renderer needs a rule.

Both SVG rules use the same thought experiment. Pick a point, draw a ray from it out to infinity in any direction, and look at every place where the ray crosses the path's outline.

nonzero, the default

The nonzero rule cares about direction. Start a counter at zero. Each time the ray crosses a part of the outline running one way across it (say, from left to right), add one. Each time it crosses a part running the other way, subtract one. If the total is anything other than zero, the point is inside.

The consequence: with nonzero, a hole only appears if the inner outline runs in the opposite direction to the outer one. An inner circle drawn in the same direction as the outer one adds to the count instead of cancelling it, and the area stays filled.

nonzero is the default in SVG, so any path without a fill-rule uses it.

evenodd

The evenodd rule ignores direction and simply counts crossings. An odd count means inside; an even count means outside.

A point in the hole of a ring crosses two outlines (inner and outer) on its way out: even, so outside. A point in the band crosses one: odd, so inside. Direction never matters, which is why evenodd feels more intuitive and why some design tools export compound shapes with it.

The ring, both ways

Here is a ring drawn as two circular subpaths, with the attribute set explicitly:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
  <path fill-rule="evenodd" fill="#a1a1aa"
        d="M12 2a10 10 0 1 0 0 20a10 10 0 1 0 0-20z
           M12 7a5 5 0 1 0 0 10a5 5 0 1 0 0-10z"/>
</svg>

Both subpaths use sweep flag 0, so both run counterclockwise on screen. With evenodd the inner circle is a hole. Remove fill-rule="evenodd", and the default nonzero fills the whole disc, because the two counterclockwise outlines add up to 2 in the middle.

Now flip the inner circle's sweep flags to 1, so it runs clockwise:

<path fill="#a1a1aa"
      d="M12 2a10 10 0 1 0 0 20a10 10 0 1 0 0-20z
         M12 7a5 5 0 1 1 0 10a5 5 0 1 1 0-10z"/>

The outer circle counts +1 and the inner one -1, so the middle totals zero and becomes a hole under nonzero. And under evenodd it is a hole as well, because the crossing count is still two.

Inner outline direction nonzero evenodd
Same as the outer outline Solid disc Ring
Opposite to the outer outline Ring Ring

The second row is the important one. When holes run opposite to their outer shape, both rules give the same result. That is the most reliable way to make an icon independent of which rule a tool assumes.

Overlapping shapes

The rules also disagree where shapes overlap inside a single path. Picture a mono logo built from two overlapping circles, merged into one path when the colors were removed:

Two overlapping subpaths, same direction nonzero evenodd
Area covered by one circle Filled Filled
Area covered by both Filled Hole

With evenodd, the lens where the circles overlap is crossed twice and becomes a hole. Sometimes that is the intended design, using negative space to keep the shapes distinguishable. Often it is an accident of merging paths. If you meant the overlap to be filled, unite the shapes with a boolean union in your design tool so there is only one outline, or switch to nonzero with matching directions. The guide on making a mono version of a colorful logo covers when the cut-out is the better choice.

Why an icon renders differently in two tools

When the same file looks filled in one place and hollow in another, the cause is usually one of these:

  • The rule is set in CSS, not as an attribute. A file that relies on style="fill-rule: evenodd" or a class in a <style> block depends on the importing tool parsing CSS. Some converters and importers only read attributes.
  • The rule is set on a parent group. fill-rule is inherited, so <g fill-rule="evenodd"> works in browsers, but a tool that flattens groups may drop it.
  • The tool assumes one rule. Some converters ignore fill-rule altogether. Font formats, for instance, rely on outline direction under a nonzero-style rule, so an SVG that depends on evenodd can come out of an icon font generator with filled holes.
  • An optimizer changed the structure. Merging paths or rewriting them can change how outlines combine. Compare before and after when you optimize.
  • Clip paths have their own rule. For <clipPath> content, the property is clip-rule, not fill-rule. A clip shape with a hole needs clip-rule="evenodd" or opposite directions.

Fixing an icon for good

  1. Find the subpaths. Each M (or m) in the d attribute starts a new subpath. A ring is two; a logo with several holes has more. SVG paths explained shows how to read them.
  2. Reverse the holes. Make every hole run opposite to the shape that contains it. Most vector editors have a "reverse path direction" command; with circular arcs written by hand, flipping the sweep flags from 0 to 1 (or back) reverses the direction, as in the example above.
  3. Or flatten with booleans. Subtract the hole from the shape, or unite overlapping shapes, using the design tool's boolean operations, then flatten. Tools typically output outlines whose directions already produce the intended holes.
  4. Put the attribute on the path. If you keep evenodd, set fill-rule="evenodd" directly on the <path>, not in CSS or on a group.
  5. Test in more than one renderer. Open the file in a browser, import it into your design tool, and run it through whatever pipeline it will face (PNG conversion, icon fonts, slides).

A file whose holes work under both rules is one less thing to debug later. If you want to make these edits in a text editor, editing an SVG by hand shows how to find and change the right attribute safely.

More in SVG

All guides