Can an SVG inherit its size from the parent element? - css

I'm trying to to switch a Vue/Vuetify app from using the webfont for Material Design Icons to use SVG icons instead.
When using the webfont, an example of a heading that contains an icon is
<template>
<h1>
<v-icon>mdi-format-list-bulleted</v-icon>
My Heading
</h1>
</template>
The height of the icon automatically matches the heading because the <i> element that is generated for the icon has CSS properties
font-size: inherit;
color: inherit;
After switching to SVG icons, an example of a heading that contains an icon is
<template>
<h1>
<v-icon>{{ iconPath }}</v-icon>
My Heading
</h1>
</template>
<script>
import { mdiFormatListBulleted } from '#mdi/js'
export default {
data: () => ({
iconPath: mdiFormatListBulleted
})
}
</script>
This generates the following markup instead:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" role="img"
aria-hidden="true" class="v-icon__svg">
<!-- path element omitted -->
</svg>
the CSS class has the following properties
.v-icon__svg {
height: 24px;
width: 24px;
fill: currentColor;
}
The fixed icon height of 24px means that the SVG icon doesn't match the heading's height.
Although the <v-icon> component provides a number of props that I can use to change the icon's size, e.g. size, large, small, these will fix the size to a specific value, rather than inheriting the size from the parent element.
Is there a way for an SVG to inherit it's size from it's parent element? More specifically, I want the SVG height and width to be the same as the parent element's height.
Demo
I've created a demo of what happens when you use SVG icons. It takes about 30 seconds for it to load, and you may need to disable 3rd party cookies for it to work.

If you set the height of the SVG to one of the relative units it will match the font-size of the context. You can combine this with vertical-align if necessary.
h1,h2 {
color: navy;
}
.height-ch {
height: 1ch;
fill: currentColor;
}
.height-em {
height: 1em;
fill: currentColor;
}
.height-rem {
height: 1rem;
fill: currentColor;
}
<h1>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" role="img"
aria-hidden="true" class="height-em">
<path d="M 0 0 L 24 0 L 24 24 L 0 24 Z" />
</svg>
Heading em
</h1>
<h2>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" role="img"
aria-hidden="true" class="height-em">
<path d="M 0 0 L 24 0 L 24 24 L 0 24 Z" />
</svg>
Heading em
</h2>
<h2>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" role="img"
aria-hidden="true" class="height-ch">
<path d="M 0 0 L 24 0 L 24 24 L 0 24 Z" />
</svg>
Heading ch
</h2>
<h2>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" role="img"
aria-hidden="true" class="height-rem">
<path d="M 0 0 L 24 0 L 24 24 L 0 24 Z" />
</svg>
Heading rem
</h2>

Related

CSS: Want to hover over svg and change to text

I have a house icon and I want as soon as I hover over it the SVG changes to the text Home
Demo:
.fa-house:hover {
content: "Home";
}
<li routerLink="/home"><svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="house" class="svg-inline--fa fa-house " role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512" color="#4d4d4e">
<path fill="currentColor"
d="M575.8 255.5c0 18-15 32.1-32 32.1h-32l.7 160.2c0 2.7-.2 5.4-.5 8.1V472c0 22.1-17.9 40-40 40H456c-1.1 0-2.2 0-3.3-.1c-1.4 .1-2.8 .1-4.2 .1H416 392c-22.1 0-40-17.9-40-40V448 384c0-17.7-14.3-32-32-32H256c-17.7 0-32 14.3-32 32v64 24c0 22.1-17.9 40-40 40H160 128.1c-1.5 0-3-.1-4.5-.2c-1.2 .1-2.4 .2-3.6 .2H104c-22.1 0-40-17.9-40-40V360c0-.9 0-1.9 .1-2.8V287.6H32c-18 0-32-14-32-32.1c0-9 3-17 10-24L266.4 8c7-7 15-8 22-8s15 2 21 7L564.8 231.5c8 7 12 15 11 24z">
</path>
</svg>
</li>
try below code, just change width and height of your svg and use below code,
#container p{
visibility: hidden;
z-index: 1;
}
#container:hover p{
visibility: visible;
}
#container:hover svg{
visibility: hidden;
}
<div id="container">
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="house"
class="svg-inline--fa fa-house" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"
color="#4d4d4e">
<path fill="currentColor"
d="M575.8 255.5c0 18-15 32.1-32 32.1h-32l.7 160.2c0 2.7-.2 5.4-.5 8.1V472c0 22.1-17.9 40-40 40H456c-1.1 0-2.2 0-3.3-.1c-1.4 .1-2.8 .1-4.2 .1H416 392c-22.1 0-40-17.9-40-40V448 384c0-17.7-14.3-32-32-32H256c-17.7 0-32 14.3-32 32v64 24c0 22.1-17.9 40-40 40H160 128.1c-1.5 0-3-.1-4.5-.2c-1.2 .1-2.4 .2-3.6 .2H104c-22.1 0-40-17.9-40-40V360c0-.9 0-1.9 .1-2.8V287.6H32c-18 0-32-14-32-32.1c0-9 3-17 10-24L266.4 8c7-7 15-8 22-8s15 2 21 7L564.8 231.5c8 7 12 15 11 24z">
</path>
</svg>
<p>SOME TEXT INSTEAD OF IMAGE</p>
</div>
comment if any query
Make a parent
<div id="parent">
<svg className='your svg'/>
<div className='Home' />
</div>
when you will hover on parent, make svg display none, and div display flex.
by default put on svg display flex, and on div with text a display none.
and don't forget about transition to make it beautifull.
If you don't understand the concept and need more explanation, I will give you full example based on your code, just ask. Have a perfect day!

Change the color of a SVG icon similar to grayscale but to shades of blue with CSS

I have a list of SVG icons that has colors in them which I use to display like below
I want to be able to re-use these SVG elsewhere in my webapp but change the color of the icons so that instead of showing color it only shows a certain shade of color. (Blue)
Is there a way to change this to blue similar to grayscale via CSS? (I'd rather not upload a separate SVG to do this)
The closest I got was something from following this How change hue of image with different colors with css filter to hue of blue
But I don’t want the square background right behind the icon. (I just want the SVG to change color)
.background {
padding: 16px;
background: rgb(199, 229, 242);
}
.donut {
width: 32px;
height: 32px;
position: relative;
}
.donut::before, .donut::after {
content: '';
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
}
.donut::before {
background-color: gray;
mix-blend-mode: color;
}
.donut::after {
mix-blend-mode: overlay;
background-color: blue;
}
<div class="background">
<div class="donut">
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<path d="M23.778 4.36A14 14 0 0016 2v5a9 9 0 11-9 9H2A14 14 0 1023.778 4.36z" fill="#E1BD16"/>
<path d="M6.1 6.1A14 14 0 002 16h5a9 9 0 019-9V2a14 14 0 00-9.9 4.1z" fill="#F85F4E"/>
</svg>
</div>
</div>
You could also apply a css filter directly on your donut icon like so:
filter: hue-rotate(180deg) saturate(75%);
Simple color shift example
.background {
padding: 16px;
background: rgb(199, 229, 242);
}
.icon-use {
width: 32px;
height: 32px;
display: inline-block;
}
.filter-blue-hover:hover,
.filter-blue {
filter: hue-rotate(180deg) saturate(75%);
}
<svg class="donut" style="display:none" fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<symbol id="icon">
<path d="M23.778 4.36A14 14 0 0016 2v5a9 9 0 11-9 9H2A14 14 0 1023.778 4.36z" fill="#E1BD16" />
<path d="M6.1 6.1A14 14 0 002 16h5a9 9 0 019-9V2a14 14 0 00-9.9 4.1z" fill="#F85F4E" />
</symbol>
</svg>
<div class="background">
<svg viewBox="0 0 32 32" class="icon-use filter-blue">
<use href="#icon" />
</svg>
</div>
<p>
<svg viewBox="0 0 32 32" class="icon-use filter-blue-hover">
<use href="#icon" />
</svg> Filter on hover - no background color needed.
</p>
Edit: normalized colorizing
This example avoids undesired colors caused by relative hue shifts.
We first tint everything to a sepia tone by sepia(100%).
By this normalizing step, we can make sure all filtered colors will be in the desired hue range ("blueish" in this case).
//toggleFilter
function toggleFilter() {
let filterItems = document.querySelectorAll(".toggleFilter");
filterItems.forEach(function(el, i) {
el.classList.toggle("filter-blue");
});
}
.icon-use {
width: 1em;
height: 1em;
display: inline-block;
font-size: 10vw;
transition: 0.3s;
}
.filter-blue {
transition: 0.3s filter ease-in-out;
filter: invert(0%) sepia(100%) saturate(300%) hue-rotate(-180deg);
}
.filter-blue:hover {
filter: invert(0%) sepia(0%) saturate(100%) hue-rotate(0deg);
}
.icon-wrp {
position: relative;
display: inline-block;
width: 1em;
font-size: 10vw;
}
<p>
<button id="btnFilter" onclick="toggleFilter()">Toggle Filter</button>
</p>
<svg class="donut" style="display:none" fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<symbol id="slice">
<circle cx="50%" cy="50%" r="25%" fill="none" pathLength="99" />
</symbol>
</svg>
<div class="icon-wrp">
<!-- pie chart-->
<svg viewBox="0 0 32 32" class="toggleFilter">
<use href="#slice" stroke="#E1BD16" stroke-width="16" />
<use href="#slice" stroke="#F85F4E" stroke-width="16" stroke-dasharray="33 100" />
<use href="#slice" stroke="purple" stroke-width="16" stroke-dashoffset="-33" stroke-dasharray="33 100" />
</svg>
</div>
<div class="icon-wrp">
<!-- pie chart-->
<svg viewBox="0 0 32 32" class="toggleFilter " transform="scale(1.5)">
<use href="#slice" stroke="blue" stroke-width="4" />
<use href="#slice" stroke="green" stroke-width="4" stroke-dasharray="33 100" />
<use href="#slice" stroke="orange" stroke-width="4" stroke-dashoffset="-33" stroke-dasharray="33 100" />
</svg>
</div>
<div class="icon-wrp">
<!-- pie chart-->
<svg viewBox="0 0 32 32" class="toggleFilter ">
<use href="#slice" stroke="yellow" stroke-width="16" />
<use href="#slice" stroke="cyan" stroke-width="16" stroke-dasharray="33 100" />
<use href="#slice" stroke="magenta" stroke-width="16" stroke-dashoffset="-33" stroke-dasharray="33 100" />
</svg>
</div>
This approach is based on the popular svg coloring concept described here (How to change the color of an svg element?).
The main benefit:
you don't need additional (background) elements to control the mix-blendmode color calculations.
Drawbacks:
you will have to tweak the different hue-shift properties to get the desired color result.
I found that you can add a position absolute SVG with a fill of the color that you want. Then using mix-blend-mode: overlay; and filter: grayscale(1); you can get the shade of color that you want
.background {
padding: 16px;
background: rgb(199, 229, 242);
}
.donut {
width: 32px;
height: 32px;
filter: grayscale(1);
mix-blend-mode: overlay;
z-index: 1;
}
.donut-background {
width: 32px;
height: 32px;
position: absolute;
z-index: 0;
}
.donut-background * {
fill: #2C93BF;
}
<div class="background">
<svg class="donut-background" fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<path d="M23.778 4.36A14 14 0 0016 2v5a9 9 0 11-9 9H2A14 14 0 1023.778 4.36z" fill="#E1BD16"/>
<path d="M6.1 6.1A14 14 0 002 16h5a9 9 0 019-9V2a14 14 0 00-9.9 4.1z" fill="#F85F4E"/>
</svg>
<svg class="donut" fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<path d="M23.778 4.36A14 14 0 0016 2v5a9 9 0 11-9 9H2A14 14 0 1023.778 4.36z" fill="#E1BD16"/>
<path d="M6.1 6.1A14 14 0 002 16h5a9 9 0 019-9V2a14 14 0 00-9.9 4.1z" fill="#F85F4E"/>
</svg>
</div>
Using filter with just the SVG's paths not the background to change color based on the original colors:
.background {
margin: 1rem;
}
.donut {
height: 32px;
width: 32px;
}
.donut svg:hover {
filter: hue-rotate(180deg);
}
<div class="background">
<div class="donut">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<path d="M23.778 4.36A14 14 0 0016 2v5a9 9 0 11-9 9H2A14 14 0 1023.778 4.36z" fill="#E1BD16"/>
<path d="M6.1 6.1A14 14 0 002 16h5a9 9 0 019-9V2a14 14 0 00-9.9 4.1z" fill="#F85F4E"/>
</svg>
</div><br>
Hover over image.
</div>

Any way to use SVG Sprite from CSS?

HTML:
<svg>
<use xlink:href="/assets/images/icons-sprite.svg#icon-name"></use>
</svg>
SVG sprite:
<svg width="0" height="0" class="hidden">
<symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" id="icon-name">
<path ... fill="currentColor"></path>
</symbol>
</svg>
Is there any way to use SVG sprite from CSS
Like this
<div class=“icon”></div>
.icon {
background-image: “/assets/images/icons-sprite.svg#icon-name”
height: 30px
}
I’m using the technique for including SVGs described here whereby you create a doc that looks something like this…
<svg xmlns="http://www.w3.org/2000/svg">
<symbol id="arrow-left" viewBox="0 0 10 16">
<path d="M9.4 1.4L8 0 0 8l8 8 1.4-1.4L2.8 8z"/>
</symbol>
<symbol id="arrow-right" viewBox="0 0 10 16">
<path d="M0 14.6L1.4 16l8-8-8-8L0 1.4 6.6 8z"/>
</symbol>
</svg>
Include it in the top of your HTML and then insert the SVG icons in your markup like this…
<svg class="arrow-right">
<use xlink:href="#arrow-right" />
</svg>
It’s easy and works great. However, I’m trying to use the same icons in my CSS pseudo classes :before and :after using an empty content attribute and the SVG in the background. Something like this…
.title:after {
float: right;
width: 16px;
height: 10px;
content: "";
background: url('#arrow-right');
}

hover on one div lights up another corresponding

I have svg paths showing statistics about letters a-z.
I have corresponding divs with the letter itself.
Each div should colorize corresponding svg path when hovered.
Is it possible to use CSS only to define the relation ships?
I mean, not a way where I have 26 definitions in the css, describing relation of every div
logic like
div.a has been hovered, colorize path.a
div.b has been hovered, colorize path.b
...
what I have for now is this.
<body>
<svg height="210" width="400">
<path class="U" d="M 0 300 L 200 0 L 400 400" />
<path class="T" d="M 0 400 L 200 0 L 400 150" />
<!-- ... -->
</svg>
</body>
I am trying to find solution for the divs, hoping it wouldn't need JS
The simple answer to this is that is is only possible if the div contains the path. Something like this for instance:
/* HTML */
<div class="example-div">
<svg class="example-svg" height="210" width="400">
<path class="U" d="M 0 300 L 200 0 L 400 400" />
<path class="T" d="M 0 400 L 200 0 L 400 150" />
</svg>
</div>
/* CSS */
.example-div {
fill: white;
}
.example-div:hover {
fill: black;
}
.example-svg path {
fill: inherit;
}
If the div does not contain the path then as far as CSS is concerned it has no knowledge of it.

Scale inline SVG symbol referenced with <use>

I have an SVG logo defined as a symbol like so:
<svg class="SpriteSheet">
<symbol id="icon-logo" viewBox="-12 -79.61 407.19 108.36">
<path id="logo-upperLeft" d="M0-67.61l83.66 0 0-10 -93.66 0 0 30.92 10 0Z" transform="translate(-2 -2)"></path>
<path id="logo-upperRight" d="M383.19-67.61l-83.66 0 0-10 93.66 0 0 30.92 -10 0Z" transform="translate(2 -2)"></path>
<path id="logo-lowerLeft" d="M0 16.75l83.66 0 0 10 -93.66 0 0-30.92 10 0Z" transform="translate(-2 2)"></path>
<path id="logo-lowerRight" d="M383.19 16.75l-83.66 0 0 10 93.66 0 0-30.92 -10 0Z" transform="translate(2 2)"></path>
</symbol>
</svg>
This definition is included at the top of the body and styled with display:none.
Later in the document, I use the logo in this way:
<header class="Header">
<h1 class="Header-headline">
<a href="/">
<svg class="Header-logo">
<use xlink:href="#icon-logo"></use>
</svg>
</a>
</h1>
</header>
I want to make the logo a certain height, with an automatic width:
.Header-logo {
height: 5rem;
}
This results in this:
Although the height is correct (here, 1rem is 24px), the width remains the default 300px. Adding width:auto causes no changes. In researching this problem, I came across several possible solutions here and here. However, none have worked with my application: reapplying the viewBox at the point of usage cuts off a large part of the image and using an <img> tag is not possible because I need to retain access to the SVG's DOM for styling purposes.
I could add a hard-coded width based on the known aspect ratio of the image, but this seems to be a non-optimal solution: what if the aspect ratio of the logo changes in the future? Another option is to define width:100%, which does work, however, this makes the 'clickable' area of the <a> extend across the entire width of the header, which I would like to avoid.
Is it possible to have an automatically-sized width with a defined height when the viewBox is described in the <symbol> definition? Must I be relegated to using an <img> tag or an absolute width for the SVG element?
Unfortunately it is the dimensions of the <svg> element that appears in your <header> that is important. There is no way to inherit a viewBox from a child symbol reference.
You would need to copy the viewBox (width and height) from the symbol.
.Header-logo {
height: 5rem;
}
.Header-logo2 {
height: 8rem;
}
<svg class="SpriteSheet" width="0" height="0">
<symbol id="icon-logo" viewBox="-12 -79.61 407.19 108.36">
<path id="logo-upperLeft" d="M0-67.61l83.66 0 0-10 -93.66 0 0 30.92 10 0Z" transform="translate(-2 -2)"></path>
<path id="logo-upperRight" d="M383.19-67.61l-83.66 0 0-10 93.66 0 0 30.92 -10 0Z" transform="translate(2 -2)"></path>
<path id="logo-lowerLeft" d="M0 16.75l83.66 0 0 10 -93.66 0 0-30.92 10 0Z" transform="translate(-2 2)"></path>
<path id="logo-lowerRight" d="M383.19 16.75l-83.66 0 0 10 93.66 0 0-30.92 -10 0Z" transform="translate(2 2)"></path>
</symbol>
</svg>
<header class="Header">
<h1 class="Header-headline">
<a href="/">
<svg class="Header-logo" viewBox="0 0 407.19 108.36">
<use xlink:href="#icon-logo"></use>
</svg>
</a>
</h1>
</header>
<header class="Header">
<h1 class="Header-headline">
<a href="/">
<svg class="Header-logo2" viewBox="0 0 407.19 108.36">
<use xlink:href="#icon-logo"></use>
</svg>
</a>
</h1>
</header>

Resources