How could I use pseudo-element :after :before conditionally - html

If I wanted to only insert a pseudo-element after a link only if the link is followed by another element say ul. How could I do this?
Example:
<ul>
<li>
blah<!-- insert -> here with CSS -->
<ul>
<li>More stuff</li>
</ul>
</li>
<li>
blah 2<!--Do nothing here-->
</li>
</ul>
CSS I wish could happen:
ul li a:after if(next:ul) {
content:"->";
}
I'm not trying to use JavaScript/jQuery. And I realize if conditions are not apart of css.
Is there a way to do this?

In general it is not possible to select elements based on their next sibling.
In your specific case, you can use ul li a:not(:last-child)::after, because it happens that your anchors that are not followed by an <ul> element are also the last child element.

You can simply use:
ul + li a:after { /* ...css code... */ }
Basically this means:
Match an a element contained in a li element that is immediately preceded by an ul element.
The + operator in CSS is called adjacent sibling combinator.

If you want to filter any element in the hierarchy/list of elements you can use the below approach.
ul li a:not(:nth-last-child(N))::after
Here N is any positive integer traversing from the end; 1 means the last element 2 means second last and so on. Instead of ul li use any selector here
For more information visit nth-last-child().

Related

CSS descendants and other selectors

With the following HTML, does my CSS display as I have stipulated below?
HTML:
<ul>
<li>1</li>
<li>2</li>
<ul>
<li>3</li>
</ul>
<li>4</li>
</ul>
CSS:
ul + li /* 1 and 3 */
ul > li /* 1, 2 and 3 */
ul ~ li /* 1, 2, 3 and 4 */
Equally important, where did I go wrong?
There's quite a lot going on here so I'm going to try to break it down for you one by one. This will be long, but bear with me.
Let's make the indentation a little more consistent so we can see what's going on with the HTML:
<ul>
<li>1</li>
<li>2</li>
<ul>
<li>3</li>
</ul>
<li>4</li>
</ul>
When you open the first ul, and start adding lis to it, those li elements are children of the first ul. They appear inside it, or more precisely, between its start tag <ul> and its end tag </ul>.
By the time you open the second ul, you've already closed the second li with its own end tag. The second ul is not a child of that li because it appears after its end tag </li>. So the second ul — the inner one if you will — is a sibling of the second li, and therefore a child of the first (outer) ul. The fourth li, similarly, is a sibling of the second ul, and also a child of the first ul.
The third li is a child of the second (inner) ul. It is neither a child nor a sibling of any of the other elements. It is a grandchild of the first (outer) ul, but it doesn't matter for the sake of answering your question.
If the markup appears visually similar to a family tree, it should make sense to you. In a family tree, children appear under a parent. (Only, in a family tree, there are typically two parents; in HTML, every child has only one parent.) Children that are siblings of one another appear side by side, connected to the same parent. This markup is structured similarly, except the children are listed top to bottom instead of left to right. But they're still "side by side", logically speaking.
Recall what the following selectors do:
ul + li matches a li that's a sibling appearing immediately after a ul.
ul > li matches a li that's a child of a ul.
ul ~ li matches a li that comes after a ul as a sibling, but unlike with + it doesn't have to appear immediately after, as long as they're between the same set of opening and closing tags (this is called "having the same parent element"). Any ul + li is automatically also a ul ~ li.
Here's the markup again with some annotations:
<ul>
<li>1</li> <!-- ul > li -->
<li>2</li> <!-- ul > li -->
<ul>
<li>3</li> <!-- ul > li -->
</ul>
<li>4</li> <!-- ul > li, ul + li, ul ~ li -->
</ul>
Indeed, none of the first three li elements are siblings of any ul. Only the very last one is, and it matches both sibling selectors.
So how do you make the inner ul a child of the second li? You do this by moving the </li> so that it appears after the </ul> like so:
<ul>
<li>1</li> <!-- ul > li -->
<li>2 <!-- ul > li -->
<ul>
<li>3</li> <!-- ul > li -->
</ul>
</li>
<li>4</li> <!-- ul > li, ul + li, ul ~ li -->
</ul>
Critically, the inner ul will now match a different selector: li > ul. Additionally, your markup will now validate, as you are never allowed to have a ul as a child of another ul in the first place.
Finally, some of your stipulations require more complex selectors as they match pretty specifically. I'll walk you through each one:
To match 1 and 3, use ul > li:first-child. This is because 1 and 3 are the first children of their respective parent uls. You can usually tell if an element is the first child of another because its start tag is the first thing that appears after the parent's start tag, ignoring any text or whitespace.
To match 1, 2 and 3, use ul > li:first-child, ul > li:nth-child(2). The additional :nth-child(2) targets item 2 specifically.
To match 1, 2, 3 and 4, using ul > li is enough, since you're just matching them all. You can probably get away with just li if you only have ul in your markup, but this is unlikely to be the case so I'm erring on the side of being more specific than necessary, rather than not being specific enough.
It's a lot to take in, so let me know if any of this is confusing or overwhelming and I'll try to address your concerns.

Nesting child selectors in CSS

I have this HTML:
<div class="navbar">
<ul>
<li>Foo
<ul>
<li>Bar</li>
</ul>
</li>
</ul>
</div>
I want to apply CSS only to item "Foo." I do not want to tag every top-level <li> with a special class. My limited knowledge tells me I should be able to do this:
.navbar > ul > li {
text-transform: uppercase;
}
But the style gets applied to "Bar" as well when I do it like this. I thought that '>' specifies only immediate children, does it not work the same way when it's nested? Is what I'm trying to do even possible?
I thought that '>' specifies only immediate children, does it not work the same way when it's nested?
It does work the same way. Since you're anchoring the ul directly to .navbar with .navbar > ul, your selector does apply to li elements directly that particular ul only.
The problem is not with the selector; it's the fact that text-transform, like most text properties, is inherited by default. So even though you're applying the style only to immediate li elements, the nested ones receive it by inheritance.
You will need to reverse this manually on the nested elements:
.navbar > ul > li li {
text-transform: none;
}

Block Desendants while selecting child elements

I am trying to make a drop down list by using nested Un ordered lists.
My case is i have an unordered list, which is having another unordered list inside of its li element. I had written hover for the first level li elements by using the child selector. My problem is while hovering the first level li element, the css for its hovering process is also get applied to its child li element. My question is why does the child selector selecting its descendants in my case..? and what should i do to avoid this in future.?
DEMO - Fiddle
Here is the solution below:
My question is why does the child selector selecting its descendants in my case..?
Because you have defined one part of the CSS by adding #ULHeaderMenuWrapperMenuCollection > li:hover
what should i do to avoid this in future.?
You have to protect the inheritance by adding #ULHeaderMenuWrapperMenuCollection > li:hover div ul li to your CSS. Here is the Working Solution.
#ULHeaderMenuWrapperMenuCollection > li:hover div ul li
{
color:black;
}
#ULHeaderMenuWrapperMenuCollection > li:hover div ul li:hover
{
color:orange;
}
Hope this helps.
Updated to fit to your original code
When you mouse is hover your sublist, it's still hover the main one.
I suggest you to put your <li> text in a <span> or a <a>, which makes your css simplest :
HTML
<ul id="ULHeaderMenuWrapperMenuCollection">
<li>
<span>Products</span>
<div id="DivProductsMenu">
<div id="DivProductsMenuUpper">
<ul>
<li><span>CIMS</span></li>
<li><span>VPRO</span></li>
<li><span>BIRIS</span></li>
</ul>
</div>
<div id="DivProductsMenuLower">
<ul>
<li><span>PATRON</span></li>
<li><span>DEAL</span></li>
<li><span>MEDIX</span></li>
</ul>
</div>
</div>
</li>
<li>
<span>Contact Us</span>
</li>
</ul>
CSS
#ULHeaderMenuWrapperMenuCollection li > span:hover {
color:orange;
}
JsFiddle

Applying different style rules to different elements

I have a bunch of unordered list elements that are stacked side by side with each other. To accomplish this, the style rule typically applied is:
#slide ul,li{
float:left;
list-style-type:none;
}
I need to introduce another unordered list of elements that behave the way the ul and li element typically do; that is stacked on top of each other but without any list-style-type, and to achieve this:
.stack ul,li{
list-style-type:none
}
​
The problem is that the styles of stack class for ul,li do not apply and the elements stack next to each other as they are being in the case of ul,li for #slide.
Check it out on this js fiddle:
http://jsfiddle.net/G7JHK/
Are my selectors wrong?
P.S: I have tried this out with class/id and various combination of both but the result is always the same.
Because of the comma in your selector you were applying float left to all li elements. Try something like this:
<ul class="stack">
<li>element 1</li>
<li>element 2</li>
</ul>
<br/>
<ul id="slide">
<li>element 3</li>
<li>element 4</li>
</ul>
#slide li{
display:inline;
}
This css will make all list elements in the div 'slide' display in a row and all other list elements will continue to display like normal. It saves you having to use two different classes :)
​
Your CSS should be like so
ul.stack li{
display:block;
}
ul#slide li{
float:left;
}
​
I think you want something like:
ul.stack li{
display:block;
}
ul#slide li{
float:left;
}
Look at the selectors. You want to select a ul with class stack (ul.stack) and find its child li.
There is problem of your selector. class or id of same element never separated by a white space. They should be with no space and the child are separated by a space but no ',' will not be used there..
So you can try this in your code
ul.stack li{
display:block;
}
ul#slide li{
float:left;
}
Also you have to place the HTML tag name first and then the preceding attribute.
The problem is that you selected the ul that is a descendent of slide, but your ul has an id of slide, so it doesnt work, because there is no ul that has a container with an id of slide. Also by putting ,li you are selecting all list items on the page. You want to have #slide li, which will only select the list items with a container id of slide. You don't need the #slide ul so your final code should be
#slide li {
float:left;
}
http://jsfiddle.net/G7JHK/6/
As an alternative, you could use ul:nth-of-type(2) instead of an id to save some space in the html
http://jsfiddle.net/G7JHK/7/

Pseudo-class inside :not

Is it possible to use a pseudo class inside of a :not tag?
Example:
li:not(.inner:hover):hover { // Code }
<li>
<div class="inner"></div>
</li>
I am trying to cancel out the effect of the parent hover, when I hover an inner item, without using javascript.
The expected result for above code is when you hover the li, but not the inner div, the li get's a hover effect. But only if you're not hovering the .inner.
Update
http://jsfiddle.net/eTV86/
What I want is, when the .inner turns black, the li turns back to red.
Yes, but you're using both a class and a pseudo-class, which is invalid:
li:not(.inner:hover):hover
Even if you change it to something that's valid (as per this answer):
li:not(.inner):hover, li:not(:hover):hover
The first selector will always match your li on hover, and the second selector won't ever match anything. It will never match your div.inner because you're attaching the :not() to the li.
Lastly, if you want to change the li when .inner gets a hover, that's not possible with current CSS selectors. You'll need JavaScript.
You can use the simple css instead pseudo class
HTML
<ul>
<li class="active">Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
</ul>
​
​
CSS
ul li a{ color:black}
ul li a:hover { color:red }
ul li.active a:hover { color:black /*re use the same properties which is there in default style viz ul li a{} */}
DEMO http://jsfiddle.net/mKQas/2/