Center an element of a SVG mask

1.8k Views Asked by At

I'm a newbie in SVG so it's probably an easy question. I'm trying to make an SVG Mask with a simple triangle shape inside a rectangle. What I want to achieve is to get the rectangle responsive with his width but the triangle should - get a fixed size - be always at the center of the viewport

You'll understand better with my snippet:

.header-arrow {
  height: 70px;
}
svg {
  height: inherit;
}
#arrow-down-alpha {
  transform: translateX(calc(50vw - 130px/2));
}
<div class="header-arrow">
  <svg width="100%">
    <defs>
      <mask id="myMask" x="0" y="0" width="100%" height="100%">
        <rect fill="white" x="0" y="0" width="100%" height="100%" />
        <polygon id="arrow-down-alpha" fill="black" x="00" y="0" width="165px" height="100%" points="55.91 37.8 111.81 0 0 0 55.91 37.8" />
      </mask>
    </defs>

    <rect id="base-mask" mask="url(#myMask)" x="0" y="0" width="100%" height="100%" />
  </svg>
</div>

It's workning right now in chrome, but the translateX (or translate) is not working in firefox and edge. I've tried to use the transform SVG attribute but it seems that I can't use percentages values. I'm not realy familiar with the viewbox but I'm not sure it will help in this case.

Thanks anyway for any kind of help !

1

There are 1 best solutions below

1
On

Here's one way to achieve what you want without relying on new units or calc(). It should be cross-browser compatible also.

How it works:

  1. We wrap the triangle in a nested SVG. We use an SVG because it has an x attribute which can take percentages.

  2. We position this nested SVG at x="50%". It is now centred in the mask (roughly, see next step).

  3. We move the triangle shape so it is centred at x=0. That's so that it is not offset from the centre of the mask.

  4. We set overflow="visible" on the nested SVG so the part of the triangle that is now off the left of the SVG (ie. x < 0) are not clipped.

.header-arrow {
  height: 70px;
}
svg {
  height: inherit;
}
<div class="header-arrow">
  <svg width="100%">
    <defs>
      <mask id="myMask" x="0" y="0" width="100%" height="100%">
        <rect fill="white" x="0" y="0" width="100%" height="100%" />
        <svg x="50%" overflow="visible">
          <polygon fill="black" points="0 38 56 0 -56 0" />
        </svg>
      </mask>
    </defs>

    <rect id="base-mask" mask="url(#myMask)" x="0" y="0" width="100%" height="100%" />
  </svg>
</div>