Add CSS pseudo element to SVG [duplicate] - html

Update
Thanks porneL for pointing out the relation between generated content and replaced elements.
I found this article which deals with this very topic:
Interestingly enough, a W3C document titled "CSS3 Generated and Replaced Content Module" (from 11 years ago!) defines the pseudo-element :outside, which could offer a solution to using generated content with replaced elements, by placing the generated content outside the replaced element, instead of trying to append it inside.
Original question
Is there a way to style an inline SVG element using the CSS :before and :after pseudo-elements?
Example: http://jsfiddle.net/wD56Q/
In this example, the styling defined with :before is not applied to the SVG (tested in Firefox 29 and Chrome 35).
Is it about the content property in :before? For what I read, it tries to insert a generated content in the element.. is it what fails with SVG?
Related documentation from MDN:
::before (:before)
::before creates a pseudo-element that is the first child of the
element matched. Often used to add cosmetic content to an element, by
using the content property. This element is inline by default.
content
The content CSS property is used with the ::before and ::after
pseudo-elements to generate content in an element. Objects inserted
using the content property are anonymous replaced elements.
The code in the example:
svg {
left: 50px;
position: absolute;
top: 50px;
}
svg circle {
fill: green;
}
svg:before {
border: 2px solid blue;
content: "";
height: 100px;
margin: -6px;
padding: 4px;
position: absolute;
width: 100px;
z-index: -1;
}
div {
background-color: green;
height: 100px;
left: 200px;
position: absolute;
top: 150px;
width: 100px;
}
div:before {
border: 2px solid blue;
content: "";
height: 100px;
margin: -6px;
padding: 4px;
position: absolute;
width: 100px;
z-index: -1;
}
<svg height="100" width="100" xmlns="http://www.w3.org/2000/svg">
<circle cx="50" cy="50" r="50" />
</svg>
<div></div>

No, inline SVG is treated as an image, and images are replaced elements which are not allowed to have generated content.
Strictly speaking, I think it's undefined. CSS 2.1 just talks about "images, embedded documents and applets" in general and The HTML standard defines it for images, but not SVG explicitly.

Related

Pseudo element not showing in react

.input-select{
position: relative;
height: 100%;
}
.input-select::before{
content: '';
position: absolute;
display: inline-block;
height: 50px;
width: 50px;
background-color: red;
z-index: 100;
}
<div className="input-group">
<label htmlFor="type">GST Type: </label>
<select name="type" id="type" className="input-select">
<option>Registered</option>
<option>Unregistered</option>
</select>
</div>
I have tried setting body and html height to 100% as well as setting .input-select height to 100%.
I have have tried setting display to block or inline block and setting z-index to a high value.
However so far I have not been able to make it work.
On select, we can't have pseudo selectors. You have to make one wrapper div and then on that div, you can give after, before.
<div class="input-select">
<select>
<option>United Kingdom</option>
<option>Canada</option>
<option>United States</option>
</select>
</div>
.input-select::before{
content: '';
position: absolute;
display: inline-block;
height: 50px;
width: 50px;
background-color: red;
z-index: 100;
}
You can not put a pseudo element in an input element,however you can put a hover pseudo element. Elements starting and closing in a single place like is not a container element.You can use hover here but not ::before and ::after
.input-select{
position: relative;
height: 100%;
}
.input-select:hover{
content: '';
position: absolute;
display: inline-block;
height: 50px;
width: 50px;
background-color: red;
z-index: 100;
}
Pseudo-elements are only allowed to be used on container elements. Elements like inputs, select, images, and any other self-closing element can’t use pseudo-elements because they aren’t “container elements.
The select box can't have a pseudo-selector. So, add one parent div and then use those selectors. Also add top/bottom/left/right positions in CSS.
This might help with troubleshooting-- I was having this problem and found that since I was calling the CSS in a module.css file (which adds extra characters to the class name when the page loads), the ::after pseudo element code wasn't being picked up, even though normal classes and ids were. When I moved just the pseudo element class to a normal / sitewide CSS file, it worked.

Setting pseudo-element dimensions in CSS

I am currently attempting to set the :before pseudo element width, to match the dimensions of the element itself (in this case, an anchor tag), with the aim of creating an overlay which covers the entire element. To demonstrate, for this example, I will consider Google's web page for a demo:
a.gb_g::before {
background-color: rgba(255, 0, 0, 0.2);
position: absolute;
content: 'hello';
display: block;
position: absolute;
}
<div class="gb_h gb_i">
<a class="gb_g" data-pid="23" href="https://mail.google.com/mail/?tab=wm&ogbl">Gmail</a>
</div>
However, this produces the following result:
I have also attempted to set width: 100%, yet this results in container overflows. Is it possible to set the pseudo element width, to perfectly match that of the element itself (in this case, the 'Gmail'/'Images' link)? The desired result is for the overlay to fully cover each of the anchor tags, without making any CSS changes to the element itself.
Basically, I'm faced with a scenario where I have a fixed web page layout (with existing styling I have no control over), for which I would like to highlight parts of the web page (including some of the links). So, ideally any proposed solutions would cause minimal impact on the existing page layout, which is why I attempted to opt for an entirely pseudo-element based solution.
Does this work for you? Adding position: relative to the element, and width: 100% to the pseudo element solved it for me.
a.gb_g::before {
background-color: rgba(255, 0, 0, 0.2);
position: absolute;
content: 'hello';
display: block;
position: absolute;
width: 100%;
}
a.gb_g{
position: relative;
}
<div class="gb_h gb_i">
<a class="gb_g" data-pid="23" href="https://mail.google.com/mail/?tab=wm&ogbl">Gmail</a>
</div>
Not sure if this is exactly what you are looking for, but you can add "position: relative" for the actual element, then "width: 100%" for ::before. You can use "overflow: hidden" and "white-space: nowrap" to fully contain the pseudo element.
a.gb_g {
position: relative;
}
a.gb_g::before {
background-color: rgba(255, 0, 0, 0.2);
position: absolute;
content: 'overlay text long';
color: white;
display: block;
width: 100%;
overflow: hidden;
white-space: nowrap
}
<div class="gb_h gb_i">
<a class="gb_g" data-pid="23">Original Text</a> Next
</div>

SVG inside link not clickable in IE11 when pointer-events set to None

I have an HTML/CSS file similar to this.
.window{
position: absolute;
width: 150px;
height: 100px;
background-color: #424242
}
svg{
pointer-events: none;
}
.b{
height: 40px;
width: 40px;
position: absolute;
bottom: 8px;
right: 8px;
}
<div class="window">
<div class="b">
<a href="https://www.google.com" target="_blank">
<svg height='100%' width='100%'>
<rect width='100%' height='100%' style='fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)'></rect>
</svg>
</a>
</div>
</div>
On Chrome, I am able to click the blue SVG with the link, but on IE11, I am not. Does anyone know why this is the case, and what I can do to fix it on IE, without impacting other browsers? The SVG rule is for some other SVGs, so it would be nice to not have to change it.
Thank you!
The problem is not the SVG itself or the pointer-events. The problem is the a tag, and how IE 11 renders the tag when it contain block elements inside.
The solution i tested is to style the a tag to fill its container:
a {
overflow: hidden;
display: block;
width: 100%;
height: 100%;
}
I encountered this problem before, with SVG's as images, in older versions of Internet Explorer.
Hope it helps!
.window{
position: absolute;
width: 150px;
height: 100px;
background-color: #424242
}
svg{
pointer-events: none;
}
.b{
height: 40px;
width: 40px;
position: absolute;
bottom: 8px;
right: 8px;
}
a {
overflow: hidden;
display: block;
width: 100%;
height: 100%;
}
<div class="window">
<div class="b">
<a href="https://www.google.com" target="_blank">
<svg height='100%' width='100%'>
<rect width='100%' height='100%' style='fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)'></rect>
</svg>
</a>
</div>
</div>
EDIT: I will write this trying to explain my experience about it. Old browsers, including old versions of Firefox, Chrome and Internet Explorer, did not suppoted to nest block elements inside inline elements. So if you tried to nest a div element inside an link, it will cause that the user won't be able to click on the link and some other strange behaviors. New browsers support some of those techniques (for example, a link with some div layout inside so all the block is clickable). IE11 is on the fence. Also i encontered some issues with SVGs and IE11, even using the SVG as an image (thru an img tag and an external SVG file).
The main problem is that some css attributes can not being setted in onlder browsers, like witdh, height and vertical padding (padding top and bottom). So if you nest a block element inside an inline element, and the element overflows the inline element dimensions (inherited by font size, line height and vertical align of the element), the inline element will not be rendered properrly.
Hope this little edit help you understand the problem.
I can't currently test this myself, but give this a try:
svg{
pointer-events: none
}
svg>rect{
position: relative;
pointer-events: auto;
}
I am referencing this: https://css-tricks.com/almanac/properties/p/pointer-events/#comment-1108851
I edited my answer. To be honest, I'm not exactly sure why you wish to do this. What use does disabling the pointer-events on the svg provide if you wish to click it?

Styling quotation marks

I have run into and issue when styling quotes. So what I'm trying to do is pull the quotation marks down a bit relative to the text so that it lines up well. I played around with relative and absolute positioning but could not figure it out. This program will become a random quote generator and the position of the end quote has to be such that it lines up the same way relative to the text if it there is a quote that takes up several lines.
body {
background-color: rgb(44, 62, 80);
}
.quoteMachine {
margin: 100px auto 0 auto;
padding: 40px 60px;
max-width: 600px;
min-height: 225px;
border-radius: 5px;
background-color: white;
}
.theQuote {
text-align: center;
font-size: 30px;
color: rgb(44, 62, 80);
}
.quotetationMarks {
font-size: 60px;
font-weight: 600;
}
.quoteAuthor {
text-align: right;
font-size: 20px;
color: rgb(44, 62, 80);
}
.twitterButton {}
<div class="quoteMachine">
<div class="theQuote">
<blockquote><span class="quotetationMarks">“</span > They call me Mister Tiibs <span class="quotetationMarks">”<span></blockquote>
</div>
<div class="quoteAuthor">
- hello
</div>
<button class="twitterButton"></button>
<button class="newQuoteButton"></button>
</div>
Since the spans are inline elements, you could add vertical-align: middle; to .quotetationMarks and that would move them down toward the middle of the rest of the string.
Alternatively, you could add position: relative; top: 10px; if you need more precise control.
Maybe adding vertical-align: sub; to .quotetationMarks is what you are looking for?
You can also use fontawesome, that's always a good option. -> http://fontawesome.io/icon/quote-right/
Edit: While vertical-align: middle; is a very valid and elegant approach, sometimes you've got a very specific position in mind for the quotation marks. If you need to match a mockup to pixel perfection, this approach grants you the flexibility.
You might get some mileage out of using pseudo-elements to render the quotes, and relative/absolute positioning to get them "just so".
This is especially important to help position them across line breaks. (I've edited my example to force a line break, in order to illustrate the robustness of this approach.)
From MDN:
Just like pseudo-classes, pseudo-elements are added to selectors but instead of describing a special state, they allow you to style certain parts of a document. For example, the ::first-line pseudo-element targets only the first line of an element specified by the selector.
And specifically for the ::before pseudo element:
::before creates a pseudo-element that is the first child of the element matched. It is often used to add cosmetic content to an element by using the content property. This element is inline by default.
These quotes you're styling are cosmetic content, so I think that this is a great use-case for the ::before pseudo element.
I've forked your codepen here: http://codepen.io/cam5/pen/kkxpbX, but here are the relevant parts
<!-- quote HTML -->
<blockquote>
<span class="quotationMark quotationMark--left"></span >
They call me…<br /> Mister Tiibs
<span class="quotationMark quotationMark--right"></span >
</blockquote>
and the CSS:
/* quote css */
.quotationMark {
position: relative;
}
.quotationMark--left::before,
.quotationMark--right::before {
font-size: 60px;
font-weight: 600;
position: absolute;
top: -15px;
}
.quotationMark--left::before {
content:"\201C";
left: -45px;
}
.quotationMark--right::before {
content:"\201D";
right: -45px;
}
This CSS Tricks resource is great when you're trying to locate the ISO for putting a certain glyph into a CSS content rule: https://css-tricks.com/snippets/html/glyphs/
Setting the parent element, the .quotationMark to display: relative; will mean that the top, right, left values passed to the children (the pseudo-elements) of it bearing the position: absolute; property are calculated relative to their parent.

How do I turn the trapezoid opposite?

I've a trapezoid shapes in CSS, but the problem is that I also need the same kind of trapezoid turning the borders opposite, the first trapezoid css is something like this:
#trapezoid1 {
height: 0;
width: 350px;
border-bottom: 190px solid rgb(2, 145, 178);
border-left: 45px solid transparent;
border-right: 45px solid transparent;
padding: 0 8px 0 0;
display:block;
position:relative;
}
But I also need the second trapezoid turning the border-bottom to border-top, however in that case, the text is being flew away from the actual trapezoid.
I did border-top instead of border-bottom to turn the trapezoid opposite.
Here's the full display of the problem.. jsfiddle
Your best option is to use pseudo elements so you dont have to use absolute positioning on the text element.
Using both :before and :after will help create the desired shape. The borders are also transparent so you don't have to worry about background images being coloured over.
#trapezoid {
width: 260px;
height: 190px;
background: red;
margin-left: 45px;
position: relative;
}
#trapezoid:before {
content: '';
border-right: 45px solid red;
border-bottom: 190px solid transparent;
position: absolute;
left: -45px;
top: 0;
}
#trapezoid:after {
content: '';
border-left: 45px solid red;
border-bottom: 190px solid transparent;
position: absolute;
right: -45px;
top: 0;
}
<div id="trapezoid">
Text in here
</div>
You can also refer to one of my previews answers which give a good overview at all of the different possible ways of creating a CSS trapezoid.
Responsive CSS Trapezoid Shape
How about this:
HTML (add span tags around trap2 text)
<div id="trapezoid1">
Designing Something
</div>
<br/>
<div id="trapezoid2">
<span id="trap2-text">Designing Opposite</span><!-- NEW -->
<!-- I need the text in proper place which currently isn't -->
</div>
CSS (add one rule)
#trap2-text {
position: absolute;
top: -190px;
left: -25px;
}
DEMO
I generally like pure css shapes, but I thought SVG might make your life easier in this case so I started fiddling around with your fiddle. I'm not completely satisfied with the results but it gives some advantage like dynamic size.
Fiddle with comments: http://jsfiddle.net/bo5k36pa/8/
If you want to use this solution I highly recommend to encode your inline svgs in base64 to avoid compability and encoding problems. See this answer for details.
Explanation
The idea was to use an inline svg as background image, so it will stretch to containers of any size.
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 4 2" preserveAspectRatio="none"><path style="fill: rgb(2, 145, 178);" d="M 0.5 0 L 3.5 0 L 4 2 L 0 2 Z" /></svg>');
background-size: 100%;
The path that makes up the trapez could be modified, if different angles or shapes are required, it could even be generated dynamically using javascript. But the real bummer here is, we can't style inline svg background images. Meaning for example to change just the fill color we have to define the entire svg markup again.
Possible solutions to avoid multiple inline svgs
Use <use>. You can define <symbols> in an external svg file and reference them in an inline <svg> via their id attributes. And we can still style those symbols using CSS. However, it would require a fair amount of extra markup in every container. Something like this:
<svg viewBox="0 0 4 2" role="img" title="Trapez"><use xlink:href="path/to/images/shapes.svg#trapez"></use></svg>
Use CSS filters to change appearance. Example fiddle / Browser Support
Go back to CSS Shapes. I'd recommend to take advantage of :before and :after pseudo elements to keep such fancy appendages a bit separate from your content box.