Combine CSS Attribute and Pseudo-Element Selectors? - css

How can I combine a pseudo-element selector (:after) with an attribute selector ([title])?
I tried using div[title]:after, but this doesn't work in Chrome.
HTML:
<div title="foo">This div has a title.</div>
<div>This div does not have a title.</div>
CSS:
div:after {
content: "NO";
}
div[title]:after {
content: "YES";
}
Demo: http://jsfiddle.net/jmAX6/
It shows me "YES" at the end of each of those div's, when it should show "NO" after the second div.
I'm running Chrome 17.0.963.38. It seems to work fine in Safari 5.1.2.

This looks like a bug, which has finally been reported. If you add a CSS rule for div[title] anywhere in your stylesheet with at least one declaration, your div[title]:after rule will magically apply. For example:
div:after {
content: "NO";
}
div[title] {
display: block;
}
div[title]:after {
content: "YES";
}
See the updated fiddle.
It also seems to have something to do with your second div having or not having certain HTML attributes, as shown in the comments below.

Related

How to change the CSS style of first-letter when hover over a parent element?

This is likely something I am just stupidly overlooking, but would you please tell me why hovering over the second division element doesn't cause the background color of the first letter to change to rgb(50,50,50) from rgb(150,150,150)?
Hovering over the first division, which starts out with no styling on the first letter, reacts to the style changes upon hover. But the second division, which starts out with the same styles that the first displays upon hover, does not change to the darker background upon hover.
I'm using the latest version of Firefox developer edition. I see now that it works in Chrome; so must be a Firefox issue.
Thank you.
div > p:before { content: 'This text.'; }
div:nth-child(2) > p::first-letter,
div:first-child:hover > p::first-letter
{
float: left;
padding: 0.5rem;
background-color: rgb(150,150,150);
}
div:nth-child(2):hover > p::first-letter
{
background-color: rgb(50,50,50);
}
<div><p></p></div>
<div><p></p></div>
This snippet works in Firefox. It seems that to get the ::first-letter to be styled both without and with :hover a letter has to be there apart from the content added by :before or :after.
div > p:after { content: 'his text.' }
div > p::first-letter
{
float: left;
padding: 0.5rem;
background-color: rgb(150,150,150);
}
div:hover > p::first-letter
{
background-color: rgb(70,70,70);
color: white;
}
<div><p>T</p></div>
I applied #Sydney Y's solution to the above snippet just to show that it works in Firefox. I don't think it is an isue of the :hover not being recognized because the snippet above recognizes it. It appears to be an issue of not including the text added through :before { content: ... } such that there is a first letter to which to apply the style. But adding no content on :hover using :after seems to alter that and works for variable content.
I realize that this of little interest to anyone who doesn't want to use drop caps and change their style based on hover.
div > p:before { content: 'This text.' }
div > p::first-letter
{
float: left;
padding: 0.5rem;
background-color: rgb(150,150,150);
}
div:hover > p::first-letter
{
background-color: rgb(70,70,70);
color: white;
}
div:hover > p:after { content: ''; }
<div><p></p></div>
Yep, just some mix-ups, your accessors are correct. Each block of CSS needs to apply to both divs:
div > p:before { content: 'This text.'; }
div> p::first-letter {
padding: 0.5rem;
background: red;
}
div:hover> p::first-letter{
background: black;
}
div:hover > p:after { content: ''; }
Thanks for the snippet, that's cool!
Edit: getting closer! Code is updated. Still attempting on Firefox.
Edit: Solved, kind of. It works, but it's kind of a hack. The
issue: In Firefox the hover doesn't trigger a repaint in this specific
instance, so I added an empty bit of content on hover because the
:after or content seem to have a kind of a hook. You may be able to
achieve the same thing with a different hack other than content.
But good news is: this works in both Chrome and Firefox.
Awesome problem. I can't imagine ever coming across this issue again, but it was super interesting to troubleshoot.
There is a bug in firefox that nth-child() is not going to work on syntax that's why it is not working. Anyway if not want the same functionality as first one with different color this can be done with you just need to put hover in front of this code
"div:nth-child(2) > p::first-letter,div:first-child:hover > p::first-letter ". I hope this will help. https://developer.mozilla.org/en-US/docs/Web/CSS/:nth-child

CSS not updating in IE / Edge?

Here is the JsFiddle
I have a css rule depending on the display status of a neighbor:
#top:not([style*="display: none"]) + #bottom {
color:red;
}
When I hide the '#top' div using javascript, the color changes since the css rule is no longer valid.
This is not the case in Internet Explorer and Edge ! Am I doing something wrong or is this just a bug in Microsofts browsers ?
I would avoid that approach, as it's somewhat fragile. Instead, explicitly toggle a class on a parent element or #top, and make your CSS changes based on that:
body.toggled #bottom {
color:red;
}
body.toggled #top {
display: none;
}
$("#btn").click(function() {
$('body').toggleClass('toggled');
});
Demo

Children :before content inheritance

The title might be a little bit confusing but I wonder why is it impossible for a child element to inherit it's parent ::before content. for example:
HTML:
<div class="foo">
<div class="baz"></div>
</div>
CSS:
.foo::before {
content: 'bar';
}
.foo .baz::before {
content: inherit;
}
I have tried it that way, and even this way:
.foo > .baz::before {
content: inherit;
}
and this one:
.foo::before ~ .baz::before {
content: inherit;
}
...and none of the above worked... Is it possible at all? if not, which options do I have in order to achieve this?
UPDATE
I think I might found a way to do such thing:
.foo {
content: 'bar';
}
.foo > .baz,
.foo > .baz::before {
content: inherit;
}
A ::before/::after pseudo-element cannot inherit from another ::before/::after pseudo-element. A pseudo-element can only inherit from its originating element — this is the element that the pseudo-element is attached to. A pseudo-element cannot even inherit from the parent of its originating element, unless the originating element itself is also inheriting from its parent and the property involved is not content.
In your example, .foo::before can only inherit from the .foo it's attached to, and likewise for .baz::before and .baz. .baz::before cannot inherit from .foo::before, so what you're trying to do is not possible. There does not appear to be a reliable way to ensure that one pseudo-element always inherits from another pseudo-element through CSS alone without enforcing this within the markup itself.

CSS label :before and :after

I am learning CSS and I am having a bit of trouble recognizing properties and understanding some of the syntax. in the CSS below.
.tabs nav li.tab-current:before,
.tabs nav li.tab-current:after {
}
I understand that tabs is a class and the nav li with the class tab-current within the tabs class in html will be applied with the same CSS.
Example:
<div class="tabs">
<nav>
<ul>
<li class="tab-current">Hey</li>
<li>hello</li>
</ul>
</nav>
</div>
However I'm not quite sure what :before and :after represent. Could someone provide me with an example? Thank you
They set something after and before the element you are selecting. For example:
p:after {
content: 'hi! im after';
}
p:before {
content: 'hi! im before';
}
You will understand it better if you see this fiddle.
:before and :after create pseudo elements as 'children' for the element they are applied to. They are often used for certain stylings, or error messages.
Fiddle: http://jsfiddle.net/XjUM8/1/
div:before {
content: "Before";
background: red;
}
div:after {
content: "After";
background: blue;
color: white;
}
You can also set them up to show up on hover
Fiddle : http://jsfiddle.net/XjUM8/2/
div:hover:before {
content: "Before";
background: red;
}
div:hover:after {
content: "After";
background: blue;
color: white;
}
Also, take a look at MDN :
Before & After
:before and :after are CSS Selectors that allow you to add content before or after the element in question. An example is of adding an arrow after a link to show progress:
HTML
<div class="testAfter"><a>Arrow After this link</a></div>
<div class="testBefore"><a>Arrow Before this link</a></div>
CSS
.testAfter:after{
content:"\25B6"
}
.testBefore:before{
content:"\25C0"
}
Fiddle to show:
http://jsfiddle.net/yPkVL/1/
You can add all kinds of things; images, text, etc. You can style them and add different positionings. You can do all kinds of things. It's like adding an extra div before or after the div in question without having to change the HTML markup.
Reference:
Before
After
:after and :before are called pseudo-elements. They're used to inject some content to your DOM through the CSS.
For instance, say you want to add an icon after every link that targets external websites (we'll assume that these links href all begin with "http://"). This would be a real pain in the neck to try and append this manually. Using the CSS pseudo-element :after, you can simply do something like this :
a[href^="http://"]:after {
content:url('href.png');
}
and bam ! You're good to go.
:after and :before allow you to simply inject some text or image, but they can also be used in many creative ways.
Beware though, they can be applied to anything except "replaced elements" : this means that you won't be able to use those pseudo-elements on tags such as <input>, <textarea>, <object>, <img>, etc.
The W3School explains it pretty well, did you read that up and not understand something?
Essentially what it means is you're going to insert whatever is in the :before area before what content is already in there, and the :after after the content.
:before and :after are selectors, they're used to select what you want to style.
The example on w3schools is as follows:
<!DOCTYPE html>
<html>
<head>
<style>
p::before
{
content:"Read this -";
}
</style>
</head>
<body>
<p>My name is Donald</p>
<p>I live in Ducksburg</p>
<p><b>Note:</b> For ::before to work in IE8, a DOCTYPE must be declared.</p>
</body>
</html>
What this does is print out:
Read this - My name is Donald and Read this - I live in Duksburg
After will esentially do the same thing.
There are

CSS :before and :first-child combined

I'm using the following code to add separators between my menu items:
#navigation_center li:before {
content: "| ";
color: #fff;
}
Now I want the first item not to have a separator in front of it, so I figured out the following code:
#navigation_center li:before:first-child {
content: none;
}
but that's not doing anything. Is it possible to combine :before and :first-child?
Try
#navigation_center li:first-child:before {
content: '';
}
Edit: I wanted to expand on this answer with comments made by FelipeAls. The original question used :first which is not a valid CSS selector. Instead, use :first-child. Also the order of the pseudo-selectors is important. The first child selector must come first.
I tend to think of :before as a kind of modifier to a selector. It does not actually select an element only the space just before the selected element.
Although hradac's answer should do the trick i thought it would be best to run through some possible permutations to help newcommers.
.works:first-child:before
{
color: green;
content: 'working ';
}
.works:not(:first-child):after
{
color: green;
content: ' is working';
}
.broken:before:first-child
{
color: red;
content: 'this will never show up';
}
.broken:after:not(:first-child)
{
color: red;
content: 'and this will not show up either';
}
works:
<div>
<div class='works'>
something
</div>
<div class='works'>
something
</div>
<div class='works'>
something
</div>
</div>
<hr/>
broken:
<div>
<div class='broken'>
something
</div>
<div class='broken'>
something
</div>
<div class='broken'>
something
</div>
</div>
Let's take this apart:
Three div.works are inside a div
Three div.broken are also inside a div
The first rule of CSS adds a green text "working " before. It does so by selecting the first-child and then selecting the empty space right before it.
The second rule adds " is working" after each block that comes after first, by analogy it first selects each block that doesn't fall under the first-child definition, and then selects the empty space before them.
The following two rules, will not find a block to attach themselves to. The :before:first-child attempts to select an empty space, but then tests if it is a first-child and it is not (since technically it's not yet in the DOM tree), the similar problem is with :not(:first-child).

Resources