3

here's my situation:

So I'm trying to toggle a sidebar by clicking another div. It's a 100% height sidebar that is fixed to the right side of the viewport. Essentially I am trying to wrap a 300px div around both the 50px wide toggle div and the 250px wide sidebar div, and I want to hide the sidebar portion using a negative margin-right pixel value. Using the .toggle:active selector (so this occurs when the toggle div is clicked), I want to show the sidebar portion by setting that margin-right pixel value back to 0px.

Code so far:

<div class="wrapper">
  <a href="#">
    <div class="toggle">Toggle</div>
  </a>
  <div class="cart">Cart</div>
</div>

CSS so far:

.wrapper {
  position:fixed;
  width:300px;
  height:100%;
  background-color:orange;
  top:0;
  right:0;
  margin-right:-250px;
}
.toggle {
  position:relative;
  display:block;
  width:50px;
  height:100%;
  background-color:grey;
  float:left;
}
.toggle:active .wrapper {
  margin-right:0px;
}
.cart {
  position: relative;
  width:250px;
  height:100%;
  background-color:red;
  float:right;
}

Here's the jsfiddle!

Here's my question:

How can I target .wrapper to change a css attribute when .toggle:active is engaged? Also, how can I specify when the sidebar is visible and when it's not?

I'm new to Javascript, but it seems like I'll need it to do this due to the callback function. If CSS-only is possible, I'd lean toward that solution. Please note that I want to use margin-right so that I can opt to use CSS transitions later to animate my element sliding left and right.

Betafresh Media
  • 177
  • 1
  • 2
  • 11

5 Answers5

4

CSS Only Solution

DEMO: http://jsfiddle.net/Victornpb/yJYJC/30/

Just use this:

/* Closed */
.wrapper{
    margin-right:-250px; 
}

/* Opened */
.wrapper:hover{
    margin-right:0px;
}

Javascript solution

DEMO: http://jsfiddle.net/Victornpb/yJYJC/6/

JS:

var wrapper = document.getElementsByClassName('wrapper')[0];
var toggle = document.getElementsByClassName('toggle')[0];

window.onload=function(){

    toggle.onclick=function(){
        wrapper.classList.toggle('opened'); 
    }

}

CSS:

.wrapper{
    position:fixed;
    width:300px;
    height:100%;
    background-color:orange;
    top:0;
    right:0;
    margin-right:-250px;
}
.wrapper.opened{
    margin-right:0px;
}
Vitim.us
  • 20,746
  • 15
  • 92
  • 109
3

A CSS-only solution (DEMO):

<div class="wrapper">    
  <label for="toggle">
     Toggle
  </label>    
  <input id="toggle" type="checkbox" />
  <div class="cart">Cart</div>
</div>

(The hidden checkbox is used to determine the toggle state)

#toggle {    
  display:none; /* hide checkbox */
}

/* the label associated with the checkbox (trigger) */
label{
  display:block;
}

/* move the div adjacent to the input (.cart) inside the visible area */
/* when the input is checked */
#toggle:checked ~ .cart{
  right:0;
}

/* the div that's being toggled */
.cart {
  position: absolute;
  width: 250px;
  height: 100%;
  right: -250px;
}
nice ass
  • 16,471
  • 7
  • 50
  • 89
1

:active only works for links (i.e. <a> tags), so it can't be used on .toggle, since it's a <div>. Even if you put it on the link, I don't think it'll do what you want though, and there's no way to "target" the parent. Having a <a> surrounding a <div> like that is pretty strange too, you shouldn't need that.

So, you'll need javascript, yes. But you can't really target a class in javascript. You have two solutions:

  1. If you can add an id to the wrapper, you can create a function in javascript that will toggle the state of the sidebar:

    <div class="wrapper" id="myId">
        <a href="#">
            <div class="toggle"
                 onclick="document.getElementById('myId').style.marginRight = (document.getElementById('myId').style.marginRight == '0') ? '-250px' : '0';">Toggle</div>
        </a>
        <div class="cart">Cart</div>
    </div>
    

    Notes: The part (document.getElementById('myId').style.marginRight == '0') ? '-250px' : '0' tests if the margin-right is 0 and if so changes it to -250px and vice versa. What I've done here might not be the best way to do, but I wanted to limit it to something short so you can use it this way, if you don't really understand javascript very well. You will be able to improve it when you'll get to know it better. Also, you will have to put the onclick on every .toggle div you have... You can use event handlers, but I'm pretty sure you don't know what that mean and that might not be a good idea to simply copy-paste this. You can always use the second point for that, since it makes things relatively easy to understand.

  2. If you really want the class (or need to repeat this a lot), you will have to use jQuery, a javascript library, by adding this (preferably in the <head>):

    <script type="text/javascript" src="http://code.jquery.com/jquery-1.9.0.min.js"></script>
    

    Then you can add this (to the head preferably still):

    <script type="text/javascript">
        $(document).ready( function()
        {
            var cart_visible = false;
    
            $('.toggle').on('click', function()
            {
                if ( cart_visible )
                    $('.wrapper').css('margin-right', '-250px');
                else
                    $('.wrapper').css('margin-right', '0');
    
                cart_visible = !cart_visible;
            });
        });
    </script>
    

    This time I used a boolean (that takes true or false as a value) to check if the cart was visible or not, changing the value at each click at the same time as the margin-right. This does the same thing as before, just toggles between -250px and 0, but you don't need to put it in every .toggle you might create and it works with a class. It makes you use jQuery though (that's not really a problem though I think)

I don't really see why you want to change margin-right though... If you just want to make it disappear, you can use display: none;, or if you really want to change the position, you can use right (in this case).

1

CSS Only, two sidebar with different behaviour

There are two different CSS only animated sidebar:

  1. inspired from @vitim.us, use hover for show/hide
  2. inspired from @niceass, use a hidden checkbox to click for show/hide

Features:

  • Smooth animation
  • Vertical text on sidebar (wich rotate when open)
  • Resize body when sidebar are shown
  • Clean box for body and sidebar
  • scrollable sidebar content (displaying his scrollbar).

hover (forked from @vitim.us's answer) with some improvements

If not completely finalized, there is some way to

  • write Open cart / Your cart verticaly
  • suppress newline between Open/Your and cart by using no-breakable space in the CSS.
  • resize main content dynamicaly, while side bar is displaying.

body {
    font-family: sans;
    font-weight: normal;
    font-size: 10pt;
}
.main {
    width: calc( 100% - 3em );
    transition: width ease 1300ms;
}
.wrapper:hover ~ .main {
    width: calc( 100% - 17em );
}
h1 {
    font-weight: bold;
    font-size: 1.3 em;
}
h2 {
    font-weight: bold;
    font-size: 1.15 em;
}
.wrapper{
    position:fixed;
    width: 16em;
    height:100%;
    background-color:orange;
    top:0;
    right:0;
    margin-right:-14em;
    /* Makes opening smoothly */
    transition: margin-right ease 1300ms;
    -moz-transition: margin-right ease 1300ms;
    -webkit-transition: margin-right ease 1300ms;
    -o-transition: margin-right ease 1300ms;
}
.inner {
    position: relative;
    width: 100%;
    float: left;
    display: inline-block;
    transform: rotate(90deg)  translate(-3em,0em);
    transition: transform ease 1300ms;
}

/* opened */
.wrapper.opened,
.wrapper:hover{
    margin-right:0px;
}

.toggle {
  position:relative;
    display:block;
    width:2em;
    height:100%;
    background-color:#CCC;
    float:left;
    font-weight: bold;
    text-align: center;
    padding-top: 50%;
    transition: background-color ease 1300ms;
    transition: color ease 1300ms;
}

/* toggle style when wrapper is hovered */
.wrapper:hover .toggle{
    background-color: #555;
    color: white;
}
.wrapper:hover .toggle .inner{
    transform: rotate(270deg);
}
/* Warn: there is NBSP, not spaces, after Open/Your */
.wrapper:not(:hover) .toggle .inner:before{
    content:"Open";
}
.wrapper:hover .toggle .inner:before{
    content:"Your";
}

.cart {
    position: relative;
    width:13.5em;
    height:100%;
    background-color:rgba(255,255,255,.4);
    float:right;
    padding: .2em;
    overflow: scroll;
}
<div class="wrapper">
    <div class="toggle"><div class="inner">&nbsp;cart</div></div>
    <div class="cart">
        <h2>Cart</h2>
        <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.
       </p>
    </div>
</div>
<div class="main">
<h1>Little <i>no-js</i> css side-bar demo</h1>
<p>This little demo let you see how a side-bar could be done without being using javascript...</p>
 <h2>Lorem Ipsum</h2>   <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.</p>
<p>Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
   </p>

</div>

toggle:checked (forked from @niceass's answer)

Same improvements, but using an invisible checkbox, so you have to click on (text of) the sidebar to open them.

(This answer is linked to What does "for" attribute do in HTML tag?)

body {
    font-family: sans;
    font-weight: normal;
    font-size: 10pt;
}
#toggle { display:none; }
.main {
    width: calc( 100% - 3em );
    transition: width ease 1300ms;
}
#toggle:checked ~ .main {
    width: calc( 100% - 17em );
}
h1 {
    font-weight: bold;
    font-size: 1.3 em;
}
h2 {
    font-weight: bold;
    font-size: 1.15 em;
}
.wrapper{
    position:fixed;
    width: 16em;
    height:100%;
    background-color:orange;
    top:0;
    right:0;
    margin-right:-14em;
    /* Makes opening smoothly */
    transition: margin-right ease 1300ms;
    -moz-transition: margin-right ease 1300ms;
    -webkit-transition: margin-right ease 1300ms;
    -o-transition: margin-right ease 1300ms;
}
#toggle:checked ~ .wrapper {
    margin-right: 0pt;
}
#but {
    position: relative;
    width: 100%;
    float: left;
    display: inline-block;
    transform: rotate(270deg)  translate(-3em,0em);
    transition: transform ease 1300ms;
}
/* opened */
#zone {
  position:relative;
    display:block;
    width:2em;
    height:100%;
    background-color:#CCC;
    float:left;
    font-weight: bold;
    text-align: center;
    padding-top: 50%;
    transition: background-color ease 1300ms;
    transition: color ease 1300ms;
}

/* toggle style when wrapper is hovered */
#toggle:checked ~ .wrapper #zone {
    background-color: #555;
    color: white;
}
#toggle:checked ~ .wrapper #zone #but {
    color: white;
    transform: rotate(90deg);
}
#toggle:not(checked) ~ .wrapper #zone #but:before {
    content:"Open ";    /* non break space &#160; */
}
#toggle:checked ~ .wrapper #zone #but:before{
    content:"☒ Your ";
}
#toggle:not(checked) ~ .wrapper #zone #but:after {
    content:" ☐";        /* figure space &#8199; */
}
#toggle:checked ~ .wrapper #zone #but:after {
    content:"";
}
.cart {
    position: relative;
    width:13.5em;
    height:100%;
    background-color:rgba(255,255,255,.4);
    float:right;
    padding: .2em;
    overflow: scroll;
}
<input id="toggle" type="checkbox" />  
<div class="wrapper">
    <div id="zone"><label for="toggle" id="but">chart</label></div>
    <div class="cart">
        <h2>Cart</h2>
      <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.
       </p>
    </div>
</div>
<div class="main">
<h1>Little <i>no-js</i> css side-bar demo</h1>
<p>This little demo let you see how a side-bar could be done without being using javascript...</p>
 <h2>Lorem Ipsum</h2>   <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.</p>
<p>Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
   </p>

</div>
F. Hauri - Give Up GitHub
  • 64,122
  • 17
  • 116
  • 137
0

I would recommend using jQuery for this. It is simple and less chance for errors.

$('.toggle').click(function() {
    $('.cart').toggle();
});

http://api.jquery.com/toggle/

Michael Garrison
  • 941
  • 2
  • 15
  • 31
  • This worked nicely, but I modified it to suit my needs (with a callback). [The jsfiddle](http://jsfiddle.net/yJYJC/27/) Thank you kindly! – Betafresh Media Jan 22 '13 at 02:52
  • 1
    I don't like the idea of using a whole bloated library to do such a basic thing, when you can easily do it using plain js or just only css. IMHO – Vitim.us Jan 22 '13 at 03:07
  • @Vitim.us I agree with you. It is silly, but I personally like to use jQuery for things like this. I was thinking that maybe if he other features like this then he might switch them over to jQuery as well, however, if this is the only instance then js or CSS would be better. – Michael Garrison Jan 22 '13 at 17:01