SVG Rect Ignores Height? - css

Here is a working demo of a rectangle. I'd like to move the height property to css and well, it doesn't work and gives me a blank. It happens in firefox and chrome.
Is there a different name for it? I don't understand why I can't use a css file. The fill color works.
Working example.
css:
rect {
fill:rgb(0, 0, 255);
/*doesnt work height:100;*/
}
html:
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<rect width="100" height="100" style="stroke-width:1;stroke:rgb(0,0,0)"/>
</svg>

In SVG the x, y, width and height of <rect> elements are attributes rather than CSS properties. Only CSS properties can be styled using CSS.

The width of a <rect> element isn't a CSS property in SVG, it's only usable as an attribute. It's for example like the size of a <select> element in HTML. You can only set it as an attribute.

SVG doesn't have a straightforward support for CSS for setting shape dimensions.
However there's a workaround for rects, which can also be used to generate horizontal and vertical lines:
Set width and height to 1, and use CSS transform: scale(width, height)
Don't specify x,y location, and use transform: translate(x, y)
E.g.
.svg {
width: 100px;
height: 30px;
}
.rectangle {
transform: scale(30, 10);
fill: orange;
}
.horiz-line {
transform: translate(15px,5px) scale(50, 1);
fill: red;
}
.vert-line {
transform: translate(10px, 5px) scale(1, 30);
fill: blue;
}
<svg>
<rect class="rectangle" width="1" height="1" />
<rect class="horiz-line" width="1" height="1" />
<rect class="vert-line" width="1" height="1" />
</svg>

workaround for symmetric rectangles:
rect:hover {
stroke-width: 20 !important;
}
<svg width="100" height="100">
<rect
stroke-width="0"
fill="blue" stroke="blue"
x="30" y="30" width="40" height="40"
/>
</svg>
(darkreader will use different colors for stroke and fill)

Related

SVG scale by (100% - 60px)

I'm trying to build an SVG image with content that is 100% the width of the container, minus 60px for some text.
If I was using HTML, or SVG with javascript, I would have no problem doing this. But I feel like there should be a way to do this using SVG (and CSS if needed).
I want the equivalent of this (Codepen here):
<svg width="100%" height="100%">
<rect fill="#ccc" x="0" y="0" width="100%" height="100%"></rect>
<text x="100%" y="50%" stroke="black" text-anchor="end">Y-axis</text>
<svg width="100%" height="100%">
<!-- This rect represents the entirety of the contents of the graph -->
<rect x="0" y="0" style="width: calc(100% - 60px)" height="100%" fill="#c88"></rect>
</svg>
</svg>
In the above snippet, the inner <rect> resizes to be 100% - 60px the width of the container element. However, this trick only works for a single element - if you replace that <rect> with a complex SVG structure it no longer works.
Things I've tried:
Doing a transform: scale() via CSS on the <rect> - I can't figure out what to put into the scale() to make it behave like 100% - 60px.
Changing the width of the nested <svg> element
<svg width="calc(100% - 60px)"> doesn't work - can't do calc() inside the width attribute
<svg width="100%" style="width: calc(100% - 60px);"> (with or without the width attribute) - doesn't work - the CSS "width" property is ignored whether or not the width attribute is present.
I'm starting to think what I want to do isn't possible right now with SVG, but it doesn't seem like an uncommon use case. Is there any way to do this?
As discussed in the comments, you might have some luck achieving the same by making your graph area 100% of the viewBox, but place the SVG in a container with 60px of padding on the right to account for the text space.
Moving your text (and background rect) to x="100%" with its text-anchor="start", in addition to letting the SVG overflow, you can get a pretty close result without needing to transform your graphic, since you have a fixed 60px value you can consistently rely on:
div {
padding-right: 60px;
}
svg {
overflow: visible;
}
<div>
<svg width="100%" height="100%">
<rect fill="#ccc" x="100%" y="0" width="60px" height="100%"></rect>
<text x="100%" y="50%" stroke="black" text-anchor="start">Y-axis</text>
<rect x="0" y="0" width="100%" height="100%" fill="#c88"></rect>
</svg>
</div>
PS: Maybe you would prefer your text to have text-anchor="middle", and transform it in CSS with transform: translateX(30px) to place it in the centre of the "text" area — might look cleaner that way:
div {
padding-right: 60px;
}
svg {
overflow: visible;
}
text {
transform: translateX(30px);
}
<div>
<svg width="100%" height="100%">
<rect fill="#ccc" x="100%" y="0" width="60px" height="100%"></rect>
<text x="100%" y="50%" stroke="black" text-anchor="middle">Y-axis</text>
<rect x="0" y="0" width="100%" height="100%" fill="#c88"></rect>
</svg>
</div>

SVG: Can I put x and y position in attributes in the style?

I would like to include positioning x="50%" y="50%" in a class style. Doing this does not work:
.centre {
x: 50%;
y: 50%;
}
Is there any way to include positioning in a style?
Edit:
Based on the answers, translate() should do the job, and indeed the following snippet shows it working. That is, if you’re not using Safari.
Safari doesn’t seem to like doing this on at text element … ?
text.centre {
font-family: sans-serif;
font-size: .5em;
fill: green;
alignment-baseline: middle;
text-anchor:middle;
-webkit-transform: translate(50%,50%);
transform: translate(50%,50%);
}
<svg x="160" y="100" width="140" height="40">
<rect style="fill: lightgrey;" x="0" y="0" width="140" height="100"/>
<rect style="fill: white;" y="10" x="10" width="120" height="20"/>
<svg x="10" y="10" width="120" height="20">
<text class="centre">Hello</text>
</svg>
</svg>
Apparently, yes, you can. If you use the transform css property. See the attached snippet.
svg {
border: 1px solid;
}
rect {
fill: red;
transform: translate(50%, 50%);
}
<svg height="200" width="200">
<rect height="100" width="100"></rect>
</svg>
You can use transform: translate(50%, 50%) the first is the x the second is y. If you need to move only along one axis or another you can use translateX(x) or translateY(y)
You can read more here
you can manipulate the positioning of paths with transform:translate();
so try manipulating your desired path with
.centre{
transform:translate(50%, 50%);
}
maybe you will want to use some vendor prefixes for cross-browser
.centre{
-webkit-transform:translate(50%, 50%);
-ms-transform:translate(50%, 50%);
transform:translate(50%, 50%);
}
i used this to animate logo parts here: http://fire.netzgestaltung.at
specific SVG CSS Properties: https://www.w3.org/TR/SVG/styling.html
more tutorials (ment for animating but uses css):
https://www.smashingmagazine.com/2014/11/styling-and-animating-svgs-with-css/
https://css-tricks.com/animating-svg-css/
https://www.elegantthemes.com/blog/resources/how-to-create-an-animated-logo-with-svg-and-css

Colour overlay for SVG using CSS?

Is there a way to apply a colour overlay to an SVG using CSS?
I have some SVGs (icons, shapes etc) that I need to be able to "tint" - adding a solid colour overlay but keep the transparency.
I read about the CSS filters, but none of them cater for adding a colour over the top, only stuff like blur or desaturate.
Please check this code snippet. I hope it will be help you.
<svg width="0" height="0" class="svg-visiblity">
<defs>
<path id="hex" d="M11.5,20.9L44.3,2c3.7-2.2,8.3-2.2,12.1,0l32.8,18.9c3.7,2.2,6,6.1,6,10.4v37.8c0,4.3-2.3,8.3-6,10.4 L56.3,98.4c-3.7,2.2-8.3,2.2-12.1,0L11.5,79.5c-3.7-2.2-6-6.1-6-10.4V31.3C5.4,27,7.7,23,11.5,20.9z"/>
<clipPath id="hex-clip-200">
<use xlink:href="#hex" transform="scale(2 2)" />
</clipPath>
</defs>
</svg>
<svg class="image-200-2">
<rect class="border" width="100%" height="100%" transform="scale(1.02)" style="clip-path: url(#hex-clip-200);" /></rect>
<image xlink:href="http://placehold.it/200x200" width="200" height="200" transform="translate(2 2)" style="clip-path: url(#hex-clip-200);"></image>
</svg>
CSS
.image-200-2 {
display: inline-block;
height: 205px;
width: 205px;
}
.image-200-2 .border {
fill: rgba(0, 0, 0, 0.5);
}
.svg-visiblity {
height: 0;
opacity: 0;
position: absolute;
width: 0;
}
See here: https://jsfiddle.net/zyr8wovg/4/

Specifying an SVG rectangle's width and height in CSS [duplicate]

Here is a working demo of a rectangle. I'd like to move the height property to css and well, it doesn't work and gives me a blank. It happens in firefox and chrome.
Is there a different name for it? I don't understand why I can't use a css file. The fill color works.
Working example.
css:
rect {
fill:rgb(0, 0, 255);
/*doesnt work height:100;*/
}
html:
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<rect width="100" height="100" style="stroke-width:1;stroke:rgb(0,0,0)"/>
</svg>
In SVG the x, y, width and height of <rect> elements are attributes rather than CSS properties. Only CSS properties can be styled using CSS.
The width of a <rect> element isn't a CSS property in SVG, it's only usable as an attribute. It's for example like the size of a <select> element in HTML. You can only set it as an attribute.
SVG doesn't have a straightforward support for CSS for setting shape dimensions.
However there's a workaround for rects, which can also be used to generate horizontal and vertical lines:
Set width and height to 1, and use CSS transform: scale(width, height)
Don't specify x,y location, and use transform: translate(x, y)
E.g.
.svg {
width: 100px;
height: 30px;
}
.rectangle {
transform: scale(30, 10);
fill: orange;
}
.horiz-line {
transform: translate(15px,5px) scale(50, 1);
fill: red;
}
.vert-line {
transform: translate(10px, 5px) scale(1, 30);
fill: blue;
}
<svg>
<rect class="rectangle" width="1" height="1" />
<rect class="horiz-line" width="1" height="1" />
<rect class="vert-line" width="1" height="1" />
</svg>
workaround for symmetric rectangles:
rect:hover {
stroke-width: 20 !important;
}
<svg width="100" height="100">
<rect
stroke-width="0"
fill="blue" stroke="blue"
x="30" y="30" width="40" height="40"
/>
</svg>
(darkreader will use different colors for stroke and fill)

CSS padding property for svg elements

I can't figure out how the CSS padding property is interpreted for svg elements. The following snippet (jsFiddle):
<!DOCTYPE html>
<meta charset="utf-8">
<title>noob d3</title>
<style>
svg{background-color:beige;
padding:0px 0px 50px 50px;}
rect{fill:red;
stroke:none;
shape-rendering:crispEdges;}
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
d3.select("body")
.append("svg")
.attr("width", 155)
.attr("height", 105)
.append("g")
.append("rect")
.attr("class", "frame")
.attr("x", 50)
.attr("y", 50)
.attr("width", 50)
.attr("height", 50);
</script>
</body>
... displays significantly differently in Firefox and Chrome. What's worse, neither display really makes sense to me: the size of the displayed svg element (the "beige" rectangle) looks to be significantly bigger than what I expected.
So my question is two-fold: 1) How is the padding property of an svg element supposed to affect where things get drawn within it? 2) Is there a polyfill that will ensure that both Chrome and Firefox both handle padding in the same way?
AFAIK, the SVG standard doesn't specify anything like padding, which is why it's handled inconsistently. Just set the SVG to the size you want (with padding) and maybe add a rect to make it appear like you want it to appear.
From my experience (granted, still very little as I am still learning SVG), I have strayed away from using padding wherever that I could do so. It was suggested to me when I was first learning SVG that I use margin in place of padding, if possible.
This is also because you can use display: block; and margin: 0 auto; to make the left and right sides of an SVG to fit directly into the middle of the screen.
There is no padding or margin, but you can set x and y attributes such that the elements inside or outside get a padding and margin. For example, if an element starts at (0,0), starting at (10, 10) will automatically give a margin of 10.
You can apply padding to parent svg elements
The padding as described by the OP actually works – albeit, not as desired.
Outermost <svg> will be rendered with padding (won't work for nested svgs).
But: child elements (e.g the <rect>) won't be re-aligned according to – unlike HTML DOM elements.
svg {
background-color: beige;
max-height:20em;
}
.pdd{
padding: 0px 0px 50px 50px;
}
rect {
fill: red;
stroke: none;
shape-rendering: crispEdges;
}
.borderBox{
box-sizing: border-box;
}
.overflow{
overflow:visible
}
<p>Rendered size: 205 x 155 – padding added to initial dimensions </p>
<svg class="pdd" width="155" height="105">
<g>
<rect class="frame" x="50" y="50" width="50" height="50" />
</g>
</svg>
<p>Rendered size: 155 x 105; cropped</p>
<svg class="pdd borderBox" width="155" height="105">
<g>
<rect class="frame" x="50" y="50" width="50" height="50" />
</g>
</svg>
<p>Rendered size: 155 x 105; cropped; overflow visible</p>
<svg class="pdd borderBox overflow" width="155" height="105">
<g>
<rect class="frame" x="50" y="50" width="50" height="50" />
</g>
</svg>
Usecase: padding for fluid svg layouts
So, padding doesn't work well for fixed widths/heights.
However, it can be handy for flexible/fluid layouts – provided you're using relative (percentage) units for svg child elements.
*{
box-sizing:border-box;
}
svg{
border:1px solid #ccc;
}
svg {
background-color: lightblue;
padding:0 10px;
overflow:visible;
}
.svg2 {
padding:10px;
}
.svg3 {
padding:0px;
}
.resize{
resize:both;
overflow:auto;
padding:1em;
border:1px solid #ccc;
}
<p>resize me :</p>
<div class="resize">
<svg id="svg" width="100%" height="40" xmlns="http://www.w3.org/2000/svg">
<circle cx="0" cy="10" r="5" />
<circle cx="0" cy="30" r="5" />
<circle cx="50%" cy="10" r="5" />
<circle cx="50%" cy="30" r="5" />
<circle cx="100%" cy="10" r="5" />
<circle cx="100%" cy="30" r="5" />
</svg>
</div>
<div class="resize">
<svg class="svg2" width="100%" height="100%" xmlns="http://www.w3.org/2000/svg">
<!-- align path center to x/y =0 by adding viewBox offset width/2 height/2 -->
<symbol class="icon icon-home" id="iconHome" viewBox="20 20 40 40" overflow="visible">
<path d="M36.4 22.2l-5.2 0l0 13l-3.4 0l0-16.7l-7.7-8.7l-7.7 8.7l0 16.7l-3.4 0l0-13l-5.2 0l16.4-17.4z"></path>
</symbol>
<use x="0" y="0%" href="#iconHome" width="20" height="20" />
<use x="0" y="100%" href="#iconHome" width="20" height="20" />
<use x="50%" y="0%" href="#iconHome" width="20" height="20" />
<use x="50%" y="100%" href="#iconHome" width="20" height="20" />
<use x="100%" y="0%" href="#iconHome" width="20" height="20" />
<use x="100%" y="100%" href="#iconHome" width="20" height="20" />
</svg>
</div>
Based on what I was able to try on firefox and chromium: the specified width and height for an svg include the padding.
In other terms, if you want an image of 20*20px with a padding of 10px on each side, you should set the width to 20+10*2 = 40px (same thing with the height) and the padding to 10px
Note : 20+10*2 : 20 is the width you want, 10 is your padding and you double it because you want it on both sides.
The best solution is open Inkscape (or other SVG editor) and change dimension

Resources