How to hide a list without javascript

I have this code and I would like to have the list be collapsed by default. Here is what it does now.

<!DOCTYPE html>
<head>
   <title>menu mockup</title>
   <style type="text/css">
      .show {display: none; }
      .hide:focus + .show {display: inline; }
      .hide:focus { display: none; }
      .hide:focus ~ #list { display:none; }
      @media print { .hide, .show { display: none; } }
   </style>
</head>
<body>
   <p>Here's a list</p>
      <div>
         <a href="#" class="hide">[hide]</a>
         <a href="#" class="show">[show]</a>
         <ol id="list">
            <li>item 1</li>
            <li>item 2</li>
            <li>item 3</li>
         </ol>
      </div>
   <p>How about that?</p>
</body>
</html>

Related posts

Leave a Reply

2 comments

  1. For this to work in pure CSS requires a change to the HTML (since CSS can only target elements that appear later in the DOM (either as later-siblings, or descendants, or a combination of those two) than the elements upon which they’re styled. So, the HTML is now:

    <p>Here's a list</p>
    <div id="top">
        <ol id="list">
            <li>item 1</li>
            <li>item 2</li>
            <li>item 3</li>
        </ol>
        <a href="#top" class="hide">[hide]</a>
        <a href="#list" class="show">[show]</a>
    </div>
    <p>How about that?</p>​
    

    Note also that the div now has an id in order to allow for the list to be hidden (again, using just CSS and basic HTML).

    The CSS is somewhat convoluted, though explained through /* comments in the CSS itself */:

    .show,
    .hide {
        /* allows for the links to be positioned 'ahead' of the list
           whose appearance they control */
        position: absolute;
        top: 0.1em;
        /* allows for an assigned width, height, etc... */
        display: inline-block;
        width: 5em;
        height: 2em;
        line-height: 2em;
        text-align: center;
    }
    
    .hide {
        left: 0;
    }
    
    .show {
        /* this is why we have an assigned width */
        left: 5.1em;
    }
    
    #list {
        /* hides on page-load */
        display: none;
    }
    
    #list:target {
        /* when clicking the 'show' link the #list is targeted
           and is shown */
        display: block;
    }
    
    #list:target ~ .show {
        /* reduces the opacity of the 'show' link, when
           the list is already shown */
        opacity: 0.3;
    }
    
    #list:target ~ .hide {
        /* when the list is shown, the 'hide' link is visible */
        opacity: 1;
    }
    
    #top {
        /* allows the links to be positioned visually ahead of,
           and relative to, the menu */
        position: relative;
        /* slightly greater than the defined height of
           the link elements */
        padding-top: 2.2em;
    }
    
    #top .hide,
    #top:target  .hide {
        /* hides the 'hide' link when the list is, itself, hidden */
        opacity: 0.3;
    }
    

    JS Fiddle demo.

    A slightly revised (another element added to wrap the links) version, to allow for more easily positioning them (rather than having to manually work out how wide each link is before setting the left position):

    <p>Here's a list</p>
    <div id="top">
        <ol id="list">
            <li>item 1</li>
            <li>item 2</li>
            <li>item 3</li>
        </ol>
        <!-- could use a div, it doesn't matter -->
        <span id="controls">
            <a href="#top" class="hide">[hide]</a>
            <a href="#list" class="show">[show]</a>
        </span>
    </div>
    <p>How about that?</p>​
    

    With the CSS:

    #controls {
        position: absolute;
        top: 0.1em;
        left: 0;
        height: 2em;
        line-height: 2em;
    }
    
    .show,
    .hide {
        display: inline-block;
        width: 5em;
        text-align: center;
    }
    
    #list {
        display: none;
    }
    
    #top {
        position: relative;
        padding-top: 2.2em;
    }
    
    #list:target {
        display: block;
    }
    
    #list:target ~ #controls .hide {
        opacity: 1;
    }
    
    #list:target ~ #controls .show {
        opacity: 0.3;
    }
    
    #top #controls .hide {
        opacity: 0.3;
    }
    #top:target #controls .hide {
        opacity: 0.3;
    }
    

    JS Fiddle demo.

    Or, instead, using visibility: hidden / visibility: visible;.

  2. This html code collapses the list by default

    <!DOCTYPE html>
    <head>
       <title>menu mockup</title>
       <style type="text/css">
          .show {display: inline; text-decoration: none;}
          .hide {display: none; text-decoration: none;}
          #list {display: none;}
          .show:focus + .hide {display: inline;}
          .hide:focus + #list { display:none;}
          .show:focus ~ #list { display:inline;}
          .show:focus { display:none;}
    
       </style>
    </head>
    <body>
       <p>Here's a list</p>
          <div>
    
    
             <a href="#" class="show">&#x25BC</a>
             <a href="#" class="hide">&#x25B2</a>
             <ol id="list">
                <li>item 1</li>
                <li>item 2</li>
                <li>item 3</li>
             </ol>
    
          </div>
      </body>
    </html>