Home > OS >  Defining `marker-end` completely using CSS
Defining `marker-end` completely using CSS

Time:04-04

MDN says you can use CSS to define a marker-end value for an SVG <path>, but all the examples use a url(#...) syntax which refers to an existing element in the drawing.

Is it possible to define a marker completely inside the CSS, such that by changing a stylesheet it can change the marker style to a completely different shape? As in, one that wasn't already defined in the image?

Or would I have to include all these options inside the image itself, and the CSS can only choose which one it uses?

(I tried a few data: URL solutions, didn't work for me.)

CodePudding user response:

It's not completely impossible, but there are some obstacles. You can style the marker shape with CSS, but not by changing the style of the path that uses the marker. You need to change the style of the marker definition itself. Consequently, you would need a unique marker for every path you want to decorate, otherwise all elements referencing the same <marker> would change at once.

Also you can only change the presentation attributes of the content of the <marker> element. Its own attributes (markerWidth, markerHeight, refX, refY, orient) are all XML, not presentation attributes. But you can change the marker shape. One strategy might be to define multiple shapes, and set all of them to display: none save the one you currently want to show.

Or, since now Chrome and Firefox have implemented the d property in CSS, you can also redefine a shape like this:

svg {
    width: 200px;
    display: block;
}
input ~ svg #marker {
    --shape: path('M2,2 H8 V8 H2 z');
    --color: green;
}
input:checked ~ svg #marker {
    --shape: path('M5,0 10,5 5,10 0,5 z');
    --color: red;
}
#marker path {    
    d: var(--shape);
    fill: var(--color);
}
#usage {
    stroke: black;
    marker-end: url(#marker);
}
<input id="switch" type="checkbox"> <label for="switch">Switch marker</label>
<svg viewBox="0 0 30 30">
  <marker id="marker" viewBox="0 0 10 10" orient="auto"
          markerWidth="6" markerHeight="6" refX="5" refY="5">
     <path />
  </marker>
  <path id="usage" d="M5,18 25,12" />
</svg>

Lokking at this pattern, you might be tempted to compare it to the way you can inherit CSS custom properties inside the shadow DOM by setting them on <use> elements. Alas, this does not work for referenced markers:

svg {
    width: 200px;
    display: block;
}
input ~ svg #usage {
    --shape: path('M2,2 H8 V8 H2 z');
    --color: green;
}
input:checked ~ svg #usage {
    --shape: path('M5,0 10,5 5,10 0,5 z');
    --color: red;
}
#marker path {    
    d: var(--shape);
    fill: var(--color);
}
#usage {
    stroke: black;
    marker-end: url(#marker);
}
<input id="switch" type="checkbox"> <label for="switch">Switch marker</label>
<svg viewBox="0 0 30 30">
  <marker id="marker" viewBox="0 0 10 10" orient="auto"
          markerWidth="6" markerHeight="6" refX="5" refY="5">
     <path />
  </marker>
  <path id="usage" d="M5,18 25,12" />
</svg>

CodePudding user response:

Here's a marker encoded as a data URL.

It works on Firefox but it seems Chrome still doesn't support external markers.

<svg viewBox="0 50 120 120" xmlns="http://www.w3.org/2000/svg">
  <polyline fill="none" stroke="black"
      points="40,60 70,80" marker-end='url(data:image/svg xml,#triangle)'/>
</svg>

  • Related