Difference between "#id li{...}" and "#id > li{...}" - css

I came across these two somewhat similar things. In one of my applications, there is a difference between these two, especially when using IE7. I wonder: what is the big difference between these two. Feel free to elaborate and site links.

The space selects all descendants. The > selects only direct descendants ("child" elements).
See this w3 page for a great overview of all selectors. From that page:
E > F ... an F element child of an E element ... child combinators
And:
E F ... an F element descendant of an E element ... descendant combinator
Note that this difference isn't particular to IE7. All decently modern browsers support both syntaxes. The same selectors also exist in CSS2. On quirksmode I only see that IE6 and below (*shudder*) have issues with the child selector.

This will apply to all li elements beneath the #id element
#id li
This will apply only to the li elements directly below the #id element
#id > li

The difference between the standard X Y and X > Y is that the latter will only select direct children. For example, consider the following markup.
<div id="container">
<ul>
<li> List Item
<ul>
<li> Child </li>
</ul>
</li>
<li> List Item </li>
<li> List Item </li>
<li> List Item </li>
</ul>
</div>
A selector of #container > ul will only target the uls which are direct children of the div with an id of container. It will not target, for instance, the ul that is a child of the first li.
For this reason, there are performance benefits in using the child combinator. In fact, it’s recommended particularly when working with JavaScript-based CSS selector engines.
Source: http://net.tutsplus.com/tutorials/html-css-techniques/the-30-css-selectors-you-must-memorize/

Related

select previous and next elements on hover

I have some html which looks something like this
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
I want to apply a style on any specific <li> on hover AND apply a different style to the previous and next <li> elements (the one next to the hovered one).
If possible I want to do this with pure css (no JS).
So to be clear there are 3 different states and 3 different sets of styles a <li> could have
the element is hovered over.
the element is not hovered over but the element before or after it is hovered over.
the element is not hovered over and the elements before or after it are not hovered over.
I know that the :hover psudo selector can be used to apply a style to the hovered element - no problem
I know that the next element can be selected with :hover + li - no problem
Applying a style to the previous element is however a problem.
I know there is no previous sibling selector, is this still the case?
I have looked at another stack overflow post which talks about applying a style directly to the previous sibling and then using two adjasent sibling selectors to apply styles to the 2nd and 3rd elements. I cant do that in this case because the hover has to be on the 2nd element.
I have considered using [attribute] selectors combined with attr()
my plan would be to give each li a data attribute and a unique specific number, ie <li data="1">
on hover the attr() feature would be used to read the previous elements data attribute and then pass that to the [attribute] selector.
it might look something like this
li:hover [data-number-type=attr(data-number-type)]
<ul>
<li data-number-type="1">Owl</li>
<li data-number-type="2">Owl</li>
<li data-number-type="3">Owl</li>
<li data-number-type="4">Owl</li>
<ui/>
That snippet of code does not work.
but is there any way to get something like that working?
Is there any other css only way that i have not considered?

CSS general sibling combinator (~) not working with negation pseudo-class (:not)

I have a contact list that is generated as an unordered list with HTML5 data attributes assigned to each list item. The values of the data attributes are single letters for alphabetizing purposes. I have no control over the markup that is generated, but I need to insert a section title before the first entry for each letter. This I hope to achieve with the :before pseudo-element. Nothing out of the ordinary. I have a lot of freedom with the CSS selectors I choose, because this project only supports IE9+.
Example markup:
<ul>
<li data-name="a"> ... </li>
<li data-name="a"> ... </li>
<li data-name="a"> ... </li>
<li data-name="z"> ... </li>
<li data-name="z"> ... </li>
<li data-name="z"> ... </li>
</ul>
Example CSS:
li:not([data-name="a"] ~ [data-name="a"]):before { ... }
Unfortunately this selector does not work and I am not entirely sure why not, because if I break it into sections, everything is just dandy.
The general sibling combinator works fine on its own, as does the negation pseudo-class, it's just when they're combined that nothing happens.
This also does not work:
li:not(li[data-name="a"] ~ li[data-name="a"]):before { ... }
When all else fails, RTFM. I found the answer to my question in the W3 selector specification:
The negation pseudo-class, :not(X), is a functional notation taking a
simple selector (excluding the negation pseudo-class itself) as an
argument.
and
A simple selector is either a type selector, universal selector,
attribute selector, class selector, ID selector, or pseudo-class.
In other words, it doesn't work because it shouldn't work. The general sibling combinator is not a simple selector, so it cannot be used with the negation pseudo-class.
Links:
http://www.w3.org/TR/css3-selectors/#negation
http://www.w3.org/TR/css3-selectors/#simple-selectors-dfn
While you've answered your own question, you could always use the adjacent-sibling combinator to discard the ::before content of elements with a data-name attribute equal to their previous sibling (though it's clumsier, unfortunately):
li[data-name="a"]::before {
content: 'a'; /* etc... */
}
li[data-name="a"] + li[data-name="a"]::before {
content: ''; /* etc... */
}
JS Fiddle demo.

What does a CSS class like ul.lsidebar a{} mean?

what is this called? i have never experienced it with css.
I am guessing that that class will only affect that tag. if you know please give me some examples of how to use this. i am talking about the (ul) part.
code is below:
ul.lsidebar a{}
It is targetting the class name lsidebar specifically for the DOM node ul
Example:
<div class="lsidebar">
ab
</div>
<ul class="lsidebar">
<li>a</li>
<li>b</li>
</ul>
If you do .lsidebar a{} it would target a in the descendant nodes of both the div and ul
But in this case, ul.lsidebar a{} targets specifically a in descendant nodes of ul (the a with text a and b in this case).
This link might help you understand how CSS is targeted in the DOM
ul.lsidebar means the following in HTML:
<ul class="lsidebar"></ul>
This is commonly called a class selector
See that little a at the end? That is called a descendant selector which means it will style the following HTML element:
<ul class="lsidebar">
I'll be styled!
</ul>
Hope this helps!
There may be several elements that belong to the class "lsidebar". with ul.lsidebar the code references only the elements "lsidebar" which are unordered lists (ul).
The "a" references the anchor elements inside the unordered lists (links).
The karthikr example is pertinent. In his example, the code will style the a and b links.

Applying :nth-of-type to a pseudoselector rather than a class or element type (without jQuery or even JS)

I have this:
<ol>
<li class="letter">
<li class="letter">
<li>
<li>
<li>
<li>
<li>
<li>
<li>
<li>
<li>
<li>
<li>
<li>
</ol>
I want the first 9 of the li elements not of class "letter" to be styled a certain way. So, my thinking is, I select those not of class "letter", then select using nth-of-type:
li:not(.letter):nth-of-type(-n+9):before { ... }
However, this selects the first 9 regardless of class, the same result I get using:
li:nth-child(-n+9):before { ... }
I see examples out there of selecting based on E:nth-of-type and .c:nth-of-type. How come it stops there? Why can't I build a selection using nth-of-type off a pseudo-class like I can off an element or class? (Or can I somehow?)
Because the word "type" in :nth-of-type() specifically refers to "element type", and nothing else.
Even examples that you see that qualify :nth-of-type() with a class selector are doing it wrong; they're really matching by the nth sibling of its element type, and not by its class. The class selector is there to say "only match this element if it has this class", and isn't actually considered when counting siblings. This is why you get the same result with both selectors in your example.
With the current Selectors specification, you're not able to select the nth sibling that matches a complex combination of selectors, so what you want to achieve is currently not possible with CSS without knowing about or having control over the HTML structure. Of course, if you know that only the first two li elements will ever have the class then you could just do
li:nth-child(n+2):nth-child(-n+9)::before { ... }
But that's not very useful if your HTML structure will vary.
There's an :nth-match() being proposed in Selectors 4 for this specific purpose, but no word on implementations yet. So for now, you're out of luck when it comes to pure CSS.

Complex CSS selector for parent of active child [duplicate]

This question already has answers here:
Is there a CSS parent selector?
(33 answers)
Closed 9 years ago.
Is there a way to select a parent element based on the class of a child element in the class? The example that is relevant to me relating to HTML output by a nice menu plugin for http://drupal.org. The output renders like this:
<ul class="menu">
<li>
<a class="active">Active Page</a>
</li>
<li>
<a>Some Other Page</a>
</li>
</ul>
My question is whether or not it is possible to apply a style to the list item that contains the anchor with the active class on it. Obviously, I'd prefer that the list item be marked as active, but I don't have control of the code that gets produced. I could perform this sort of thing using javascript (JQuery springs to mind), but I was wondering if there is a way to do this using CSS selectors.
Just to be clear, I want to apply a style to the list item, not the anchor.
According to Wikipedia:
Selectors are unable to ascend
CSS offers no way to select a parent or ancestor of element that satisfies certain criteria. A more advanced selector scheme (such as XPath) would enable more sophisticated stylesheets. However, the major reasons for the CSS Working Group rejecting proposals for parent selectors are related to browser performance and incremental rendering issues.
And for anyone searching SO in future, this might also be referred to as an ancestor selector.
Update:
The Selectors Level 4 Spec allows you to select which part of the select is the subject:
The subject of the selector can be explicitly identified by prepending
a dollar sign ($) to one of the compound selectors in a selector.
Although the element structure that the selector represents is the
same with or without the dollar sign, indicating the subject in this
way can change which compound selector represents the subject in that
structure.
Example 1:
For example, the following selector represents a list item LI unique child of
an ordered list OL:
OL > LI:only-child
However the following one represents an ordered list OL having a unique child,
that child being a LI:
$OL > LI:only-child
The structures represented by these two selectors are the same,
but the subjects of the selectors are not.
Although this isn't available (currently, November 2011) in any browser or as a selector in jQuery.
You can use has():
li:has(a:active) {
/* ... */
}
Unfortunately, there's no way to do that with CSS.
It's not very difficult with JavaScript though:
// JavaScript code:
document.getElementsByClassName("active")[0].parentNode;
// jQuery code:
$('.active').parent().get(0); // This would be the <a>'s parent <li>.
Late to the party again but for what it's worth it is possible using jQuery to be a little more succinct. In my case I needed to find the <ul> parent tag for a <span> tag contained in the child <li>. jQuery has the :has selector so it's possible to identify a parent by the children it contains (updated per #Afrowave's comment ref: https://api.jquery.com/has-selector/):
$("ul").has("#someId")
will select the ul element that has a child element with id someId. Or to answer the original question, something like the following should do the trick (untested):
$("li").has(".active")
THE “PARENT” SELECTOR
Right now, there is no option to select the parent of an element in CSS (not even CSS3). But with CSS4, the most important news in the current W3C draft is the support for the parent selector.
$ul li:hover{
background: #fff;
}
Using the above, when hovering an list element, the whole unordered list will be highlighted by adding a white background to it.
Official documentation: https://www.w3.org/TR/2011/WD-selectors4-20110929/#overview (last row).
The first draft of Selectors Level 4 outlines a way to explicitly set the subject of a selector. This would allow the OP to style the list element with the selector $li > a.active
From Determining the Subject of a Selector:
For example, the following selector represents a list item LI unique child of an ordered list OL:
OL > LI:only-child
However the following one represents an ordered list OL having a unique child, that child being a LI:
$OL > LI:only-child
The structures represented by these two selectors are the same, but the subjects of the selectors are not.
Edit: Given how "drafty" a draft spec can be, it's best to keep tabs on this by checking the CSSWG's page on selectors level 4.
Future answer with CSS4 selectors
New CSS Specs contain an experimental :has pseudo selector that might be able to do this thing.
li:has(a:active) {
/* ... */
}
The browser support on this is basically non-existent at this time, but it is in consideration on the official specs.
Answer in 2012 that was wrong in 2012 and is even more wrong in 2018
While it is true that CSS cannot ASCEND, it is incorrect that you cannot grab the parent element of another element. Let me reiterate:
Using your HTML example code, you are able to grab the li without specifying li
ul * a {
property:value;
}
In this example, the ul is the parent of some element and that element is the parent of anchor. The downside of using this method is that if there is a ul with any child element that contains an anchor, it inherits the styles specified.
You may also use the child selector as well since you'll have to specify the parent element anyway.
ul>li a {
property:value;
}
In this example, the anchor must be a descendant of an li that MUST be a child of ul, meaning it must be within the tree following the ul declaration. This is going to be a bit more specific and will only grab a list item that contains an anchor AND is a child of ul.
SO, to answer your question by code.
ul.menu > li a.active {
property:value;
}
This should grab the ul with the class of menu, and the child list item that contains only an anchor with the class of active.
I had the same problem with Drupal. Given the limitations of CSS, the way to get this working is to add the "active" class to the parent elements when the menu HTML is generated. There's a good discussion of this at http://drupal.org/node/219804, the upshot of which is that this functionality has been rolled in to version 6.x-2.x of the nicemenus module. As this is still in development, I've backported the patch to 6.x-1.3 at http://drupal.org/node/465738 so that I can continue to use the production-ready version of the module.
Many people answered with jQuery parent, but just to add on to that I wanted to share a quick snippet of code that I use for adding classes to my navs so I can add styling to li's that only have sub-menus and not li's that don't.
$("li ul").parent().addClass('has-sub');
I actually ran into the same issue as the original poster. There is a simple solution of just using .parent() jQuery selector. My problem was, I was using .parent instead of .parent(). Stupid mistake I know.
Bind the events (in this case since my tabs are in Modal I needed to bind them with .live instead of a basic .click.
$('#testTab1 .tabLink').live('click', function() {
$('#modal ul.tabs li').removeClass("current"); //Remove any "current" class
$(this).parent().addClass("current"); //Add "current" class to selected tab
$('#modal div#testTab1 .tabContent').hide();
$(this).next('.tabContent').fadeIn();
return false;
})
$('#testTab2 .tabLink').live('click', function() {
$('#modal ul.tabs li').removeClass("current"); //Remove any "current" class
$(this).parent().addClass("current"); //Add "current" class to selected tab
$('#modal div#testTab2 .tabContent').hide();
$(this).next('.tabContent').fadeIn();
return false;
})
Here is the HTML..
<div id="tabView1" style="display:none;">
<!-- start: the code for tabView 1 -->
<div id="testTab1" style="width:1080px; height:640px; position:relative;">
<h1 class="Bold_Gray_45px">Modal Header</h1>
<div class="tabBleed"></div>
<ul class="tabs">
<li class="current"> Tab Title Link
<div class="tabContent" id="tabContent1-1">
<div class="modalCol">
<p>Your Tab Content</p>
<p>tabBased Anchor Link </p>
</div>
<div class="tabsImg"> </div>
</div>
</li>
<li> Tab Title Link
<div class="tabContent" id="tabContent1-2">
<div class="modalCol">
<p>Your Tab Content</p>
<p>tabBased Anchor Link </p>
</div>
<div class="tabsImg"> </div>
</div>
</li>
</ul>
</div>
</div>
Of course you can repeat that pattern..with more LI's
Another thought occurred to me just now that could be a pure CSS solution. Display your active class as an absolutely positioned block and set its style to cover up the parent li.
a.active {
position:absolute;
display:block;
width:100%;
height:100%;
top:0em;
left:0em;
background-color: whatever;
border: whatever;
}
/* will also need to make sure the parent li is a positioned element so... */
ul.menu li {
position:relative;
}
For those of you who want to use javascript without jquery...
Selecting the parent is trivial. You need a getElementsByClass function of some sort, unless you can get your drupal plugin to assign the active item an ID instead of Class. The function I provided I grabbed from some other genius on SO. It works well, just keep in mind when you're debugging that the function will always return an array of nodes, not just a single node.
active_li = getElementsByClass("active","a");
active_li[0].parentNode.style.whatever="whatever";
function getElementsByClass(node,searchClass,tag) {
var classElements = new Array();
var els = node.getElementsByTagName(tag); // use "*" for all elements
var elsLen = els.length;
var pattern = new RegExp("\\b"+searchClass+"\\b");
for (i = 0, j = 0; i < elsLen; i++) {
if ( pattern.test(els[i].className) ) {
classElements[j] = els[i];
j++;
}
}
return classElements;
}

Resources