svg hover overlapping elements in Firefox - firefox

I have a svg with some circles that should get bigger on hover, here is a snippet
!This will not work in Firefox
var svgRoot = $('.svg-root')[0];
$('.bubble').mouseover(function (e) {
svgRoot.append(e.currentTarget);
});
circle{
transition: all 200ms;
}
circle:hover{
stroke: black;
fill: white;
transform: scale(3);
}
.svg-root svg{
overflow: visible;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<svg class="svg-root">
<svg class="bubble" x="50" y="50">
<circle r="10"></circle>
</svg>
<svg class="bubble" x="70" y="70">
<circle r="10"></circle>
</svg>
<svg class="bubble" x="90" y="50">
<circle r="10"></circle>
</svg>
</svg>
To avoid the other circles overlapping the one the mouse is currently hovering over, I used the append trick. That solves the z-index Problem, but it causes a different one. It seems that after appending the node, Firefox does not recognize the hover state of the cursor. The circles will not scale on hover in Firefox, but they will in Chrome.
I need them to scale on hover and to have the highest z-index while doing so.
Any solutions?

Related

d3.js - style function doesn't change the font color [duplicate]

Okay... I'm going nuts over here. I've started experimenting with SVG. Working with SVG and applying CSS classes to it works like a charm. I just cant figure out what i'm doing wrong, but i just cant get the class to work on a svg text element. I've stripped it all the way down and this is what i got:
<!DOCTYPE html>
<html>
<head>
<meta charset='UTF-8'>
<title>Playground</title>
</head>
<body>
<style type="text/css">
.mainsvg {
height: 320px;
border: 1px solid red;
width: 400px;
}
.caption {
color: yellow;
}
</style>
<h2>SVG - Sandbox</h2>
<div>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" class="mainsvg">
<text x="65" y="40" class="caption">Fact</text>
</svg>
</div>
</body>
</html>
According to http://www.w3.org/TR/SVG/styling.html#ClassAttribute this should work...
Any hints/tips on what to change, or an alternative?
Setting the class is correct but the CSS color property has no effect on SVG. SVG uses fill and stroke properties. In your case you probably just need to change color to fill. This displays yellow text for me in Firefox.
<!DOCTYPE html>
<html>
<head>
<meta charset='UTF-8'>
<title>Playground</title>
</head>
<body>
<style type="text/css">
.mainsvg {
height: 320px;
border: 1px solid red;
width: 400px;
}
.caption {
fill: yellow;
}
</style>
<h2>SVG - Sandbox</h2>
<div>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" class="mainsvg">
<text x="65" y="40" class="caption">Fact</text>
</svg>
</div>
</body>
</html>
This is the top Google result for coloring SVG text and to make it very clear for rookies like me, to color an SVG text element in 2022, use stroke, and fill.
fill="red"
stroke="#0000FF"
Just like you use stroke for the outline color and fill for the inside color of a shape, you can do the same thing for text in SVGs.
And the best news is, if you use fill="currentColor" instead of a hard coded color, you can set the SVG text with CSS.
svg {
color: red;
}
Click run code snippet to see an example right in this answer.
<svg height="202" width="202">
<circle cx="101" cy="101" r="100"
stroke="red"
stroke-width="1"
fill="none"
/>
<!-- fill="currentColor" if you want to use CSS to set the color of SVG text -->
<text x="100" y="100"
text-anchor="middle"
fill="red"
stroke="#0000FF"
stroke-width="1px"
alignment-baseline="middle"
font-variant="all-small-caps"
font-size="25"
font-weight="bold"
>
Font is Colored
</text>
The accepted answer doesn't work for me either, so I did more research, and found a solution.
If you wrap the SVG <text .../> element in an <g .../> (group) element it can work:
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" class="mainsvg">
<g class="caption">
<text x="65" y="40" fill="currentcolor">Fact</text>
</g>
</svg>
This applies the CSS to the <g>, and then the <text> element inherits the currentcolor of the parent into its fill (or stroke).

Clicking On-or-Through Image is Browser-Dependent

I have found a difference between how Firefox and Chrome handle clicking near an image that I need to fix. I have a rect with an image occupying roughly the top 65%. I preserve the aspect ratio of the image and so it appears narrower than the full rect, which is perfect for what I need.
However, when I click near to the image, in the margin space either side of it, Firefox says I have clicked on the rect whereas Chrome says that I have clicked on the image. Inspecting the elements, I see that the image element spans the full width of the rect in both cases, but it is the functionality in Firefox that I need (as though I'm clicking "through" those image margins).
This is better explained with an example. The code below shows one rect and a narrow image in the top 65%. If I click either side of the image in Firefox, it says that the event.target.nodeName is "use" (I have the rect in a <g>) whereas Chrome says it is "image".
function clickHandler(ev) {
ev = ev || window.event;
alert (ev.target.nodeName);
}
text {
text-anchor: middle;
font-size: 10px;
font-weight: bold;
font-family: "Times New Roman";
pointer-events: none;
}
.m {
stroke: dimgray;
stroke-opacity: 1.0;
stroke-width: 1.5;
fill-opacity: 1.0;
fill: white;
}
<svg id="TreeTest" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<g id="G-Box">
<rect width="80" height="80" rx="5" ry="5"/>
</g>
</defs>
<g id="HenryProctor">
<use tabindex="0" xlink:href="#G-Box" class="m" x="50" y="50" onclick="clickHandler(evt);">
</use>
<text x="90" y="106" dy="1em">Henry</text>
<text x="90" y="106" dy="2em">Proctor</text>
<image x="52.5" y="52.5" width="75" height="51.5" xlink:href="https://parallaxviewpoint.com/Images/Proctor_Henry_b1833.jpg" preserveAspectRatio="xMidYMin meet" onclick="clickHandler(evt);">
</image>
</g>
</svg>
Is there a way to detect when the click was only on the visible part of the image?
[Edited for clarification] I need to distinguish between a click on the visible image and a click anywhere else in the rect. I have my event handler on both, but the action it takes depends on knowing what the user clicked on.
That difference is an interesting quirk that I hadn't noticed before.
Although Firefox's behaviour seems the most useful in this case, I think that Chrome's behaviour follows the spec more accurately. The blank areas on each side of the image are still technically part the "fill" of the <image> element. So clicking there probably should return the "image".
Do you care whether the user clicks on the visible part of the image, or the blank areas beside it? If not, then you could just tell the browser to ignore all click events on the <image> element using:
pointer-events="none"
Now when you click anywhere on the image, in Chrome, you get "use".
function clickHandler(ev) {
ev = ev || window.event;
alert (ev.target.nodeName);
}
text {
text-anchor: middle;
font-size: 10px;
font-weight: bold;
font-family: "Times New Roman";
pointer-events: none;
}
.m {
stroke: dimgray;
stroke-opacity: 1.0;
stroke-width: 1.5;
fill-opacity: 1.0;
fill: white;
}
<svg id="TreeTest" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<g id="G-Box">
<rect width="80" height="80" rx="5" ry="5"/>
</g>
</defs>
<g id="HenryProctor">
<use tabindex="0" xlink:href="#G-Box" class="m" x="50" y="50" onclick="clickHandler(evt);">
</use>
<text x="90" y="106" dy="1em">Henry</text>
<text x="90" y="106" dy="2em">Proctor</text>
<image x="52.5" y="52.5" width="75" height="51.5" xlink:href="https://parallaxviewpoint.com/Images/Proctor_Henry_b1833.jpg" preserveAspectRatio="xMidYMin meet" onclick="clickHandler(evt);"
pointer-events="none">
</image>
</g>
</svg>
SVG content is in shadowDOM, so you can use evt.composedPath() to get the whole Event path.
evt.composedPath()[0] is the Element you clicked.
SO snippets have some delay issues with this; outputting errors in the console, and after a minute the wrong info in the attached SO snippet console.
Update
Argh! OP wants IE support (its 2021, even Microsoft says not to use IE)
For those who want a modern solution with native Web Components, where the IMG is read, and its naturalWidth and naturalHeight are used to generate SVG from a Template
See JSFiddle: https://jsfiddle.net/WebComponents/qv1n9khf/
<person-card img="https://www.gravatar.com/avatar/..."></person-card>
<person-card img="https://www.gravatar.com/avatar/..."></person-card>

Part of SVG changing in animation on hover

Included here is an image of the svg file (could not upload svg file)
I would like to hover mouse over, and radiantly change background (to blue) only of the circle, from the inner circle to the edges, as an animation.
Even better if the animation was kind of wobbling effect from the middle of the circle and outwards. Nice if it was kind of "random" looking, the blue wobbling effect. Important it's animating from the middle of the circle, out towards the edge until the whole circle is blue.
When mouse/hover is removed then the animation is backwards.
Is that possible in svg/css land and can someone point towards the right direction?
This is a slightly hacky way to do it, using a blue circle with a black stroke that starts so thick it fills its interior. Hovering over the circle causes the stroke to shrink to nothing.
.logo-background {
fill: blue;
stroke: black;
stroke-width: 200;
transition: stroke-width 500ms;
}
.logo-background:hover {
stroke-width: 0;
}
.logo {
fill: none;
stroke: white;
stroke-width: 5;
pointer-events: none;
}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 200 200" height="100px">
<defs>
<clipPath id="circle-clip">
<circle cx="100" cy="100" r="100" />
</clipPath>
</defs>
<circle class="logo-background" cx="100" cy="100" r="100" clip-path="url(#circle-clip)" />
<rect class="logo" x="60" y="60" width="80" height="80" rx="5" ry="5"/>
</svg>

animated svg mask doesn't work in firefox

h1 everyone, i'm trying to make a cross-browser animation based on svg mask for svg elements. At first, I caught a bug with css, in firefox mask doesn't work with css 'width' and 'height', only with inline properties. So, next question - how to animate mask for firefox, nothing harder that 'width resize'. https://codepen.io/flyby/pen/KmYOgb
<div id='cont'>
<svg>
<defs>
<mask id='rectMask' maskUnits='userSpaceOnUse' maskContentUnits='userSpaceOnUse' transform='scale(1)'>
<rect x='0' y='0' id='maskRect' width='700' height='850'/>
</mask>
</defs>
<path id='maskedPath' d='m 0,0 l 650,0 -100,850 -550,0 z' mask='url(#rectMask)'/>
<path id='riverPath' d='m 653,0 l -100,850' mask='url(#rectMask)'/>
<path id='notMaskedPath' d='m 655,0 l 650,0 0,850 -750,0 z'/>
</svg>
</div>
CSS:
body {
margin:0;
padding:0;
overflow:hidden;
}
#cont {
width:100vw;
height:100vh;
background-color:rgb(50,50,50);
}
svg {
width:100%;
height:100%;
}
#maskedPath {
stroke:none;
fill:rgb(230,230,230);
}
#notMaskedPath {
stroke:none;
fill:rgb(230,230,230);
}
#riverPath {
stroke:rgb(50,160,240);
stroke-width:8;
fill:none;
}
#maskRect {
width:0px;
height:850px;
fill:white;
stroke:none;
animation: resize 3s linear infinite;
}
#-moz-keyframes resize {
50% {width: 700px !important;}
0%,100% {width: 0px !important;}
}
Like you have discovered, your can't (yet) set geometric properties, like width and height of SVG elements in Firefox. It's not a bug. It's just an SVG 2 thing that Firefox has not implemented yet, but Chrome has.
The solution is to use the built-in SVG ("SMIL") animation elements, instead of CSS animation.
body {
margin:0;
padding:0;
overflow:hidden;
}
#cont {
width:100vw;
height:100vh;
background-color:rgb(50,50,50);
}
svg {
width:100%;
height:100%;
}
#maskedPath {
stroke:none;
fill:rgb(230,230,230);
}
#notMaskedPath {
stroke:none;
fill:rgb(230,230,230);
}
#riverPath {
stroke:rgb(50,160,240);
stroke-width:8;
fill:none;
}
#maskRect {
fill:white;
stroke:none;
}
<!--this animation doesn't work in FIREFOX, and not tested in IE11 ad Edge YET, WILL BE FIXED SOON (I HOPE)-->
<div id='cont'>
<svg>
<defs>
<mask id='rectMask' maskUnits='userSpaceOnUse' maskContentUnits='userSpaceOnUse' transform='scale(1)'>
<rect x='0' y='0' width="0" height="850" id='maskRect'>
<animate attributeName="width"
keyTimes="0; 0.4; 0.5; 1"
values="0; 670; 670; 0"
dur="4s" repeatCount="indefinite"/>
</rect>
</mask>
</defs>
<path id='maskedPath' d='m 0,0 l 650,0 -100,850 -550,0 z' mask='url(#rectMask)'/>
<path id='riverPath' d='m 653,0 l -100,850' mask='url(#rectMask)'/>
<path id='notMaskedPath' d='m 655,0 l 650,0 0,850 -750,0 z'/>
</svg>
</div>

Unable to utilize the :not CSS selector around SVGs in Firefox [duplicate]

I can't seem to figure out why Firefox is using the default svg fill color instead of the class's fill.
Here are the 3 fills when viewing the FF inspector:
SVG is being inserted via
<svg class="icon">
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#menu-bag"></use>
</svg>
It should be showing the .skip-link .icon fill of white (#fff) but it's actually using the SVG fill of #002649; If i change .skip-link .icon to .skip-link svg then it works fine. Why can I not use a class and instead but explicitly state the element??
Am I missing something obvious about how Firefox fills an SVG? This CSS works fine in other browsers.
If the behavior was unique to Firefox prior to version 56, it was because #menu-bag refers to a <symbol> element.
The specs say that a re-used <symbol> should be implemented as if it were replaced by a nested <svg>. Firefox used to treat this literally in their shadow DOM. The shadow DOM isn't visible in your DOM inspector, but it is subject to CSS selectors.
Which means that this code:
<a href="#" class="skip-link">
<svg class="icon">
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#menu-bag"></use>
</svg>
</a>
WAs implemented like this:
<a href="#" class="skip-link">
<svg class="icon">
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#menu-bag">
<!--Start of shadow DOM boundary-->
<svg><!-- replacement for <symbol> -->
<!-- graphics content -->
</svg>
<!--End of shadow DOM boundary-->
</use>
</svg>
</a>
The svg.icon matches your .skip-link .icon rule (and as Kyle Mitt points out, that rule will always take precedence over your a:hover svg rule). This value is also inherited by the <use> element.
However, the shadow-DOM <svg> doesn't get the inherited value, because it is styled directly with the svg rule. When you change your selector to .skip-link svg, or when you trigger the a:hover svg rule, then the hidden inner element gets the style directly applied because that SVG is also a descendent of the link.
As Robert Longson noted in the comments, this is not how it is supposed to work. It's a side effect of the way that Firefox implemented <use> elements as complete cloned DOM trees, which just happened to be hidden from your DOM inspector.
Here's a "working" example of your original problem. Which is to say, on Chrome, Safari, Opera, Firefox 56+ or IE you will see a green circle that isn't altered when you hover it, but on Firefox prior to version 56 you will see a blue circle that turns red on hover/focus.
svg {
fill: navy;
}
a:hover svg, a:focus svg {
fill: red;
}
.skip-link .icon {
fill: green;
}
.icon {
height: 50;
width: 50;
}
<a href="#" class="skip-link">
<svg class="icon">
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#menu-bag" />
</svg>
</a>
<svg height="0" width="0">
<symbol id="menu-bag" viewBox="-10 -10 20 20">
<circle r="10" />
</symbol>
</svg>
So what to do you if you need to support old versions of Firefox? You have two options, one of which you've already figured out by trial and error:
Avoid setting default styles using the svg tag selector, and rely on normal style inheritance from the <use> element.
Use selectors that intentionally select the shadow-<svg> to cancel out the defaults, while also making sure that they have the intended effect on other browsers.
One option would be to use a rule like the following, which would maintain the specificity of your original rule for other browsers:
.skip-link .icon, .skip-link .icon use>svg {
fill: green;
}
The use>svg selector will never match anything except with the Firefox bug, so it is safe to use without side effects. (Originally, I'd just suggested adding svg to the end of the selector, but that could be problematic in certain situations.)
A more universal option based on the answer #AmeliaBR provided, is to simply do something along the lines of:
svg use svg {
fill: inherit;
}
which will make the shadow element inherit the fill color.
Robert is correct that <use> is not always applied consistently. Certainly when you use an SVG as an image, it doesn't know how to apply any of the CSS rules you've added to your page.
But there are a lot of other things here as well that could decide the element's style so an example might be helpful.
Here's a stack snippet to center our discussion.
svg {
fill: blue;
}
a:hover svg {
fill: red;
}
.skip-link .icon {
fill: purple;
}
.green {
fill: green;
}
<a href="#" class="skip-link">
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="icon" >
<def>
<text id="text" >use xlink</text>
<text id="over" class="green">use xlink override</text>
</def>
<text x="5" y="15" >Plain</text>
<use x="5" y="30" xlink:href="#text" />
<use x="5" y="50" xlink:href="#over" />
<text x="5" y="65" class="green" >class="green"</text>
<text x="5" y="80" fill="orange" >fill="orange"</text>
</svg>
</a>
Specificity
The SVG element itself is being styled with several conflicting rules. What determines which rule wins has to do with [specificity and order]. In this case, the SVG element itself will end up purple. The hover anchor rule, for example, will never show up because it is less specific than .skip-link .icon
Inheritance
Some properties allow for inheritance from their parents, but only when not specified themselves. Any specifications will override the inherited value. If the question is, my <svg> element has a certain style, why isn't it being applied to all child elements equally, the answer is simple. It's perfectly fine for child elements to specify their own value and override the inherited one.
<text x="5" y="65" style="fill:green;" >class="green"</text>
<text x="5" y="80" fill="orange" >fill="orange"</text>
Use & Xlink
The tricky part becomes what happens when use is involved. In this case, it can be hard to trace the actual styles being applied. Use will create an inline representation of the element identified by the xlink attribute, but you cannot access this element directly. Therefore, selecting use in the developer tools will only reveal the styles applied to the parent of the element. The element itself may override the inherited properties and we'd have no way of observing it in the dev panel.
Here, for example, the style applied to use is inherited from the parent. In the developer tools, it appears that the winning rule is purple, but this is only because it hasn't taken into consideration the element being pulled in. This is a soft value that can be overridden if the element specifies any value.
But the full set of selectors for the inlined text would actually look like this:
Specific Situation
One thing I'd suggest in the future is providing runnable code that other people can use to easily reproduce the issue as it saves a lot of extra debugging time. However, here's what I suspect is happening with your exact situation:
svg {
fill: #002649;
}
a:hover svg {
fill: #8A8B8C;
}
.skip-link .icon {
fill: #FFF;
}
<a href="#" class="skip-link">
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="icon" >
<def>
<svg xmlns="http://www.w3.org/2000/svg" id="menu-bag">
<rect height="100" width="100" />
</svg>
</def>
<use xlink:href="#menu-bag" />
</svg>
</a>
Set your default svg fill color on the body or html tag and it will be inherited as a default, but you can easily override it using just a class.
body {
fill: black;
}
.green {
fill: green;
}
.red {
fill: red;
}
Now just use the color class anywhere to change the fill color. Add the color class to the svg, or to a span or other element wrapping the svg. Works in Firefox too.
<a href="#" class="skip-link green">
<svg>
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#menu-bag" />
</svg>
</a>
<svg height="0" width="0">
<symbol id="menu-bag" viewBox="-10 -10 20 20">
<circle r="10" />
</symbol>
</svg>
My case is not exactly the same, but I share it anyway.
I´m using svg as a background image, like the example below (googled for it, don´t remember where). And in Firefox had problems with the "fill" color.
As the fill value, I had to write it in RGB mode and worked properly (fill:rgb(237, 237, 237);).
If I wrote in in HEX (fill:#ededed;), it wouldn´t render.
If I wrote for example "fill: blue;" it would also show properly.
.a-class {
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 10' preserveAspectRatio='none' height='130' style='background:var(--main-lt-green); fill:rgb(237, 237, 237);'><polygon points='100 0 100 10 0 10'></polygon></svg>");
background-repeat: no-repeat;
background-size: 100% 100px;
background-position-y: top;
margin-top: -100px;
padding-top: 100px;
}
what fixed it for me was adding the following css globally:
svg, symbol, defs {
fill: inherit;
}
then you can set your svg's fill and it will apply.

Resources