How can I toggle a div to reveal content with CSS

26,231

Solution 1

I'm afraid I couldn't work out, in your sample code and image, what you wanted to click on and what you wanted to show. However, the following works with an onclick-like event with pure CSS:

<div id="wrapper">
    <ul id="top">
        <li><a href="#one">One</a></li>
        <li><a href="#two">Two</a></li>
    </ul>
    <div class="box" id="one">
        <p>One</p>
        <span><a href="#top">Close</a></span>
    </div>
    <div class="box" id="two">
        <p>Two</p>
        <span><a href="#top">Close</a></span>
    </div>
</div>

CSS:

.box {
    position: absolute;
    top: 20%;
    left: 50%;
    width: 50%;
    margin-left: -25%;
    border: 4px solid #000;
    background-color: #f90;
    /* the CSS, above, is all for aesthetic purposes, what matters is the following */
    opacity: 0;
    -webkit-transition: all 1s linear;
    -ms-transition: all 1s linear;
    -moz-transition: all 1s linear;
    -0-transition: all 1s linear;
    transition: all 1s linear;
}

.box:target {
    opacity: 1;
    -webkit-transition: all 1s linear;
    -ms-transition: all 1s linear;
    -moz-transition: all 1s linear;
    -0-transition: all 1s linear;
    transition: all 1s linear;
}

JS Fiddle demo.

Unfortunately it seems (in Chromium 17/Ubuntu 11.04) impossible to animate from display: none; to display: block; Similarly a transition from height: 0 to height: auto also fails (trying either results in a sudden appearance rather than a transition. So the content in the demo is always 'there,' but simply hidden (with opacity) and then shown once the relevant link is clicked.

However for a slide-toggle like effect:

.box {
    /* aesthetic stuff excised for brevity */
    opacity: 0;
    height: 0;
    overflow: hidden;
    -webkit-transition: all 1s linear;
    -ms-transition: all 1s linear;
    -moz-transition: all 1s linear;
    -0-transition: all 1s linear;
    transition: all 1s linear;
}

.box:target {
    opacity: 1;
    height: 3em;
    -webkit-transition: all 1s linear;
    -ms-transition: all 1s linear;
    -moz-transition: all 1s linear;
    -0-transition: all 1s linear;
    transition: all 1s linear;
}

JS Fiddle demo.

Solution 2

You can use the "Checkbox Hack": http://css-tricks.com/the-checkbox-hack/

Solution 3

Making these modifications of your code will give you a CSS transition.

Inside your <div class="box">, add a container <div class="trans"> around the contents, like so:

<div class="box">
  <div class="trans">
    <img src="http://www.placehold.it/250x300" alt="" />
        <div class="section progress">
            <h4>
                <a href="#">Div After</a>
            </h4>
            <div class="metrics">
                <div class="meter">
                    <span style="width: 75%"></span>
                </div><!--.meter-->
            </div><!--.metrics-->
        </div><!--.section-progress-->
        <div class="sub_section">
            <ul class="list">
                <li>Item 1</li>
                <li class="last">Item 2</li>
            </ul>
        </div><!--.sub_section-->
    </div><!--.trans-->
</div><!--.box-->

Then, in your css, add:

.box > .trans {
    height:365px;
    overflow:hidden;
    }

.box > .trans:hover{
    height: 500px;
    -webkit-transition: height .25s linear;
    transition: height .25s linear;
    }

This will give you a mouseenter/mouseleave type effect. I don't think you'd be able to do an "onclick" type effect that would hold it open with just CSS.

Solution 4

You're gonna need to use javascript to listen for the event that fires the transition, unless you want it to apply on hover. so, you can start with something like this:

$('.box').click(function(){
    $(this).toggleClass('show');
});

Then in the css, you need to have the class with the new size and the transition applied:

.show
{
height: 300px;
-webkit-transition: height .25s ease-in-out;
transition: height .25s linear;
}

If you want a purely CSS solution, then you'll have to handle this using the ':hover' pseudo-class like redlena said. The only difference I would make is that you don't need an additional div (.trans) and you don't need to specify the child selector in your CSS either (.box > .trans).

Share:
26,231
Jedda
Author by

Jedda

Updated on January 18, 2020

Comments

  • Jedda
    Jedda over 4 years

    So I've got a div that should expand to reveal a list when toggled. The before and after states can be seen here http://reversl.net/box/ but what do I need to add to my styling to make this happen? I'd like to use css transitions for added effect. I'm not worried about browser compatibility because it's just for learning purposes. Any tips?

    <div class="box"><img src="http://www.placehold.it/250x300" alt="" />
            <div class="section progress">
                <h4>
                    <a href="#">Div Before</a>
                </h4>
                <div class="metrics">
                    <div class="meter">
                        <span style="width: 75%"></span>
                    </div><!--.meter-->
                </div><!--.metrics-->
            </div><!--.section-progress-->
    </div><!--.box-->
    
    <div class="box"><img src="http://www.placehold.it/250x300" alt="" />
            <div class="section progress">
                <h4>
                    <a href="#">Div After</a>
                </h4>
                <div class="metrics">
                    <div class="meter">
                        <span style="width: 75%"></span>
                    </div><!--.meter-->
                </div><!--.metrics-->
            </div><!--.section-progress-->
            <div class="sub_section">
                <ul class="list">
                    <li>Item 1</li>
                    <li class="last">Item 2</li>
                </ul>
            </div><!--.sub_section-->
    </div><!--.box-->
    
    .boxes {
    width: 100%;
    padding: 1%;
    }
    
    .box {
    width: 20%;
    padding: 1%;
    background: #fff;
    -moz-box-shadow: 2px 3px 4px 0px #e9e9e9;
    -webkit-box-shadow: 2px 3px 4px 0px #e9e9e9;
    box-shadow: 2px 3px 3px 0px #e9e9e9;
    display: inline-block;
    margin-top: 1em;
    }
    
    .box img {
    margin-bottom: 1%;
    }
    
    .progress a {
    margin: 0;
    padding: 0;
    color: #999;
    text-decoration: none;
    }
    
    .metrics {
    margin: -1em 0 0 0;
    padding: 0;
    background: #c0c0c0;
    
    }
    .accordion .progress .meter {
    background: #555;
    width: 100%;
    position: relative;
    }
    
    .meter > span {
    height: 10px;
    display: block;
    background-color: #777;
    position: relative;
    overflow: hidden;
    }
    
    .sub_section {
    margin-top: 1em;
    border-bottom: none;
    }
    
    .list {
    padding: 0;
    margin: 0;
    }
    
    .list li {
    background: #dcdcdc url('http://placehold.it/40x40') no-repeat;
    font-size: 11px;
    color: #999;
    list-style: none;
    padding: 1.3em 1em 1.3em 4.5em;
    margin-bottom: 5px;
    }
    
    .list .last {
    border-bottom: none;
    }
    
  • redlena
    redlena about 12 years
    Forgot to mention... play around with the ".25s" duration in the hover style and with the alternatives to "linear" (which are ease, ease-in, ease-out, ease-in-out) to get the effect timing you like.
  • kingjeffrey
    kingjeffrey about 12 years
    It can be achieved with pure html and css using the checkbox hack I linked to in my answer.
  • Jedda
    Jedda about 12 years
    Awesome. I wonder could you get the 'onclick' effect using CSS3's :target pseudo-class seen here paulrhayes.com/2009-06/accordion-using-only-css Though I'd have know idea how to apply it to my example. Onequestion on your solution: Is there a way to have it not push the div upwards on the page when hovered. i.e. could the div expand down only?
  • Alex Morales
    Alex Morales about 12 years
    Target requires a uri-fragment identifier. You'd need javascript to change the window's location to add one. reference.sitepoint.com/css/pseudoclass-target
  • Jedda
    Jedda about 12 years
    This is great! Cheers for sharing
  • Alex Morales
    Alex Morales about 12 years
    Yeah, in order to animate a height, you must have at the very least a min-height for the end state. You should be able to achieve the animation from height:0 to min-height: 300px or whatever value you want to set it to. I updated your fiddle to show it in action: jsfiddle.net/Nyq8u/2
  • Jedda
    Jedda about 12 years
    @alexmorales Great job! This is almost exactly what I'm after. See here reversl.net/box/#top Is there a way to set it up so that clicking the same link hides the content again rather than clicking the 'close' link inside the target?
  • Jedda
    Jedda about 12 years
    @davidthomas Thanks a mill. See my adaptation above.
  • Alex Morales
    Alex Morales about 12 years
    @Jedda Since you're using the link's href attribute to set the uri-fragment (which I completely forgot you can do), you need to change the href on click. Otherwise, you won't be able to accomplish this with only one link without any JS. (Unless of course, there's some way to change an element's attribute without using JS.)
  • kingjeffrey
    kingjeffrey about 12 years
    This is a fantastic solution.