Clip-path using inline SVG clipping wrong elements when position:absolute - css

This is a little hard to explain, so here's a jsFiddle to show what I mean.
<style>
.clip {
clip-path: url(#clippath);
-o-clip-path: url(#clippath);
-moz-clip-path: url(#clippath);
-webkit-clip-path: url(#clippath);
}
</style>
<div id="container">
<svg>
<defs>
<clippath id="clippath">
<rect x="0" y="0" width="50" height="320" />
</clippath>
</defs>
</svg>
<div id="d1">Bottom</div>
<div id="d2" class="clip">Middle</div>
<div id="d3">Top</div>
</div>
The problem is that I want to apply a clip-path to an absolutely positioned element, however I am finding that all other absolutely positioned elements which appear after it in the DOM will be clipped too. This isn't the case with relatively positioned elements, oddly.
How can I make sure that only the desired element is clipped? I can't see anything wrong with my code. Is this a bug?

This now behaves correctly in all browsers I've tested aside from Internet Explorer (which lacks support for clippath on HTML elements entirely), and as such it's no longer a problem.

Related

Custom SVG shape clip path image

Been trying to work this out but have wasted so much time I think its best for me to just ask.
The objective is to have custom (responsive) shapes - which house an image (example below):
I've followed some online sources and have managed to get this (kinda) working with:
SVG custom path and clip-path
<header>
<h1><span class="text-shadow">Hiking</span><br>
<span class="text-shadow">The Pinicles</span><br>
<span class="text-shadow">NZ</span></h1>
<svg width='0' height='0'>
<defs>
<clipPath id='clipper'>
<path d="M0 830.5V0.500008H514C514 0.500008 575.5 0.500008 632.5 146.5C689.5 292.5 239.5 646.667 0 830.5Z" fill="#C4C4C4"/>
</clipPath>
</defs>
</svg>
<img class="headerIMG" src="/ASSETS/IMG/blog-images/mountain.JPG" alt="">
And applying the clip path to the image:
img.headerIMG {
clip-path: url(#clipper);
}
Result:
What I am trying to do and failing at is:
moving the IMG to position it so that a different part of the photo is showing (not the top left)
resizing the SVG clip path so it could be 100vh or 50vh depending on the media query used.
Any help here would be great and please feel free to ask any questions you might have to better understand what I am trying to do.
There are a few different ways to move the image independently from the clip path. But they boil down to applying the clip to a parent element, so you can move the image around within it.
For example
<div class="headerIMG-container">
<img class="headerIMG" src="/ASSETS/IMG/blog-images/mountain.JPG" alt="">
</div>
.headerIMG-container {
clip-path: url(#clipper);
}
.headerIMG {
transform: tarnslate(0, -100px);
}
or something like
<div class="headerIMG></div>
.headerIMG {
clip-path: url(#clipper);
background: url(/ASSETS/IMG/blog-images/mountain.JPG) no-repeat;
background-position: 0px 100px;
}
or do it all in the SVG
<svg width="400" height="300">
<defs>...clip...</defs>
<g clip-path="url(#clipper)">
<image class="headerIMG" xlink:href="/ASSETS/IMG/blog-images/mountain.JPG" width="???" height="???" transform="translate(0, -100)"/>
</g>
</svg>

css clip-path with svg not working in Chrome

I've created an svg for use as a clip-path on an image, and it appears perfect in Firefox, however it doesn't work in Chrome, and I'm wondering what the problem is.
Chrome should support an inline svg clip-path according to this.
And full support according to MDN.
<style>
img {
width: 40%;
height: auto;
display: inline;
}
.clip {
-webkit-clip-path: url('#clip');
clip-path: url('#clip');
}
</style>
<p>Left image should be clipped, right image is not.</p>
<img src="https://i.imgur.com/nnHdzO6l.jpg" class="clip">
<img src="https://i.imgur.com/nnHdzO6l.jpg" >
<svg version="1.1"
baseProfile="full"
height="400" width="400"
xmlns="http://www.w3.org/2000/svg">
<defs>
<clipPath id="clip"
clipPathUnits="objectBoundingBox"
transform="scale(0.0025, 0.0025)">
<!-- https://css-tricks.com/scaling-svg-clipping-paths-css-use/ -->
<circle cx="50%" cy="50%" r="50%" />
<rect width="82.8%" height="82.8%" y="17.2%" x="8.6%" />
</clipPath>
</defs>
</svg>
External SVG files are not supported by Chrome at the moment.
You can check this here:
https://caniuse.com/#search=CSS%20clip
Here is what they say about the Partial support for Chrome:
Partial support refers to supporting shapes and the url(#foo) syntax
for inline SVG, but not shapes in external SVGs.

How to make overflow-ed SVG content viewable via scrolling?

I have this simple HTML:
<html>
<body>
<embed src="test.svg" type="image/svg+xml" style="border:3px solid green;width:200px;height:200px;overflow:scroll;">
</body>
</html>
And a simple SVG:
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" style="border:3px solid red;width:500px;height:500px;overflow:auto;">
<circle cx="50" cy="250" r="80" stroke="green" stroke-width="4" fill="yellow" />
</svg>
The output from browsers:
[1,1] Edge: OK
[2,1] IE11: OK
[1,2] Chrome55: Not scrollable
[2,2] Firefox50: Scrollable at a negligible degree
How to ensure Firefox and Chrome able to have scrollable <embed> with overflow-ed SVG content, as in Edge and IE?
Thank you.
just put a div around the embed und use that as scrolling area...
<html>
<body>
<div style="border:3px solid green;width:100px;height:100px;overflow:scroll;">
<embed src="https://upload.wikimedia.org/wikipedia/commons/e/e9/SVG-Grundelemente.svg" type="image/svg+xml">
</div>
</body>
</html>
to match the behaviour of MS browsers, you have to extend your viewBox to contain all elements you want to be able to scroll to...
given the appropiate width and height should do want you want then...
You can as well roll your own zoom and pan solution using svgDocuments currentTranslate and currentScale properties... I would be curious how currentTranslate behaves for this weird MS behaviour...

Custom CSS shape with borders and background image

Hi guys im trying to do this in css/sass only! The border have to change on rollover and the background could be an image! I tried SVG and clipPath, transform3d without any success!Example here
Create the container div and use transforms in CSS to give the entire element the 3d effect. You can look this up and play with the values to your liking.
Make the background image the background of the container div to keep it simple.
Use an SVG to draw the controller icon. There are some tutorials out there on how to export a path for an SVG using GIMP, at least that is what I do for complicated shapes like this.
Ok, this is best done like this, first the html structure:
<div id="imageContainer" class="center">
<h2>Lets go and see how it goes</h2>
<img class="pic" src="https://moltopiccolo.files.wordpress.com/2012/01/cool- drinks.jpg">
</div>
This means, you have a container div and place your img in that container, it is important to not have the img as div background in this instance.
Second, position the div relative, the image absolute.This will only work if the image is positioned absolute.
Now declare a clip path, there are generators for different shapes with previews etc, check the codepen for the correct declarations.
Give a transition to the clip path, make sure to use the prefixes.
Now it is up to you wheter you want to trigger the animation on hover, this can be done with css. If you want the animations triggered on click, you can do that in JS and change the clip paths with JS.
I think the border animation needs no explanation, this is the very easiest part, if you need help with that, let me know.
Here is the link, hover over the picture and see:-)
http://codepen.io/damianocel/pen/KdobyK
There is the workaround that we found. It will need some adjustement but look good for our need!
<a href="">
<svg class="stroke-path" height="100%" width="100%">
<defs>
<pattern id="img1" patternUnits="userSpaceOnUse" width="100%" height="100%">
<image xlink:href="http://cdn.collider.com/wp-content/uploads/super-mario-bros.jpg" x="0" y="0" width="100%" height="100%" />
</pattern>
</defs>
<path id="mlp2" d="M206.5,173.1L33.3,162.5c-6.3,0-11.4-5.1-11.3-11.4c0,0,0,0,0,0L10.5,39.8c0-6.3,5.1-11.4,11.3-11.4 c0,0,0,0,0,0l208.2-17.9c6.3,0,11.4,5.1,11.3,11.4c0,0,0,0,0,0l-23.6,139.8C217.8,168,212.8,173.1,206.5,173.1 C206.5,173.1,206.5,173.1,206.5,173.1z" fill="url(#img1)" fill-opacity="1" />
</svg>
<svg class="" height="100%" width="100%">
<defs>
<filter id="f1" x="0" y="0" width="200%" height="200%">
<feOffset result="offOut" in="SourceGraphic" dx="0" dy="0" />
<feGaussianBlur result="blurOut" in="offOut" stdDeviation="8" />
-->
http://codepen.io/anon/pen/vXBPOz

SVG Fill not being applied in FireFox

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