Show scrollbars if SVG elements overflows their container - svg

I have an embedded SVG with dynamic content inside, which may grow in all directions.
This content may be grow bigger than the fix sized container around.
My expected behavoir is, to show scrollbars, if any element inside the SVG needs more place than the container provides.
See the following simplified example:
<html>
<head>
</head>
<body>
<div style="overflow: auto; position: absolute; top: 60px; left: 60px; background-color: gray; height: 200px; width: 300px;">
<svg style="height: 190px;">
<rect x="-50" y="0" width="100" height="50" fill="red"></rect>
</svg>
</div>
</body>
</html>
What is the way to do this?
Is it really true, there is no concept in SVG to support such behavoir?
Any suggestions how to do it right "by hand"?

Svg does'nt support auto resizing to inside elements of itself.
So, you should resize manually the svg graphic to be able to scroll by outer svg element.
var svg = document.querySelector("svg");
var bbox = svg.getBBox();
svg.setAttribute("viewBox", [bbox.x, bbox.y, bbox.width, bbox.height]);
svg.width.baseVal.valueAsString = bbox.width;
svg.height.baseVal.valueAsString = bbox.height;

Related

Clip-Path vs Border-Radius issue when window is resized

I want to use an SVG as a clip-path to round the edges of an image. Yes, I must do it in this way for various reasons .
PROBLEM:
When the browser window is resized, the points and handles that form the rounded corners adjust to the changing size of the image (bounding box) because I'm using clipPathUnits="ObjectBoundingBox". This causes the rounded edges to loose their "roundness" and look overall really bad. The CSS border-radius property doesn't have this issue. No matter how you resize the browser window, the edges of a div clipped with border-radius never loose their round shape. The problem is most apparent when you resize the browser window to it's most narrow or widest possible state. Try that with this codepen and you'll see what I mean. The top image uses border-radius and the bottom image uses clip-path. Is there any way to force the ONLY rounded edges of the SVG clip-path to stay equally rounded no matter how the image is resized without sacrificing the responsiveness of the clip-path dimensions? Is this even possible? I'm totally open to a JavaScript solution if there is one. Thanks!
You can trick the <svg> element to have just the same dimensions as the image and then size the clip-path with relative units. The downside is that you cannot reuse these paths but have to define one for every individual image.
.box {
left: 5%;
height: 40%;
position: absolute;
background-color: blue;
overflow: hidden;
}
#box1 {
top: 5%;
width: 50%;
clip-path: url(#clipPath1);
}
#box2 {
top: 55%;
width: 90%;
clip-path: url(#clipPath2);
}
.flower{
width: 100%;
height: 100%;
object-fit: cover;
object-position: center;
}
svg {
width: 100%;
height: 100%;
position: absolute;
}
<div class="box" id="box1">
<img class="flower" src="https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500" alt="none">
<svg>
<clipPath id="clipPath1" clipPathUnits="userSpaceOnUse">
<rect width="100%" height="100%" rx="20" ry="20"/>
</clipPath>
</svg>
</div>
<div class="box" id="box2">
<img class="flower" src="https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500" alt="none">
<svg>
<clipPath id="clipPath2" clipPathUnits="userSpaceOnUse">
<rect width="100%" height="100%" rx="20" ry="20"/>
</clipPath>
</svg>
</div>

Responsive inline svg?

This SVG icon is 640x640px. The toolbar is 48px high.
The icon should now automatically adjust to the height of the toolbar.
Accordingly, the blue area would have to be 48x48px.
However, the icon now occupies much more space than it needs.
I gave the svg a height of 48px. Better would be height: 100% but that does not work.
my codepen
Changing only the height to 48px leaves the width at 640px. Because you have width="640px" specified on your <SVG>.
So the fix is simply to remove the width and height attributes from <svg>.
body {
margin: 5%;
}
.toolbar {
position: realive;
color: #fff;
display: flex;
align-items:center;
justify-content: space-between;
background: red;
height: 48px;
}
.toolbar__section.flex-grow {
flex-grow: 1;
}
.toolbar__section.bg-green {
background: green;
}
svg {
display: flex;
height: 48px;
background: blue;
}
<p><strong>Responsive inline svg?</strong></p>
<p>
This SVG icon is 640x640px. The toolbar is 48px high.
The icon should now automatically adjust to the height of the toolbar.
Accordingly, the blue area would have to be 48x48px.
However, the icon now occupies much more space than it needs.
I gave the svg a height of 48px. Better would be "height: 100%" but that does not work.
</p>
<div class="toolbar">
<div class="toolbar__section bg-green flex-grow">
Logo
</div>
<div class="toolbar__section">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640" preserveAspectRatio="xMinYMin meet">
<title></title>
<g id="icomoon-ignore">
</g>
<path fill="#000" d="M603.794 613.188l-190.189-207.478c42.858-44.846 66.395-103.468 66.395-165.71 0-64.106-24.964-124.375-70.294-169.706s-105.6-70.294-169.706-70.294-124.375 24.964-169.706 70.294-70.294 105.6-70.294 169.706 24.964 124.376 70.294 169.706 105.6 70.294 169.706 70.294c55.226 0 107.595-18.542 150.027-52.655l190.178 207.467c3.156 3.442 7.471 5.188 11.799 5.188 3.862 0 7.736-1.391 10.808-4.205 6.513-5.972 6.954-16.093 0.982-22.607zM32 240c0-114.691 93.309-208 208-208s208 93.309 208 208-93.309 208-208 208-208-93.309-208-208z"></path>
</svg>
</div>
<div class="toolbar__section bg-green">
Login Icon
</div>
</div>
Delete the width attribute from the svg element. You may have to adjust the flex-grow attributes in your toolbar afterwards.
See it live on CodePen.
Tested on Chrome 63.0.3239.132

Using CSS clip-path only affects first object in webkit browsers?

I am trying to use the CSS clip-path attribute to apply an SVG clip-path to some elements in a page. For example, HTML (note that clipPathUnits="objectBoundingBox" allows the circle to be expressed in fractions of the containing element size):
setTimeout(function(){
$('.circle:first div').addClass('clipped');
setTimeout(function(){
$('.circle:nth-of-type(2) div').addClass('clipped');
}, 2000);
}, 2000);
.circle {
width: 100px;
height: 100px;
overflow: hidden;
margin-bottom: 10px;
}
.circle div {
width: 100%;
height: 100%;
background: red;
position: relative;
}
.clipped {
-webkit-clip-path: url(#circle_clip);
-moz-clip-path: url(#circle_clip);
-o-clip-path: url(#circle_clip);
clip-path: url(#circle_clip);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="circle">
<div></div>
</div>
<div class="circle">
<div></div>
</div>
<svg>
<defs>
<clippath id="circle_clip" clipPathUnits="objectBoundingBox">
<circle cx=".5" cy=".5" r=".5" />
</clippath>
</defs>
</svg>
Using this code, the first element appears properly clipped into a circle, but the second element disappears in Chrome and Safari. On Firefox two elements appear, both properly clipped.
Here's another Fiddle that actually gets it to work by applying the clipping to each element, removing it from the first before applying to the second, then turning the first back on. Interesting, with timers to "animate" it everything works. If you simply add and remove the classes in a single operation it does not work, as if there was a race condition involved or it needs to finish rendering before the fix takes effect.
Am I doing something wrong or do Webkit browsers have a bug? Can someone get these Fiddles to work?

Why doesn't an HTML anchor tag wrap a scalable SVG <object>?

I have created a scalable SVG object, using the preserveAspectRatio and viewBox attributes in the SVG file itself:
<svg
…
width="800"
height="800"
preserveAspectRatio="xMinYMin meet"
viewBox="0 0 800 800"
…
In the HTML, I reference the SVG file using the <object> tag and wrap it an <a> tag (I want to do this so that I can style it later):
<a>
<object type="image/svg+xml" data="smiley.svg">
</object>
</a>
I style the <object> tag with some CSS to make it 50% wide, and no wider than 100%:
object {
max-width: 100%;
width: 50%;
}
The problem is that the anchor tag doesn't wrap all around the object!
Any ideas anyone?
Adding display: block to anchor seems to fix it for me.
I actually found a fully working solution at teamtreehouse.
It's a combination of inline-block and pseudo-elements.
Thomas Quayle made a pen of the example solution (replicated below).
a.svg {
position: relative;
display: inline-block;
width: 25%;
}
a.svg:after {
content: "";
position: absolute;
top: 0;
right: 0;
bottom: 0;
left:0;
}
object {
width: 100%;
}
<h1>SVG Link Demo</h1>
<blockquote>Replicated from Thomas Quayle's codepen example</blockquote>
<a href="http://google.com" class="svg">
<object data="http://openclipart.org/people/cjcreativedesign/PuppyLongEars.svg" type="image/svg+xml" class="mailicon">
</object>
</a>
<a href="http://google.com" class="svg">
<object data="http://openclipart.org/people/cjcreativedesign/PuppyLongEars.svg" type="image/svg+xml" class="mailicon">
</object>
</a>
<p>How cool is that?</p>
I think #CBroe has it: SVG can be interactive content, therefore it shouldn't be wrapped by anchor element:
w3.org/TR/html5/text-level-semantics.html#the-a-element: “Content model: Transparent, but there must be no interactive content descendant.”

How to scale SVG image to fill browser window?

This seems like it ought to be easy, but I'm just not getting something.
I want to make an HTML page containing a single SVG image that automatically scales to fit the browser window, without any scrolling and while preserving its aspect ratio.
For example, at the moment I have a 1024x768 SVG image; if the browser viewport is 1980x1000 then I want the image to display at 1333x1000 (fill vertically, centred horizontally). If the browser was 800x1000 then I want it to display at 800x600 (fill horizontally, centred vertically).
Currently I have it defined like so:
<body style="height: 100%">
<div id="content" style="width: 100%; height: 100%">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
width="100%" height="100%"
viewBox="0 0 1024 768"
preserveAspectRatio="xMidYMid meet">
...
</svg>
</div>
</body>
However this is scaling up to the full width of the browser (for a wide but short window) and producing vertical scrolling, which isn't what I want.
What am I missing?
How about:
html, body { margin:0; padding:0; overflow:hidden }
svg { position:fixed; top:0; bottom:0; left:0; right:0 }
Or:
html, body { margin:0; padding:0; overflow:hidden }
svg { position:fixed; top:0; left:0; height:100%; width:100% }
I have an example on my site using (roughly) this technique, albeit with 5% padding all around, and using position:absolute instead of position:fixed:
http://phrogz.net/svg/svg_in_xhtml5.xhtml
(Using position:fixed prevents a very edge-case scenario of linking to a sub-page anchor on the page, and overflow:hidden can ensure that no scroll bars ever appear (in case you have extra content.)

Resources