Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stroke SVG Path only inside or only outside

Tags:

html

css

svg

stroke

Consider 2 html svg paths , a square (class inside) and a rectangle (class outside) having same height. When I apply stroke-width: 10px, the stroke gets applied 5px inside and 5px outside. Fiddle

enter image description here

How do I stroke only inside or only outside?

.inside { 
  stroke: #333;
  stroke-mode: inside;     // property does not exist
  stroke-width: 5px;
}

.outside {
   stroke: #333;
   stroke-mode: outside;   // property does not exist
   stroke-width: 5px;
}

If there is no such property, is there a workaround to achieve something like:

enter image description here

like image 591
Saravanabalagi Ramachandran Avatar asked Jul 12 '19 13:07

Saravanabalagi Ramachandran


People also ask

What is stroke in SVG?

The stroke attribute is a presentation attribute defining the color (or any SVG paint servers like gradients or patterns) used to paint the outline of the shape; Note: As a presentation attribute stroke can be used as a CSS property. You can use this attribute with the following SVG elements: <altGlyph>

What is inner stroke?

An internal capsule stroke affects the tiny blood vessels deep within the brain. Because many crucial fibers pass through the internal capsule, even a small stroke in this area can result in a significant loss of motor control, sensation, or cognition.

What is stroke-width in SVG?

The stroke-width property in CSS is for setting the width of a border on SVG shapes. .module { stroke-width: 2; } Remember: This will override a presentation attribute <path stroke-width="2" ... /> This will not override an inline style e.g. <path style="stroke-width: 2;" ... />

How do I change the stroke-width in SVG?

You can add a stroke with stroke="black" stroke-width="10" and then adjust your viewBox accordingly.


1 Answers

The comment above by @enxaneta is exactly right.

Normally, where a filled rectangle is 48px wide and has a stroke with a stroke-width of 12px, the rectangle will display with:

  • a 12px wide border
  • an apparent width of 36px

Why 36px rather than 48px?

Because the 12px-wide stroke painted along the left side of the rectangle is obscuring 6px of the rectangle and the12px-wide stroke painted along the right side of the rectangle is obscuring 6px of the rectangle.

See this example where the stroke has 50% opacity - you can see that half of the stroke overlaps the fill:

svg rect {
  x: 10px;
  y: 10px;
  width: 200px;
  height: 100px;
  stroke: rgba(0, 0, 0, 0.5);
  stroke-width: 12px;
  fill: rgb(255, 0, 0);
}
<svg>
  <rect />
</svg>

Solution to create an Outer Border of 12px:

To create an Outer Border, the solution is to paint the stroke first and then paint the fill over the top.

We can achieve this using:

paint-order: stroke;

Now the rectangle will display with:

  • an apparent 6px wide border (because half the width of the 12px wide border is obscured by the fill painted over the top)
  • a width of 48px

svg rect {
  x: 10px;
  y: 10px;
  width: 200px;
  height: 100px;
  stroke: rgba(0, 0, 0, 0.5);
  stroke-width: 12px;
  fill: rgb(255, 0, 0);
  paint-order: stroke;
}
<svg>
  <rect />
</svg>

Finally, to ensure the rectangle displays with:

  • a 12px wide border
  • a width of 48px

change the stroke-width from 12px to 24px (i.e. double the intended display width):

svg rect {
  x: 10px;
  y: 10px;
  width: 200px;
  height: 100px;
  stroke: rgb(0, 0, 0);
  stroke-width: 24px;      /* double the intended display width */
  fill: rgb(255, 0, 0);
  paint-order: stroke;
}
<svg>
  <rect />
</svg>

Solution to create an Inner Border of 12px:

To create an Inner Border, we need three steps instead of two.

The first two steps are straightforward:

  • double the stroke-width (just as with the outer border)
  • use paint-order: fill (instead of paint-order: stroke)

svg rect {
  x: 10px;
  y: 10px;
  width: 200px;
  height: 100px;
  stroke: rgba(0, 0, 0, 0.5);
  stroke-width: 24px;      /* double the intended display width */
  fill: rgb(255, 0, 0);
  paint-order: fill;
}
<svg>
  <rect />
</svg>

The third step is to define and apply a <clipPath> which exactly duplicates the shape which is to have an Inner Border.

For instance, if the shape is:

<rect width="200" height="100" />

Then the <clipPath> should be:

<clipPath id="my-clip-path">
  <rect width="200" height="100" /> <!-- Same as the shape -->
</clipPath>

Working Example:

#my-rect {
  stroke: rgb(0, 0, 0);
  stroke-width: 24px;
  fill: rgb(255, 0, 0);
  paint-order: fill;
  clip-path: url(#my-clip-path);
}

#my-rect,
#my-clip-path-rect {
  x: 10px;
  y: 10px;
  width: 200px;
  height: 100px;
}
<svg>
  <defs>
    <clipPath id="my-clip-path">
      <rect id="my-clip-path-rect" />
    </clipPath>
  </defs>
  
  <rect id="my-rect" />
</svg>

All of the rectangles together:

svg {
  display: block;
  float: left;
  width: 220px;
  margin-left: 12px;
}

svg:nth-of-type(1) rect {
  x: 10px;
  y: 10px;
  width: 200px;
  height: 100px;
  stroke: rgba(0, 0, 0, 0.5);
  stroke-width: 12px;
  fill: rgb(255, 0, 0);
}

svg:nth-of-type(2) rect {
  x: 10px;
  y: 10px;
  width: 200px;
  height: 100px;
  stroke: rgba(0, 0, 0, 0.5);
  stroke-width: 24px;
  fill: rgb(255, 0, 0);
}

svg:nth-of-type(3) rect {
  x: 10px;
  y: 10px;
  width: 200px;
  height: 100px;
  stroke: rgb(0, 0, 0);
  stroke-width: 24px;
  fill: rgb(255, 0, 0);
  paint-order: stroke;
}

#svg3clip {
  width: 200px;
  height: 100px;
}

svg:nth-of-type(4) rect {
  x: 10px;
  y: 10px;
  width: 200px;
  height: 100px;
  stroke: rgb(0, 0, 0);
  stroke-width: 24px;
  fill: rgb(255, 0, 0);
  paint-order: fill;
  clip-path: url(#svg3clip);
}
<svg>
  <rect />
</svg>

<svg>
  <rect />
</svg>

<svg>
  <defs>
    <clipPath id="svg3clip">
      <rect />
    </clipPath>
  </defs>
  
  <rect />
</svg>

<svg>
  <rect />
</svg>

Further Reading:

  • https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/paint-order
  • https://developer.mozilla.org/en-US/docs/Web/CSS/paint-order
  • https://developer.mozilla.org/en-US/docs/Web/SVG/Element/clipPath
  • https://developer.mozilla.org/en-US/docs/Web/CSS/clip-path
like image 142
Rounin - Glory to UKRAINE Avatar answered Nov 15 '22 06:11

Rounin - Glory to UKRAINE