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.
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.
Share Improve this question asked Jan 22, 2013 at 1:56 Betafresh MediaBetafresh Media 1871 gold badge2 silver badges11 bronze badges5 Answers
Reset to default 4CSS Only Solution
DEMO: http://jsfiddle/Victornpb/yJYJC/30/
Just use this:
/* Closed */
.wrapper{
margin-right:-250px;
}
/* Opened */
.wrapper:hover{
margin-right:0px;
}
Javascript solution
DEMO: http://jsfiddle/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;
}
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;
}
CSS Only, no-js sidebar
two versions with different behaviour
There are two different CSS only animated sidebar:
- inspired from @vitim.us, using hover for show / hide
- inspired from @niceass, using a hidden checkbox to click for show/hide
Features:
- Smooth animation
- Vertical text on sidebar (wich rotate when open)
- Dynamically resize body while sidebar are moving
- Clean box for body and sidebar
- scrollable sidebar content (displaying his scrollbar).
hover
(forked from @vitim.us's answer) with some improvements
If not pletely 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"> 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 modo 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 modo 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 will permit to have to click on (text of) the sidebar to open them and add some other labels where you want to be able to click on.
(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   */
}
#toggle:checked ~ .wrapper #zone #but:before{
content:"☒ Your ";
}
#toggle:not(checked) ~ .wrapper #zone #but:after {
content:" ☐"; /* figure space   */
}
#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 modo 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. Note that you could toggle sidebar by clicking <a href=''><label for="toggle">[here!]</label></a>...</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 modo 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>
: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:
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 themargin-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 theonclick
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.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./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
orfalse
as a value) to check if the cart was visible or not, changing the value at each click at the same time as themargin-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).
I would remend using jQuery for this. It is simple and less chance for errors.
$('.toggle').click(function() {
$('.cart').toggle();
});
http://api.jquery./toggle/