The trick with using hidden checkboxes/radio buttons, the :checked pseudo class selector, and adjacent sibling (~) combinators really enables some neat functional possibility with pure CSS1. If you need a primer, we recently used this to build a functional tabbed area.
Let’s exploit it again to build “fold out popups”. That is, links/buttons you can click to reveal tooltip-like rich HTML popup content.

HTML Structure
We need a checkbox for the on/off clickable functionality (don’t worry, it’s hidden). Then right after it is a label. Like any good label, the for
attribute matches the inputs id
attribute. That way we can click it to toggle the checkbox.
The label contains within it a number of spans. The .box
span is the container for the rich HTML popup. In other words, put whatever you want in there. Well, whatever you want that are inline elements. It’s tempting to use a div
and header tags and stuff, but some browsers don’t dig that and will render those things outside of the label instead of within. Making the .box outside of the label wouldn’t be too big of a deal, as we could chain ~
selectors to get it to hide/show anyway, but having them within means we’ll be able to position the popup relative to the position of the label, like a “popup” should.
<input type="checkbox" id="popup" class="popUpControl">
<label for="popup">
Click me!
<span class="box">
Super cool popup content
</span>
</label>
CSS Basics
Our goal with the .box is to absolutely position it relative to the label it’s within, so it pops up attached to it. By default, it will be hidden by having zero opacity. We’ll also scale it down to nothing, skew it, and add transitions. Then when we reveal it by way of the checkbox becoming checked, we’ll scale it back up, remove the skew, and make it visible by bringing the opacity back up to 1.
.box {
position: absolute;
left: 0;
top: 100%;
z-index: 100;
/* Prevent some white flashing in Safari 5.1 */
-webkit-backface-visibility: hidden;
-moz-border-radius: 20px;
-webkit-border-radius: 20px;
border-radius: 20px;
width: 260px;
padding: 20px;
opacity: 0;
-webkit-transform: scale(0) skew(50deg);
-moz-transform: scale(0) skew(50deg);
-ms-transform: scale(0) skew(50deg);
-o-transform: scale(0) skew(50deg);
-webkit-transform-origin: 0px -30px;
-moz-transform-origin: 0px -30px;
-ms-transform-origin: 0px -30px;
-o-transform-origin: 0px -30px;
-webkit-transition: -webkit-transform ease-out .35s, opacity ease-out .4s;
-moz-transition: -moz-transform ease-out .35s, opacity ease-out .4s;
-ms-transition: -ms-transform ease-out .35s, opacity ease-out .4s;
-o-transition: -o-transform ease-out .35s, opacity ease-out .4s;
}
.popUpControl {
display: none;
}
.popUpControl:checked ~ label > .box {
opacity: 1;
-webkit-transform: scale(1) skew(0deg);
-moz-transform: scale(1) skew(0deg);
-ms-transform: scale(1) skew(0deg);
-o-transform: scale(1) skew(0deg);
}
The actual CSS for the box has some additional styling, but this the important functional stuff. Snag the download that accompanies this tutorial for the complete set of CSS.
Changing Text of Button When Open
This isn’t vital to the idea here, but another neat trick in this demo is changing the text of the button when the popup is open. This works by actually hiding the text inside the button when :checked and inserting new text. The basics:
<input type="checkbox">
<label>
<span>Default text</span>
</label>
[type=checkbox]:checked ~ label span {
display: none;
}
[type=checkbox]:checked ~ label:before {
content: "Text to show when checked";
}
Yet another “hack” (bad, as generated content isn’t very accessible or selectable). But hey, we’re still having fun right?
1 Yeah but… JavaScript
This definitely walks “separation of concerns” line. Even though I’ve created this in “pure” CSS, I actually think this type of behavior is probably better suited to JavaScript. And by “use JavaScript”, this is what I would actually do:
- Toggle a class name for “open” and “closed” on the .box, rather than use the checkbox.
- Change the text through the JavaScript, not use CSS generated content.
But everything else should stay in the CSS. The styling, the transitions, the transforms… That stuff is style not functionality.
Boy I’m a hypocrite hey?
Credit
Thanks to Victor Coulon who sent me this idea that I riffed on for this.
I was really expecting to see dogs :(
Haha, looks like you beat me to that point!
Since every cat on the internet is worth at least 2.5 dogs, I think we made out ahead of the game.
The demo says more dogs and a cat shows up! I can only think of a billion uses for something like this – I haven’t checked but do you know how this works/doesn’t work in older browsers?
Awesome as usual!
Awesome Effect! Thanks for the share!
Chris… I notice that the pop-up (out) on the link eases in both directions (out and in); but, the photograph just triggers on then eases out. Is that how it is meant to be or is FF6.0 still missing some of your intended functionality?
Yeah, I have problems too when trying to close de popup on FF6.
Great tips!
Great effect. The source code is less than I think. Thanks for sharing.
I think that you should have a
cursor: pointer;
int the CSS, because it just makes the link look un-clickable.
I also thing that a :hover on the button would be good, just for nicer visual effects.
Sadly it doesn’t work on iOS devices with mobile Safari.
Or in opera mobile.
It could, it’s just a matter of using JavaScript instead like I recommend at the bottom of the article.
Great Chris ;)
Very Nice Effect!
Neat. In Windows, Chrome both reveals and hides the popup with the effect. Interestingly, Firefox will pop it open instantly (no effect) but will ease it back in on hide.
Yeah… super weird. Looking at that now. I don’t see why it would be doing that (tested Firefox 7). Maybe the generated content change? Weirdddd.
Great as usual, but there is something I don’t understand in this line of code:
What the “~” and the “>” do?
Looks like this article from CSS Tricks might help you understand what “~” and “>” do: Child and Sibling Selectors.
If you have any more questions, I’ll be happy to help :)
Thanks for sharing that post Aaron! Understanding that is paramount to understanding this tutorial. Essentially, it allows us to select a different element when a preceding element is in a different state (in this case).
I think making the ‘popup’ that folds out as well as the label (or text link, as in the demo) unselectable would prevent its selection when it is sometimes double-clicked to make the popup visible (some people do that). Maybe
-webkit-user-select: none;
or something?That’s odd. For me browsing the example in Safari 5.0.6 the “bubble” popup from the link example is underlined in blue (like the link is).
Yeah I forgot to mention that but I left it in there on purpose. The text-decoration: underline is propagating to the child elements even though the children have explicitly turned it off. Just one of those weird things. The CSS3 spec has some ways around that but there are no implementations yet.
Hi, i have a question what if i want to use this effect on more than one link? when i do this, all the links open the first pop up
This may be because you did not change the id’s for each checkbox and the labels.
Check out this example for more (I’ve striped some CSS – for webkit-only CSS3 – just to keep it a bit more handy).
I have to click twice to get it to pup-out and click twice to get it to pup back in… (Chrome)
It didn’t work on my iPad… :(
I didn’t get to see the cat
Perfect – other than the cat it is exactly what i needed – the angle that it skews is slightly odd but i guess this can change?
It doesn’t work. Only cat. Shit sample :)
Chris… the button does NOT animate open in FF6; however, it does animate closed. (The anchor link DOES animate both directions) – is that a known issue in FF6, a peculiarity to the code you wrote, or ?
[I can’t get over how good your new site style looks! To me at least, the most user friendly and appealing one since I’ve been stalking your site, lo these many years! I hope you do a screencast or posts about specifics of how you pulled it off… soon]
One things for sure, if any animal makes it to heaven, it would have to be cats. I mean, where else are we gonna get the strings for the harps? One time, I ran over a cat on purpose… I felt bad when i woke up the next morning, but i don’t feel bad anymore. Reason being: he was probably homeless, and I helped him find a better home: heaven… I probably shouldn’t have said this.
I was thinking to make something that does this. I can’t and don’t like to work with JS so that was no option for me. the best I could come up with was using the hover selector (see my demo).
then this post showed up.
because I wanted multiple buttons and only one opened at the time I’ve used radiobuttons. and added one extra to make close button.
just check my demo site:
http://tuinderijdevork.nl/demo/
works fine in: opera 11.51 and ff 6.0
the closebutton is broken in midori 0.4.0 and chromium 12.0.742.112
I didn’t try to fix it in webkit browsers yet, so suggestions (and other test results) are welcome.
I’m new to the whole transition / transform properties, but perhaps the reason a few of us are not seeing the animation effects in Firefox is due to a lack of ease-in declarations?
Something like this:
I implemented a variation of this in the javascript triggered version I built, and that did the trick; it now animates in and out in Firefox (6.01), Chrome, and Safari.
Curious that Chrome / Safari still animate it even without those declarations though.
Sweet tut, and amazing site, Chris. This is fast becoming a first resource for when I’m troubleshooting some new (to me) form of CSS. Excellent work.
By the way, when I was checking out the demo page, my wife walked past my computer. She likes the cat. :)
This example doesn’t work in IE8 and the layout of the whole re-designed website doesn’t work in IE7 or 8, it’s all a mess with elements overlapping etc.
Forget about IE. Maybe in IE9 some of the new stuff works, but I think its a waste of money and time to work around all IE’s shortcomings. I’m for the idea to show IE visitors a plain text version and attached to that the advice to switch to a real browser. (and maybe some explanation why you’re doing this…)
Awesome. I’m going to try to put this to use in one of my next projects. Thanks.
Hello,
I am quite new on CSS / HTML so please do not lough because of my dumb question :)
Is it possible to have this functionality with link or even on image with mapping (i have a such solution on my case)? I have no idea how to change the code instead of INPUT tag.
Thanks in advance!
Any ideas how to make CSS popup when i press or move mouse cursor over specific AREA of mapped image? I have few areas of the image that should call different popups.
i have looked to ‘de vries’ posted demo link and tried to make something, but it seems that my skills are to low for this.
the first part of my demo (were the popup shows when the mouse moves over) is probably the easiest to understand. the code for that is in the css file (http://tuinderijdevork.nl/demo/css/de_vork.css) under /* FANCY MENU */. the code under /* FANCY MENU 2.0 */ is for the second part of the demo.
the css code can be a bit messy because it is a part of a joomla-template i’m working on.
ps. I still didn’t figure out why its not working with webkit. When I open a popup and then make the browser re-render the page by chancing any css code on the page it’s fixed. (if I only could expect my visitors to do that…) Ideas??, anyone?
“But everything else should stay in the CSS. The styling, the transitions, the transforms… That stuff is style not functionality.”
HTML = Content, CSS = Presentation, JS = Behavior
I love the new stuff we have available in CSS3, but am I the only one that feels that interaction like tooltips and things like this fold out popup should be left to JS. To me, that IS functionality, behavior, and user interaction. I can see arguments for both sides, but I just feel like CSS is going to go beyond it’s purpose if we keep adding in more features like animation.
Just a discussion starter :)
Chris. Which plugin do you use for syntax highlighting?
Google-code-prettify
Thanks for the add. I was looking for something like that!
Hey awesome effect
Very neat !
Will have to dissect the code to fully understand it though.
Thanks !
Nicely done with the CSS – like you say, there are always places where Javascript might be more suitable, just depends on what you’re trying to achieve I suppose.
Animating is still going to be a problem with html/css for some time I think…
Many Thanks,
Darren.
Nice CSS, but if you have tutorial about javascript notice me please..
Many Thanks,
Faris
so the example is great and works well but is there any way to apply it to a youtube video considering the embed uses a block-level element?
ive tried encasing in a p but alas it just displays beneath the code as mentioned in the tutorial
Thanks for the code, Chris! :) It’ s been almost 3 years, but still useful.
Instead of ‘span’ nested in ‘label’ (as in your code), i’m trying to nest a ‘div class=”popout-box” ‘ that includes many things (lots of code). So ‘/label’ gets to be way down in the code which is not semantic.. If I close label before the div class, the pop-out-box doesn’t work.. Any suggestions how I can make it semantic and still get it to pop-out?
Will be happy for any help, comments or advice :)
Click
Oh my god, the way you did that triangle is some crazy maniac thing! respect
its not working in mozilla fire fox version 27.0. how can i fix this?