What is the best way to utilize a mask in an inline SVG that is compatible with Chrome browser?

I am looking to visually crop my element using an SVG shape that is defined within the same HTML file (inline SVG).

Using clip-path works perfectly:

div {
  width: 200px;
  height: 200px;
  background-color: red;
  clip-path: url("#c");
}
<div>
  <svg>
    <defs>
      <clippath id="c">
        <circle cx="100" cy="100" r="50" />
      </clippath>
    </defs>
  </svg>
</div>

However, when using a mask, Chrome does not apply any masking effect even though it works fine in Firefox:

div {
  width: 200px;
  height: 200px;
  background-color: red;
  mask: url("#m");
}
<div>
  <svg>
    <defs>
      <mask id="m">
        <circle cx="100" cy="100" r="50" fill="white" />
      </mask>
    </defs>
  </svg>
</div>

After researching (example), it appears that Chrome expects the mask to reference an entire image rather than a definition. Is there a way to refer to an entire image if it's been inlined? Or are there other methods I can try to apply a mask from an inline element?

Answer №1

Discover a creative JavaScript solution that may not be the most aesthetically pleasing but gets the job done:

  • Capture the content of your <mask>,
  • Replicate it in a new SVG element (Chrome thankfully doesn't require width and height),
  • Convert it to a data-URI and assign it to the -webkit-mask-image property.

const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
const mask = document.querySelector("mask");
svg.innerHTML = mask.innerHTML;
const markup = new XMLSerializer().serializeToString(svg);
const url = `data:image/svg+xml;charset=utf8,${ encodeURIComponent(markup) }`;
const div = document.getElementById('mask-me');
div.style.webkitMaskImage = `url('${ url }')`;
#mask-me {
  width: 200px;
  height: 200px;
  background-color: red;
  /**
    This will be overidden by -webkit-mask-image even in Firefox.
    We could have avoided it with a CSS variable, e.g
    -webkit-mask-image: var(--workaround-url);
    but Safari acts in all ways as if they did support inline SVG as mask,
    when they don't.
    So, for them, we have to use the workaround everywhere...
  mask-image: url(#m);
  **/
}
<div id="mask-me">
  <svg>
    <defs>
      <mask id="m">
        <circle cx="100" cy="100" r="50" fill="white" />
      </mask>
    </defs>
  </svg>
</div>


For those requiring the mask-mode: luminance function, you'll need to implement it manually within the generated SVG image using a

<feColorMatrix type="luminanceToAlpha"/>
:

const svgNS = "http://www.w3.org/2000/svg";
const svg = document.createElementNS(svgNS, "svg");

const alpha = document.createElementNS(svgNS, "feColorMatrix");
alpha.setAttribute("type", "luminanceToAlpha");
const filter = document.createElementNS(svgNS, "filter");
filter.setAttribute("id", "alpha");
filter.append(alpha);
svg.append(filter);

const g = document.createElementNS(svgNS, "g");
g.setAttribute("filter", "url(#alpha)");

const bg = document.createElementNS(svgNS, "rect");
bg.setAttribute("width", "100%");
bg.setAttribute("height", "100%");
g.append(bg);

var mask = document.querySelector('mask').cloneNode(true);
g.append(...mask.children);
svg.append(g);

const markup = new XMLSerializer().serializeToString(svg);
const url = "data:image/svg+xml;charset=utf8," + encodeURIComponent(markup);
const div = document.getElementById("mask-me");
div.style.webkitMaskImage = `url('${ url }')`;
.border {
  display: inline-block;
  border: 1px solid;
}
#mask-me {
  width: 300px;
  height: 200px;
  background-color: red;
  /** Safari doesn't really support mask-image using inline SVG either...
    mask-image: url(#m);
    mask-mode: luminance;
  **/
}
<div id="mask-me">
  <svg width="0">
    <defs>
      <mask id="m">
        <circle cx="100" cy="100" r="50" fill="white" />
        <rect x="90" y="90" width="20" height="20" fill="black" />
      </mask>
    </defs>
  </svg>
</div>

Answer №2

Recently, I discovered that Chrome does not currently offer full support for the mask property according to my findings. However, it does seem to support the use of mask-image. You can refer to this resource for more details: Browser Support - CSS Masks.

It appears that this is still the current situation regarding Chrome and the mask property.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the best way to animate elements so that they move in a circular motion?

My goal is to recreate the image shown in the picture: https://i.sstatic.net/z08II.jpg In case the image is blocked, you can view it here: https://i.sstatic.net/YYg4J.jpg The picture appears to have only one icon visible, but there are actually 4 icons. ...

Creating a dynamic multi-level menu within a hamburger menu

Tackling the challenge of creating a hamburger multi-level menu for a web page using CSS has proven to be quite tricky. The main issue I'm encountering is successfully incorporating a sub-menu to make it truly multi-level. Here's the progress I&a ...

Calling ASPX method remotely and receiving undefined data

I'm still fairly new to ASP.NET and web services. I've encountered an issue where I am calling a web service from a *.aspx page, and the web service is returning the correct output. However, when I call the *.aspx method from an external HTML pag ...

Ways to create a noticeable effect on an image button when hovering without causing a shift in the position

Check out my simple script here: http://jsfiddle.net/PA9Sf/ I am looking to make a specific button stand out when hovered over without affecting the position of other buttons on the page. The current implementation in the provided jsfiddle moves the butto ...

Exploring the height and overflow properties of nested div elements

Imagine a scenario where you have a fixed-size container and need all the elements to fit inside. The issue arises when some elements contain lots of text, causing the overflow to be hidden but still stretching beyond the container's height. How can t ...

Initiate the video tag playback by using jquery.play() function

Is there a way to make the video start playing as soon as the overlaying absolute div has faded out? I've tried using javascript and autoplay, but it doesn't seem to work without controls enabled. Any suggestions? Check out the HTML code below: ...

Header of table remains fixed as user scrolls through data, allowing for easy reference. The left

Above, I have utilized some code from another answer here to display a table. However, I am now contemplating the possibility of customizing it so that the first column remains fixed for horizontal scrolling. Currently, I'm employing the following as ...

Identifying Oversized Files on Safari Mobile: A Guide to Detecting Ignored Large Files in

Mobile browsers such as Safari have a tendency to ignore large files when passed in through the <input type="file">. For example, testing with a 10mb image file results in no trigger of any events - no change, no error, nothing. The user action is si ...

Creating a platform akin to YouTube for sharing videos online

Currently, I am in the process of creating a personalized website that bears similarities to YouTube. However, I am unsure about how to enable new pages and files on this platform. Despite being relatively new to HTML, I possess a basic understanding of co ...

After toggling the class, Jquery will no longer select the button

I am having an issue with my jQuery code where I have a button that, when clicked, should switch classes from #testButton to .first or .second. The image toggle shows that the first click works fine and toggles the image, but the second click does not seem ...

Incorporating text overlays on images that are compatible with responsive websites is a top priority for me

This is a piece of HTML code that utilizes bootstrap 3 for design purposes. The challenge faced is related to positioning text over an image. When resizing the browser, the alignment of the text with the background gets disturbed. Assistance is needed in r ...

What is causing JS to malfunction and preventing App Scripts from running `doGet()` when using either `e` or `event` as parameters?

Following a Basic Web App video last night, I meticulously followed every step until the very end where things started to go wrong. Today, I decided to start from scratch and recreate it all. Despite weeks of coding practice, I can't seem to figure ou ...

Attempting to display images in various formats using the Picture HTML element

Vue is being used to create a dynamic picture component, resulting in the following code: <picture style="display: contents;"> <source type="image/avif" sizes="700px" src ...

Alter the background image of a DIV based on the selected menu item

I am working on a project that involves a div element with the class "jumbotron" which currently has a background image applied to it. Additionally, I have a menu consisting of 6 items that I would like to interact with. My goal is to dynamically change ...

Position a dynamic <div> in the center of the screen

My goal is to design a gallery page with a list of thumbnails, where clicking on a thumbnail will open the related image in a popup div showing its full size. The issue I'm facing is how to center the popup div on the screen, especially when each pic ...

Issues with displaying AngularJs directive template

Having an issue with my AngularJs directive. Everything works perfectly fine when I use the "template" attribute, but when I switch to using "templateURL", it stops working. Both the JavaScript file for the directive and the HTML file for the template are ...

Is there a way to undo the transition when hovering out?

Is it possible to achieve a reverse transition animation on hover out using CSS? I want the "Menu" text to slide to the right blue line when I hover out, and after a delay of 400ms, slide back from the left grey line. Can this be done? .menu { displ ...

What is the best way to horizontally align my divs and ensure they stack properly using media queries?

My layout is not working as expected - I want these two elements to be side by side in the center before a media query, and then stack on top of each other when it hits. But for some reason, it's not behaving the way I intended. I've tried to ce ...

Tic Tac Toe is not functioning properly

Hey there! Can someone please help me figure out what's going on? I'm trying to create a Tic Tac Toe game, but instead of using "O" and "X" to mark the fields, I want to use different colors. Specifically, one player should be able to mark with b ...

Dynamic resizing in NextJs does not trigger a re-render

My goal is to dynamically pass the width value to a component's styles. Everything works fine on initial load, but when I resize the window, the component fails to re-render even though the hook is functioning as intended. I came across some informat ...