What is the simplest way to implement pure css show/hide? - css

I discovered the <details> element for html5, and that made me want to determine whether it was possible to implement a simple and reusable show/hide via css alone.
I have created a show/hide mechanism in the past for showing and hiding content by giving two elements relative positioning and one a negative z-index, and then decreasing the z-index of the front element on hover (and increasing the z-index of the back element on hover).
However, that method only works for elements that are in the same location. Are there other techniques for simulating show/hide on non-overlapping elements? e.g. a title that causes a section of descriptive text to display.
Trivial example code that I would like to be able to apply a show/hide to:
<div id='container'>
<h3 id='show-hide-trigger'>summary</h3>
<p id='show-hide-text'>Paragraph of detail text paragraph Paragraph of detail text paragraph Paragraph of detail text paragraph Paragraph of detail text paragraph</p>
</div>
And yes, I do know that jQuery exists.

there is a plethora of options based on the structure (for modern browsers).
Have a look at the
selector + selector adjacent sibling selector
selector ~ selector general sibling selector
selector selector descendant selector
selector > selector child selector
These can be combined with classes / ids / pseudo-selectors like :hover etc, and create a big list of options.
here is a small demo i made to showcase them : http://jsfiddle.net/gaby/8v9Yz/

Try this using nested divs and targets.
I'm not a CSS guru, so there may be all kinds of flaws with this, but it seems to work.
http://jsfiddle.net/NmdxC/6/
#show {display:none ; }
#hide {display:block;}
#show:target {display: block; }
#hide:target {display: none; }

CSS without the exact code is hard to visualize, but what is wrong with changing the display or visibility declarations dangling from a :hover?
a #myelement{display:none;}
a:hover #myelement{display:block;}
I problably misunderstood the question...care to add code?

First thing that springs to mind is something like:
<a class="blah" href="#">Hello<span>Test</span></a>
a.blah {position:relative}
a.blah span {position:absolute;top:50px;left:50px;display:none;}
a.blah:hover span {display:block;}

Related

Is the CSS :not() selector supposed to work with distant descendants?

Here is the official documentation for the CSS3 :not() pseudo-class:
http://www.w3.org/TR/css3-selectors/#negation
and the proposed CSS Selectors Level 4 enhancement:
http://dev.w3.org/csswg/selectors4/#negation
I've been searching the implementation and browser support for :not(), but the only examples I found were with a single element or with a direct child of an element, e.g.:
div *:not(p) { color: red; }
The example above works when <p> is a direct child of <div>, but it does not work when <p> is a more distant descendant of <div>.
div :not(p) {
color: red;
}
<div>
<ul>
<li>This is red</li>
</ul>
<p>This is NOT</p>
<blockquote><p>This is red but is not supposed to be!</p></blockquote>
</div>
If the answer is in the official documentation above, then I didn't find/understand it. As I said, I have searched this site and the web but couldn't find any discussion about the support or lack thereof of :not() as grand-children of another element.
Is this supposed to work like I think it should?
Is this supposed to work like I think it should?
No, the behavior you're seeing is correct.
In your last example, although the <blockquote> contains a <p>, it's the <blockquote> itself that's matching *:not(p), as well as the condition that it must be a descendant of the <div>, which it is. The style is applied only to the <blockquote>, but it is then inherited by the <p> inside it.
The <p> element itself still counts against the negation, so the <p> itself is still being excluded from your selector. It's just inheriting the text color from its parent, the <blockquote> element.
Even if none of its relatively close ancestors matched the selector, you have elements like html and body to worry about as well — although you could probably just tack on a body selector in the very beginning:
body div...
This is why I often strongly advise against using the :not() selector for filtering descendants, especially when not qualified with a type selector (like div in your example). It doesn't work the way most people expect it to, and the use of inherited properties like color only serves to compound the problem, on top of making it even more confusing for authors. See my answers to these other questions for more examples:
Why doesn't this CSS :not() declaration filter down?
CSS negation pseudo-class :not() for parent/ancestor elements
The solution to the problem described is to simply apply a different color to <p> elements. You won't be able to simply exclude them with a selector because of inheritance:
/* Apply to div and let all its descendants inherit */
div {
color: red;
}
/* Remove it from div p */
div p {
color: black;
}
On Selectors Level 4: yes, :not() has indeed been enhanced to accept full complex selectors that contain combinators. Essentially, this means (once browsers begin implementing it) you will be able to write the following selector and have it do exactly what you want:
p:not(div p) {
color: red;
}
In case anyone is interested, this works in jQuery today.
The color is assigned to the blockquote, and is then inherited by the p.
:not(p) just makes it so that the styles are not directly applied. They are still inherited though.

How to style parent when parent contains specific child?

I have some html that looks like this:
<div id="parent">
<div id="child"></div>
</div>
I want to apply a default background color to #parent except for when it contains a #child.
So the CSS should end up looking something like this:
#parent {
background: red
}
#parent:contains(#child) {
background: none
}
However, I can't get the :contains pseudo selector to work that way. Is there a way to achieve this?
:contains() was only intended to match elements containing certain text, not elements containing certain other elements. It is because of the complications associated with matching elements by text that there were almost no browser implementations, leading to :contains() being dropped from the spec.
Since there is no parent selector in CSS, and :has() (which does look at elements) only exists in jQuery, you won't be able to achieve this with CSS yet.
For the record, jQuery implements :contains() as well, but it does so according to the old spec, so it uses the name :has() for elements instead.
With jquery
if($("#child").length>0) $("#parent").css("backgroundColor","#fff");
Its not possible with pure css.

How to exclude a class with all children in style definition

I have a file like
<div>
<div class="abc">
<div>
<!--some more divs inside-->
</div>
</div>
</div>
What I want to do is to apply styles only to the first div. I tried to use div:not(.abc, .abc *), div:not(.abc):not(.abc *), div:not(.abc), div:not(.abc) * but none of these worked. It would be hard to edit the html, because there would be many files to be edited. Also the code shown above appears in different places, so using > selector is not the solution... Does someone know how to do this?
You cannot reliably use the :not() selector in CSS for excluding an element and/or its descendants. The reason for it is explained in this answer (and some others that it links to):
You can't use combinators. This works in jQuery, but not CSS:
/*
* Grab everything that is neither #foo itself nor within #foo.
* Notice the descendant combinator (the space) between #foo and *.
*/
:not(#foo, #foo *)
This one is particularly nasty, primarily because it has no proper workaround. There are some loose workarounds (1 and 2), but they usually depend on the HTML structure and are therefore very limited in utility.
And since your markup is unpredictable enough that you cannot edit it or use the > selector, I'm afraid there's not much of a way out for you other than to either find a way to apply a class to your top div and use that class, as demonstrated by Fluidbyte, and/or use jQuery, as implied above.
I usually find it's easier to include what you need via a class then try to exclude descendant elements. See the fiddle here: http://jsfiddle.net/cLtHg/
That takes care of inheritance issues and is much more cross-browser friendly.
If you're really not touching the HTML, then a simple although dirty approach would be to apply styles to the first div and then remove them from subsequent divs, like so:
div {margin-bottom: 20px; border: 1px solid #ccc;}
div div {margin-bottom: 0; border: none;}
The major drawback here is that some styles in the child divs may get removed unintendedly. Depends on how they're styled in the first place.
Use :first-child with the ID or Class of its parent Element. If you are unable to catch the element using CSS, it is suggested to use Javascript or jQuery.
Have you tried :first-child or :nth-child() selecor?

CSS Selecting element after chosen class

I'm modifying JQuery UI Accordion Menu, which currently has a structure as below:
<h3>Title</h3>
<div>Children</div>
<h3 class="no-children">Title</h3>
<div>Children</div>
<h3>Title</h3>
<div>Children</div> ...
As you can see, the middle title has no children, so what I want to do in CSS is something along the lines of selecting the div that occurs after the .no-children class and hide it. These are not nested so I can't do this the easy way.
I know I can display:none but I can't seem to select the correct element.
Is there a way to do this?
.nochildren+div{
/* Style goes here */
}
This selects a DIV that that is immediately preceded by a element with the the .nochildren class. This will only work if both elements are on the same level, many older browsers will have issues with it.
http://www.quirksmode.org/css/contents.html
If you are using jQuery there is an easy way of doing this Here
You could use
$('.no-children').next().hide();
or .nextUntil();
http://jsfiddle.net/lollero/DqpPd/1/
CSS way would be
.no-children + div { display: none; }
http://jsfiddle.net/lollero/DqpPd/ ( ie7+ )

CSS: Does it render "ul > li" faster than "ul li"?

using ">" rather than " " make the rendered faster as I heard from few people?
.slide:hover > div > span {
border-color: #c8c8c8;
}
OR
.slide:hover div span {
border-color: #c8c8c8;
}
Thanks a lot!
update: question
any reliability problem for any of this?
You should very seriously reconsider listening to the people who tell you this type of thing.
The difference is utterly insignificant at best. No one should waste time, energy, or brainpower considering such things. This isn't a useful optimization. Don't fall into the trap of premature optimization, especially for a dynamic language like HTML/CSS.
Write code that is clear, maintainable, and functional first, before worrying about anything else.
If ul > li looks clearer to you than ul li, then write it that way. If not, don't. Keep it simple.
.slide:hover > div > span is more efficient than .slide:hover div span.
However, you're never going to notice the difference with average size pages.
If you used the Child Selector instead of the Descendant Selector everywhere in your stylesheet for a really freaking massive/complex page, you could shave off a noticeable portion of the render time (see comment by #Boris Zbarsky).
With average size pages, you might shave off a few milliseconds.
There is one disadvantage to using the Child Selector - IE6 does not support it.
For 99% of sites, IE6 support is not an issue, but some people still do use it:
http://ie6countdown.com/
Which is faster?
Like Cody and thirtydot said, theoretically using > should be faster, but even styling for IE6 is less a waste of your time than styling for performance. Browsers are fast enough; trust your browsers, not the people who tell you this, especially not those who don't provide any browser benchmarks to back their claims.
any reliability problem for any of this?
Sure. Besides IE6 not supporting > at all as thirtydot mentions, there's also the difference in elements matched since > and the whitespace combinators select different things:
<section class="slide">
<div>
<span></span> <!-- [1] -->
<div>
<span></span> <!-- [2] -->
</div>
</div>
<div>
<p>
<span></span> <!-- [3] -->
</p>
</div>
</section>
What's selected and what's not:
Selected by both selectors
This span is a child of a div which is a child of an element with class slide. Since span is a child of div, it's also a descendant of div. Likewise for div and its .slide parent/ancestor.
On hovering the .slide element, this span is selected. The rule applied is the second one because both selectors are of equal specificity, but the second one, well, comes second.
Selected only by .slide:hover div span
This span is in a div, but its parent div is located in another div that doesn't have the class slide. So the first selector doesn't find this element.
The inner parent div is, however, a grandchild of a .slide element. Regardless of depth, it's still in some way a descendant of .slide (it's contained somewhere within it).
On hovering the .slide element, this span is selected. The rule applied is the second one because it's the only one that matches.
Selected only by .slide:hover div span
This span's parent is a p element, not a div. Easy enough; the first selector doesn't find this element.
The span is, however, a grandchild of a div element, which itself is inside a .slide.
On hovering the .slide element, this span is selected. The rule applied is the second one because it's the only one that matches.
One last thing: in all three scenarios do you find that the rules in only the second selector are applied. This is purely coincidental; the differences in how supporting browsers look for elements to match are still real.

Resources