ChatGPT解决这个技术问题 Extra ChatGPT

Is there a way to use SVG as content in a pseudo element ::before or ::after

I would like to use ::before to place SVG images before some selected elements:

#mydiv::before {
  content: '<svg ... code here</svg>';
  display: block;
  width: 22px;
  height: 10px;
  margin: 10px 5px 0 10px;
}

Above code just displays the plaintext.
I checked the spec and there seem to be some restrictions on what content can be. CSS content property solution is preferable.

Is something wrong with using it as a background image?
I want to use it to generate fancy pointers to JQuery UI tooltips. I do that now with CSS pseudo elements hack but that gives me only triangles. Background image will not work in this case as I need something that goes outside the element.

Z
Zach Jensz

Yes you can! Just tested this and it works great, this is awesome! It still doesn't work with html, but it does with svg.

SVG URL encoder to format your own SVGs as shown here.

#test::before { content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='100' cy='50' r='40' stroke='black' stroke-width='2' fill='red'/%3E%3Cpolyline points='20,20 40,25 60,40 80,120 120,140 200,180' style='fill:none;stroke:black;stroke-width:3'/%3E%3C/svg%3E "); width: 200px; height: 200px; }


Unless SVGs are special, you should be able to treat them the same as you would an image: content: url(path/to/my.svg). That doesn't necessarily mean it would work with the jQuery UI tooltips library, though.
Why would you want to do this? If you have the svg code in the file already, then there is no need to put it in a pseudo-class. The whole point of pseudo-classes is to reduce DOM elements when you want to add a bit of content, but in your case if you just use your svg code normally it will be no worse (and probably cleaner) than putting it in a pseudo-class(which is also probably impossible). Unless of course if you want to put your svg code in a bunch of locations, in which case you should just keep your svg code in a separate file like an image.
unfortunately, i don't believe this solution works with SVG sprites. for instance, content: url(mysprite.svg#my-icon) won't actually pull up your icon. i would love to be proven wrong, however :)
@watson, semantic. The HTML = structure, CSS = presentation. If a SVG is decorative then it shouldn't be in the HTML structure, it should be in CSS.
As mentioned in other replies; Its 2020, So does SVG: content:url("data:image/svg+xml,<svg width='10' viewBox='0 0 8 8' xmlns='http://www.w3.org/2000/svg'><circle cx='4' cy='4' r='4' fill='red'/></svg>");
Z
Zach Jensz

You can use the url() CSS function.

#mydiv::before {
  content: url("data:image/svg+xml; utf8, <svg ... code here</svg>");
  display: block;
  width: 22px;
  height: 10px;
  margin: 10px 5px 0 10px;
}

Make sure your SVG doesn't contain any # symbols. Use an encoder like this one.


Since SVGs often use double quotes, you can also just use outer single quotes. @Jenny's suggestion is a great way of doing it if you don't want to use an external SVG file.
This is great. Unfortunately it only works with Chrome for me (tested on Chrome, Firefox and Edge).
What I found important is to add xmlns='http://www.w3.org/2000/svg' in the <svg> part to work in Chrome 66.x. For example - small chevron will be: content:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='24px' height='24px' fill='white'><path d='M7.41,8.58L12,13.17L16.59,8.58L18,10L12,16L6,10L7.41,8.58Z' /></svg>");
fyi # urlencodes to %23, and also have to remove all line breaks.
Easy way: Use yoksel.github.io/url-encoder for safe encoding SVG images as URL data (background-image or content property).
P
Penny Liu

You can add the SVG as background-image of an empty :after or :before.

Here you go:

.anchor:before {
  display: block;
  content: ' ';
  background-image: url('../images/anchor.svg');
  background-size: 28px 28px;
  height: 28px;
  width: 28px;
}

I find this one of the best solutions, after looking for a while. You can control every single aspect of the inserted element and works in the normal way CSS style-sheets works, with separated logic. Great
...ahh this got my hopes up, until I realize that background-size is not supported in Opera Mini. This is so frustrating.
Worked great. @deathlock, background-size shouldn't be needed as you are defining the dimensions in the svg itself, I didn't need it.
Should be the accepted answers since the question says "in a pseudo element :before or :after"
@NicolasBoisteault I tried it but what worked for me was actually to use this structure as one of the answers : url("data:image/svg+xml; utf8, <svg.. code here</svg>");
A
Alexei Zababurin
<div class="author_">Lord Byron</div>

.author_ { font-family: 'Playfair Display', serif; font-size: 1.25em; font-weight: 700;letter-spacing: 0.25em; font-style: italic; position:relative; margin-top: -0.5em; color: black; z-index:1; overflow:hidden; text-align:center; } .author_:after{ left:20px; margin:0 -100% 0 0; display: inline-block; height: 10px; content: url(data:image/svg+xml,%0A%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22120px%22%20height%3D%2220px%22%20viewBox%3D%220%200%201200%20200%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%3E%0A%20%20%3Cpath%20stroke%3D%22black%22%20stroke-width%3D%223%22%20fill%3D%22none%22%20d%3D%22M1145%2085c17%2C7%208%2C24%20-4%2C29%20-12%2C4%20-40%2C6%20-48%2C-8%20-9%2C-15%209%2C-34%2026%2C-42%2017%2C-7%2045%2C-6%2062%2C2%2017%2C9%2019%2C18%2020%2C27%201%2C9%200%2C29%20-27%2C52%20-28%2C23%20-52%2C34%20-102%2C33%20-49%2C0%20-130%2C-31%20-185%2C-50%20-56%2C-18%20-74%2C-21%20-96%2C-23%20-22%2C-2%20-29%2C-2%20-56%2C7%20-27%2C8%20-44%2C17%20-44%2C17%20-13%2C5%20-15%2C7%20-40%2C16%20-25%2C9%20-69%2C14%20-120%2C11%20-51%2C-3%20-126%2C-23%20-181%2C-32%20-54%2C-9%20-105%2C-20%20-148%2C-23%20-42%2C-3%20-71%2C1%20-104%2C5%20-34%2C5%20-65%2C15%20-98%2C22%22%2F%3E%0A%3C%2Fsvg%3E%0A); } .author_:before { right:20px; margin:0 0 0 -100%; display: inline-block; height: 10px; content: url(data:image/svg+xml,%0A%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22120px%22%20height%3D%2220px%22%20viewBox%3D%220%200%201200%20130%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%3E%0A%20%20%3Cpath%20stroke%3D%22black%22%20stroke-width%3D%223%22%20fill%3D%22none%22%20d%3D%22M55%2068c-17%2C6%20-8%2C23%204%2C28%2012%2C5%2040%2C7%2048%2C-8%209%2C-15%20-9%2C-34%20-26%2C-41%20-17%2C-8%20-45%2C-7%20-62%2C2%20-18%2C8%20-19%2C18%20-20%2C27%20-1%2C9%200%2C29%2027%2C52%2028%2C23%2052%2C33%20102%2C33%2049%2C-1%20130%2C-31%20185%2C-50%2056%2C-19%2074%2C-21%2096%2C-23%2022%2C-2%2029%2C-2%2056%2C6%2027%2C8%2043%2C17%2043%2C17%2014%2C6%2016%2C7%2041%2C16%2025%2C9%2069%2C15%20120%2C11%2051%2C-3%20126%2C-22%20181%2C-32%2054%2C-9%20105%2C-20%20148%2C-23%2042%2C-3%2071%2C1%20104%2C6%2034%2C4%2065%2C14%2098%2C22%22%2F%3E%0A%3C%2Fsvg%3E%0A); }

Lord Byron

Convenient tool for SVG encoding url-encoder


A
Asons

Making use of CSS sprites and data uri gives extra interesting benefits like fast loading and less requests AND we get IE8 support by using image/base64:

Codepen sample using SVG

HTML

<div class="div1"></div>
<div class="div2"></div>

CSS

.div1:after, .div2:after {
  content: '';
  display: block;
  height: 80px;
  width: 80px;
  background-image: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20height%3D%2280%22%20width%3D%22160%22%3E%0D%0A%20%20%3Ccircle%20cx%3D%2240%22%20cy%3D%2240%22%20r%3D%2238%22%20stroke%3D%22black%22%20stroke-width%3D%221%22%20fill%3D%22red%22%20%2F%3E%0D%0A%20%20%3Ccircle%20cx%3D%22120%22%20cy%3D%2240%22%20r%3D%2238%22%20stroke%3D%22black%22%20stroke-width%3D%221%22%20fill%3D%22blue%22%20%2F%3E%0D%0A%3C%2Fsvg%3E);
}
.div2:after {
  background-position: -80px 0;
}

For IE8, change to this:

  background-image: url(data:image/png;base64,data......);

But this isn't scalable, isn't it? I can't resize it to 16px or 320px at will.
@deathlock Of course it scales, though not my sample as it has a fixed size set, 80px wide/high.
@deathlock May I ask if you downvoted because the above sample didn't scale?
how would you make it scale? And no, I didn't.
@deathlock Thanks, and here is one way to scale svg: jsfiddle.net/ess6ywce ... using percent. Also, search SO with scale svg and you'll find many more ways
J
Jakub Muda

To extend further this topic. In case you want to add Font Awesome 5 icons you need to add some extra CSS.

Icons by default have classes svg-inline--fa and fa-w-*.

There are also modifier classes like fa-lg, fa-rotate-* and other. You need to check svg-with-js.css file and find proper CSS for that.

You need to add your own color to css icon otherwise it will be black by default, for example fill='%23f00' where %23 is encoded #.

h1::before{ /* svg-inline--fa */ display:inline-block; font-size:inherit; height:1em; overflow:visible; vertical-align:-.125em; /* fa-w-14 */ width:.875em; /* Icon */ content:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512'%3E%3Cpath fill='%23f00' d='M400 256H152V152.9c0-39.6 31.7-72.5 71.3-72.9 40-.4 72.7 32.1 72.7 72v16c0 13.3 10.7 24 24 24h32c13.3 0 24-10.7 24-24v-16C376 68 307.5-.3 223.5 0 139.5.3 72 69.5 72 153.5V256H48c-26.5 0-48 21.5-48 48v160c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V304c0-26.5-21.5-48-48-48zM264 408c0 22.1-17.9 40-40 40s-40-17.9-40-40v-48c0-22.1 17.9-40 40-40s40 17.9 40 40v48z'%3E%3C/path%3E%3C/svg%3E"); /* Margin */ margin-right:.75rem; }

Lorem Ipsum


z
zbycz

Be careful all of the other answers have some problem in IE.

Lets have this situation - button with prepended icon. All browsers handles this correctly, but IE takes the width of the element and scales the before content to fit it. JSFiddle

#mydiv1 { width: 200px; height: 30px; background: green; }
#mydiv1:before {
    content: url("data:url or /standard/url.svg");
}

Solution is to set size to before element and leave it where it is:

#mydiv2 { width: 200px; height: 30px; background: green; }
#mydiv2:before {
    content: url("data:url or /standard/url.svg");
    display: inline-block;
    width: 16px; //only one size is alright, IE scales uniformly to fit it
}

The background-image + background-size solutions works as well, but is little unhandy, since you have to specify the same sizes twice.

The result in IE11:

https://i.stack.imgur.com/EA4lN.png


M
Mario Petrovic

Although this was many years ago, I'd like to also share this.

The answers above are correct, you can directly attach the encoded svg string into the css content property. For those having any issues with the URL it may be due to spaces and characters not valid for such, in that case paste your decoded SVG code into: https://mothereff.in/url

Use the encoded SVG URL and it should work fine. Incorrect & Correct Examples:

#incorrect::before {
  content: url(
    data:image/svg + xml,
    <svgid="Layer_1"data-name="Layer 1"xmlns="http://www.w3.org/2000/svg"viewBox="0 0 15.37 188.41"><defs><style>.cls-1{fill:#aeadad;}</style></defs><circleclass="cls-1"cx="7.69"cy="7.69"r="7.69"/><rectclass="cls-1"x="6.69"y="27.72"width="2"height="160.69"/></svg>
  );
}
#correct::before {
  content: url(data:image/svg+xml,%0A%3Csvg%20id%3D%22Layer%5f1%22%20data-name%3D%22Layer%201%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2015.37%20188.41%22%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill%3A%23aeadad%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Ccircle%20class%3D%22cls-1%22%20cx%3D%227.69%22%20cy%3D%227.69%22%20r%3D%227.69%22%2F%3E%3Crect%20class%3D%22cls-1%22%20x%3D%226.69%22%20y%3D%2227.72%22%20width%3D%222%22%20height%3D%22160.69%22%2F%3E%3C%2Fsvg%3E%0A);
}

It works, thanks! However yet i can't modify several svg properties with css. :( So it's width i needed to hardcode as html attribute, like: <svg width="30" ... It's color or fill property i also fail to change by external css sheet. Positioning works at least. Any idea?
Are you applying the css properties via class or id? & also, is the bag within an Object element ? If so apply the changes to the object > svg - Also if your rendering the svg via content method ^ you’ll need to apply it to the svg first as the css won’t effect the content properties as it’s an external link and the paths etc are not rendered within the page as such
Got it man! Works. So we truly NEED to add each property (attribute) to the svg html itself. No other way with external css.. Here seems to be more details on the reason here: stackoverflow.com/a/4505130/9022150 "Generated content does not alter the document tree. In particular, it is not fed back to the document language processor (e.g., for reparsing)." Thanks again.
So if i choose to have N pieces of svg-s each injected via content methods, then later for e.g. changing the color for all of them, I'd need to copy the svg out, url decode, modify color attr, url encode, paste back to content method.. Haha, probably, thanks no ;)
T
Trunk

I just today noticed that a newspaper here used direct injection of the SVG into the ::before and ::after pseudo-elements to render stylized quotes for highlighted content in the article. I tried to find that paper's CMS via whatcms.org but to no avail. I can say however that the owner newspaper - a large national, even international, paper uses a CMS called DM Polopoly.

It seems so much more laborious to enter SVG data into the content element rather than blank the content and use the SVG as a background image. I wonder why they chose this method - what advantage went with this. I've seen some people on Google links who said it made it easy to manipulate the SVG image on hovering upon the pseudo-element . . . But I saw no killer example of this 'benefit'.

This article has a simpler method for inserting the SVG as content. It uses a zoom property to get size adjustment for the image.


M
Michael Alfandre
.myDiv {
  display: flex;
  align-items: center;
}

.myDiv:before {
  display: inline-block;
  content: url(./dog.svg);
  margin-right: 15px;
  width: 10px;
}

You should explain a little more your answer. Just from this, it's really hard to tell how or why your answer works.