CSS3 selectors - select very first item or item after - css

Let's say a have the following code:
<nav id="main-navigation">
<ul>
<li>Link 1 Level 1</li>
<li>Link 1 Level 1</li>
<ul>
<li>Link 1 Level 2
</ul>
</ul>
</nav>
And now I want to to set first ul's height to 100px and second ul should be 300px.
When I try
nav ul {
height: 100px
}
Second ul also inherits this value.
I was trying "~", "+", ">", first-childs etc. but don't know how to do that, even with documentation.
Is there a good explained (preferably with demos/screens) guide to new css3 selectors? W3 Table is too nerdy for me.
Thanks!!!

Just select any ul that is a descendant of ul and give it that style, if you will only have 2 layers of <ul>s. No need for any special CSS2/CSS3 combinators since <ul> cannot directly contain <ul>, plus you don't have to worry about IE either.
nav ul {
height: 100px;
}
nav ul ul {
height: 300px;
}

To select direct children of an element, and not any descendant, you should use the > syntax. In your case (after you put the second ul inside a li) you need:
nav > ul {
height: 100px;
}
nav > ul > li > ul {
height: 300px;
}
Extra: It doesn't really make sense to have a 300px item inside a 100px item. Why do you want that?
Another extra: Try to read the w3c docs, it will save you some time in the long run. What you don't understand you can always ask on SO.

Firstly, how imporant is browser compatibility to you? All of those selectors you mentioned have issues in various versions of IE (IE8 is obviously better than IE7, but even IE8 is missing a lot of CSS selectors)
Simple nested selectors (ie just a space between the CSS names) will work for you - although as you say, setting nav li {height:100px;} sets it for all the LIs, you can override that with nav li li {height:300px;} to set the inner one back the way you want it.
If you want to use the 'correct' selectors, the one you want is >.
nav>ul>li {
height:100px;
}
This will only affect the outer LI elements, not the inner one. However as I say, it won't work in older versions of IE (fortunately it does work in IE7 and up, so it's only an issue if you want to support IE6).
You say that you've found the various selectors quite hard to grasp. I recommend you visit Quirksmode. For a start, it's got a very handy compatibility chart showing which browsers support which selectors, but it's also got excellent examples of how each selector works, which should help you understand them a bit better.

Related

CSS3: Differences in child styling

I'm not sure if my question title accurately displays what I'm trying to ask, but this is pretty much my first exposure to CSS3 and have been exploring various projects people have done in order to gain some hands on experience.
In searching through these projects I cam across something I'm having some trouble understanding. What exactly is the difference between the following two lines:
#random_ID > ul > li > a { ... }
#random_ID ul li a { ... }
Are these just two ways of writing the same thing? Any help would be greatly appreciated!
The greater than symbol limits the lookup to just first-level descendants: children of the selector on the left. Without the symbol, it can be any descendent at any level.
So the first example, it's "random_ID with a child ul with a child li with a child a" and the second is "random_ID with any descendant ul with any descendent li with any descendent a"
> means "direct child". This will only style it if the element (one on the right of >) is a direct child of the parent (one on the left of >)
So say if I have the following layout:
<div>
<ul>
<li></li>
<li></li>
</ul>
</div>
div > li { background: red; } Would not work, because li is not a direct child of it, whereas div > ul > li> or div li would work.
It should be noted that not every browser supports the direct child tag, specifically older versions of internet explorer, so don't rely on it, or have some fallback if you do use it.

CSS :nth-of-type() and :not() selector?

I have floated articles side by side that are 25% wide. I'm adding a clear:both after every fourth element. However I need to insert a graphical section-break inbetween the elements. And it has to be inside the <ul>. To be valid I wrapped the "section-break" (the first li item in the sample underneath) into a <li> as well.
<ul>
<li class="year"><h1>THIS IS A SECTION Break and 100% wide</h1></li>
<li>This is a article and only 25% wide</li>
<li>This is a article and only 25% wide</li>
<li>This is a article and only 25% wide</li>
<li>This is a article and only 25% wide</li>
</ul>
I want every fourth element to be a line break so I use …
ul li:nth-of-type(4n+1) { clear: both; }
However I want the li.year not to be affected by this behaviour so I tried this
ul li:not(.year):nth-of-type(4n+1) { clear: both; }
Right now the last <li> in my sample code above is floated into the next line but that shouldn't happen since the first <li> isn't one of the floated articles but contains a headline.
Is it possible to stack the :not and nth-of-type() selector onto each other?
The selector you have --
ul li:not(.year):nth-of-type(4n+1) { background: yellow; }
-- is perfectly correct (as shown by highlighting the selector).
The issue is with how you're using clear. It works if you use clear:right, and then clear:left on the following element:
ul li:not(.year):nth-of-type(4n+1) { clear: right; }
ul li:not(.year):nth-of-type(4n+2) { clear: left; }
Edit per comments The stricken-out text is nonsense. The real issue, as per BoltClock's answer, is that the :not pseudo-class doesn't affect nth-of-type. Adjusting the selector offset works in this case by coincidence, but would not work if the :not pattern was different.
ul li:not(.year):nth-of-type(4n+2) { clear: left; }
http://jsfiddle.net/8MuCU/
The reason your :not() doesn't appear to work is because the li.year is of the same element type as the rest of your li elements (naturally), so :nth-of-type(4n+1) matches the same elements regardless of the .year class.
It's not possible to stack selectors sequentially either. That's just not how they work.
Since you can't change your li elements to something else because of HTML markup rules, and :nth-match() is in a future spec and hasn't been implemented yet, you have to make do with changing your :nth-of-type() formula to accommodate the structure instead:
ul li:not(.year):nth-of-type(4n+2) { clear: both; }

Is there any way to specify a CSS shorthand for "all elements except the first/last"?

Very often, it's natural to need to specify a CSS style for all elements except the first (or the last). For example, when styling paragraphs, you wish to add a bottom margin to every element except the last one (or similarly, a top margin to every element except the first one).
Is there any way to do that that's :
more concise than defining p {...} and then p:first-child {...}?
more straightforward and intuitive than p:nth-child(-n+1)?
If there is not, do you know of any attempt at adding it?
For all p elements except the first child, use either one of these (the second one is better-supported):
p:not(:first-child)
p:first-child ~ p
For all p elements except the last child:
p:not(:last-child)
For all p elements except the first and the last children:
p:not(:first-child):not(:last-child)
As usual, CSS3's :not() and :last-child aren't supported until IE9+ and relatively new versions of other browsers. You're not going to reach very far in terms of browser support (IE8 and older) unless you add classes to your first and last children, using JavaScript or otherwise.
Remember that vertical margins collapse between in-flow paragraphs and their ancestor(s), so unless you want to zero out the margins of the container element for these paragraphs as well, you shouldn't need to zero out the margins of the first and last p elements specifically. Here's a fiddle to illustrate.
If IE7-8 support is not needed you can use the :not() CSS selector, like:
p:not(:first-child) {
...
}
But if you need to support IE7+, which may still be the case there is a little trick you can use and usually gets you fairly far. A lesser known fact is that the :first-child psuedo selector actually works in IE7+ (not :last-child though) as are some other css selectors and this makes stuff like adding vertical margins in a horizontally floated layout possible.
Imagine this html:
<ul>
<li>Item #1</li>
<li>Item #2</li>
<li>Item #3</li>
<li>Item #4</li>
</ul>
And this as some CSS:
/* General reset */
ul, li { list-type: none; margin: 0; padding: 0; }
/* Make horizontal */
ul > li { float: left; }
So now all list items are horizontally next to each other, and now we want to add a margin in BETWEEN all items but not on the right or left side, we can do this in css:
/* General reset */
ul, li { list-type: none; margin: 0; padding: 0; }
/* Make horizontal */
ul > li { float: left; margin-left: 10px; }
ul > li:first-child { margin-left: 0; }
This usually covers 95% of the cases where I want something unique, then the rest of the 'forgotten' selectors cover another few percent, after that you need to add some classes which usually isn't much of a bottleneck anyway in the backend of the page.
Well, you could do:
p:not(:first-child) {...}
But only the most recent browsers support the :not psuedo-class.
Other than that, no. Your best option is to specify a style for all and then override it for the first/last.
I would suggest to use first-of-type:
p:not(:first-of-type) { ... }
Browser support (caniuse)

CSS - floating LIs - bigger content messes up the next row

<style>
ul{margin:0px;padding:0px;}
ul li{margin:0px 5px 5px 0px;padding:0px;list-style-type:none;float:left;}
</style>
<ul class="clearfix">
<li> </li>
<li> </li>
<li> </li>
<li> </li>
<li> </li>
<li> </li>
</ul>
The first li contains more content than the rest.
So, I have the following problem:
problem http://img830.imageshack.us/img830/240/problemc.png
But how do I move the next row down, so it looks like that:
want this http://img440.imageshack.us/img440/9750/solutionm.png
I tried using display:inline-block; instead of float:left; for the lis, which works, but I'd still rather use float:left; over inline-block.
Any ideas on how to do this?
Solution for IE:
http://blog.mozilla.com/webdev/2009/02/20/cross-browser-inline-block/
The best solution is to use a little-known display style called table-cell.
I've had to do this a few times. Here's how you do it:
/* -*- CSS -*- */
ul li .wrapper
{
display:table-cell;
width:100px; /*replace here*/
min-height:100px;/* " " */
}
ul li
{
float:left;
display:inline-block;
}
ul
{
display:table;
}
...
<!-- HTML -->
<ul>
<li><div class="wrapper">my-content</div></li>
<li><div class="wrapper">my-content</div></li>
<li><div class="wrapper">my-content</div></li>
<li><div class="wrapper">my-content</div></li>
</ul>
How this works:
When the parser sees that there's a UL object, it treats it like a table instead of a list. This gives you the distinct advantage that you're beginning to /act/ like you're working with tables (but you're not!)
The rule then runs against the wrapper class -- this creates a "Table cell". We don't want to put it in the li because OTHERWISE the li will act as the table cell. This is kinda bad. the work around is that your li is actually aligned left. There's some argument whether or not is a good idea to do it this way -- this is the "Most Effective" because it forces the box model to comply. Its fugly, I know.
the REASON its bad for the li to be treated like a table-cell is that it won't wrap. The reason it wont wrap is that table-cells aren't supposed to wrap.
There is ONE other solution that might work, however I haven't tested it.
/* -*- CSS -*- */
ul li { display: inline-block; float:left; min-height:200px;width:200px; }
Its not as ugly, but it should work by making the box model force the alignment as well.
First of all: Are you sure you're using the right markup? A list generally doesn't end up to look like that.
Second. Do you know how many items you will have on a row? In your image they seem to have the same width. If you know that you can add clear:both; to the forth li (and other you may need) and force it down. This would be the only way to do it with left floating lis.
You can't do this using only float:left; the blocks just fall into place where they fit as your first example shows. If you intend for your content to always display in three columns, you could programmatically clear the float on the first item in each row.

How to make resizable li elements with CSS only

Scenario: I have an unordered list < ul > of width (lets say 200px) with four < li > elements that are sized equally. Therefore each should be 50px. When I add a 5th < li > element each width should re-size to 40px. If I change the width of the < ul > to 500px with 5 < li > elements, each < li > element should be 100px.
Is this possible with only CSS? If yes, how is it implemented?
Currently, I have a solution that meets the above requirements but it includes jQuery to re-size the < li > elements based on mathematical calculations.
Thanks for the attention.
Aparently you can fake tables like here, but I am not sure if this works in all browsers(edit: it works on winxp ie8, chrome 7, firefox).
<div id="menu">
<ul>
<li>
...
</li>
<!-- other list items -->
</ul>
</div>
#menu {
display: table;
}
ul {
display: table-row;
}
li {
display: table-cell;
}
Also example on fiddle.net here
Your question doesn't completely make sense to me. If you leave the widths off, the list will be as wide as it needs to be. But here's a crack at your question:
<style type="text/css">
ul
{
width:500px;
}
li
{
width:100px;
}
</style>
<ul>
<li>1. one</li>
<li>2. two</li>
<li>3. three</li>
<li>4. four</li>
<li>5. five</li>
</ul>
Using CSS expressions it is possible, but CSS Expressions come with a very heavy performance penalty. JavaScript (and jQuery for that matter) is the appropriate tool to use to create the effect you want.
CSS should only be used for styling, HTML should only be used for structure, and JavaScript should be used whenever you want to create dynamic content.
Until such a time as browsers implement the calc(), min() and max() functions this isn't possible outside of scripting (either server-, or client-, side) or using a table.
Currently, and surprisingly (perhaps only to me), neither Firefox, Webkit or Opera support calc() function, not even with the various flavours of vendor prefix.
That said, one day something like the following might work (but not today, sadly):
ul {
counter-reset: numListItems;
width: 60%;
}
ul li {
counter-increment: numListItems;
width: calc(100%/numListItems);
}
But, obviously, for that to work browsers would need to implement some form, and understanding, of variables within the scope of calc(), which doesn't appear to be necessarily on the road-map (I'm not sure that the counter() is, or is intended to be, interoperable with the calc()).

Resources