I'm working on trying to get a div to slide up from the bottom. So far it works ok as I can get the div to show and hide when I need to by adding a class of open-drawer to the element that I'm trying to get to slide up. But I'm not sure how I can get it to animate and slide up from the bottom.
Not sure if I need to adjust something within the transition or what.
Here's what I got so far:
$(".drawer-link").click(function(e) {
var vdata = $(this).data("id");
$(".drawer[data-id=" + vdata + "]").addClass("open-drawer");
e.preventDefault();
});
$(".close").on("click", function(e) {
$(".drawer").removeClass("open-drawer");
e.preventDefault();
});
body {
padding: 20px;
}
.drawer {
position: fixed;
height: 100%;
width: 100%;
left: 0;
background: #0c1f3f;
padding-top: 90px;
overflow-y: scroll;
transition: top 0.5s ease;
color: white;
opacity: 0;
}
.wrapper {
width: 100%;
max-width: 1140px;
margin: 0 auto;
}
.open-drawer {
top: 150px;
opacity: 1;
}
.close {
color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<a class="drawer-link" href="#" data-id="drawer-01">Link To Show Drawer</a>
</div>
<div class="drawer" data-id="drawer-01">
<div class="wrapper">
<h3>Test</h3>
<p>This is the drawer</p>
<a class="close" href="#">Close The Drawer</a>
</div>
</div>
Link to demo (CodePen): https://codepen.io/ultraloveninja/pen/qzVQLp
Three examples: jQuery, pure JS, and pure HTML+CSS
Toggle animate panel using jQuery and .toggleClass()
Use transform: translateY at 100% and on click the class .is-open will animate to 0.
No need for extra special classes, use what you already have, a data-*
attribute: data-drawer="#drawer-01" (notice the ID # selector!)
Also, make sure to use id="drawer-01" as the drawer selector.
Use jQuery's .toggleClass()
Animating transform is always a better idea than animating non-accelerable properties like top, bottom etc etc
$("[data-drawer]").on('click', function(e) {
e.preventDefault();
$($(this).data("drawer")).toggleClass("is-open");
});
.drawer {
position: fixed;
height: 100%;
width: 100%;
left: 0;
top: 0;
background: #0c1f3f;
overflow-y: scroll;
color: white;
/* Initial transforms */
opacity: 0;
transform: translateY(100%);
transition: 0.5s ease;
}
.drawer.is-open {
opacity: 1;
transform: translateY(0);
}
<div>
Link To Show Drawer
</div>
<div class="drawer" id="drawer-01">
<div class="wrapper">
<h3>Test</h3>
<p>This is the drawer</p>
<a data-drawer="#drawer-01" href="#!">Close The Drawer</a>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Toggle animate panel in pure JavaScript and .classList.toggle()
If you don't want to use jQuery only because of such a simple task, here's in vanilla JavaScript:
const toggleDrawer = (evt) => {
evt.preventDefault();
document.querySelector(evt.target.getAttribute('data-drawer')).classList.toggle('is-open');
}
document.querySelectorAll('[data-drawer]').forEach(btn => btn.addEventListener('click', toggleDrawer));
.drawer {
position: fixed;
height: 100%;
width: 100%;
left: 0;
top: 0;
background: #0c1f3f;
overflow-y: scroll;
color: white;
/* Initial transforms */
opacity: 0;
transform: translateY(100%);
transition: 0.5s ease;
}
.drawer.is-open {
opacity: 1;
transform: translateY(0);
}
Link To Show Drawer
<div class="drawer" id="drawer-01">
<div class="wrapper">
<h3>Test</h3>
<p>This is the drawer</p>
<a data-drawer="#drawer-01" href="#!">Close The Drawer</a>
</div>
</div>
Toggle animate panel in pure HTML + CSS and a hidden checkbox
Need support for no-JS environment? Here you go
.drawer-button {color: blue; cursor: pointer;}
.drawer {
position: fixed;
height: 100%;
width: 100%;
left: 0;
top: 0;
background: #0c1f3f;
overflow-y: scroll;
color: white;
/* Initial transforms */
opacity: 0;
transform: translateY(100%);
transition: 0.5s ease;
}
.drawer-toggler:checked+.drawer {
opacity: 1;
transform: translateY(0);
}
<label class="drawer-button" for="drawer-01">SHOW DRAWER</label>
<div>Other HTML here...</div>
<input id="drawer-01" class="drawer-toggler" type="checkbox" hidden>
<div class="drawer">
<div class="wrapper">
<h3>Test</h3>
<p>This is the drawer</p>
<label class="drawer-button" for="drawer-01">CLOSE DRAWER</label>
</div>
</div>
If you're able to give the .drawer a fixed height, then you can change the bottom property to initially be negative that amount.
Be sure to also add the opacity to the transition, otherwise it will instantly hide instead of fading out gently.
$(".drawer-link").click(function(e) {
var vdata = $(this).data("id");
$(".drawer[data-id=" + vdata + "]").addClass("open-drawer");
e.preventDefault();
});
$(".close").on("click", function(e) {
$(".drawer").toggleClass("open-drawer");
e.preventDefault();
});
body {
padding: 20px;
}
.drawer {
position: fixed;
height: 150px;
bottom: -150px;
width: 100%;
left: 0;
background: #0c1f3f;
padding-top: 90px;
overflow-y: scroll;
transition: bottom 0.5s ease, opacity 0.5s ease;
color: white;
opacity: 0;
}
.wrapper {
width: 100%;
max-width: 1140px;
margin: 0 auto;
}
.open-drawer {
bottom: 0px;
opacity: 1;
}
.close {
color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<a class="drawer-link" href="#" data-id="drawer-01">Link To Show Drawer</a>
</div>
<div class="drawer" data-id="drawer-01">
<div class="wrapper">
<h3>Test</h3>
<p>This is the drawer</p>
<a class="close" href="#">Close The Drawer</a>
</div>
</div>
Related
Here is a codepen: https://codepen.io/jon424/pen/XWzGNLe
In this example, if you select the toggle button, the image will be covered by another div. The white square will gradually cover the image from the top of the image to the bottom.
I simply want to reverse this effect. I want the white square to cover the image, moving from the bottom of the image to the top.
I’ve tried using a negative value for max-height in the .covered class, but that wasn’t working. Any idea on how I can go about doing this?
document.querySelector('.child2').classList.add('covered');
document.querySelector('button').addEventListener('click', () => {
document.querySelector('.child2').classList.toggle('covered');
});
.parent {
position: relative;
width: 300px;
height: 300px;
margin: 10px;
overflow: hidden;
}
.child1 {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
.child2 {
z-index: 1;
background: #ffffff;
transition: max-height 1s ease-in-out;
max-height:100%;
}
.covered {
max-height: 0px;
}
<button>Toggle</button>
<div class="parent">
<img class="child1" src="https://picsum.photos/200/300">
<div class="child1 child2"></div>
</div>
Very simple: change the top: 0; attribute in .child1 to bottom: 0;
Here is another way to do it you can manipulate the top of the child2:
document.querySelector('button').addEventListener('click', () => { document.querySelector('.child2').classList.toggle('covered');});
.parent {
position: relative;
width: 300px;
height: 300px;
margin: 10px;
overflow: hidden;
}
.child1 {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
.child2 {
position: absolute;
top: 100%;
z-index: 1;
background: #ffffff;
transition: top 1s ease-in-out;
max-height: 100%;
}
.covered {
top: 0px;
}
<button>Toggle</button>
<div class="parent">
<img class="child1" src="https://picsum.photos/200/300">
<div class="child1 child2"></div>
</div>
By adding those lines on .child2 I am getting I think what you want:
bottom:0;
top:unset;
Here is the full working example:
document.querySelector(".child2").classList.add("covered");
document.querySelector("button").addEventListener("click", () => {
document.querySelector(".child2").classList.toggle("covered");
});
.parent {
position: relative;
width: 300px;
height: 300px;
margin: 10px;
overflow: hidden;
}
.child1 {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
.child2 {
z-index: 1;
background: #ffffff;
transition: max-height 1s ease-in-out;
max-height: 100%;
bottom:0;
top:unset;
}
.covered {
max-height: 0px;
}
<button>Toggle</button>
<div class="parent">
<img class="child1" src="https://picsum.photos/200/300">
<div class="child1 child2"></div>
</div>
Not sure but are you looking for this type of effect, I know CSS solution if this help you.
.parent {
position: relative;
}
.parent::before {
content: "";
position: absolute;
height: 0;
width: 100%;
background-color: white;
bottom: 100%;
left: 0;
transition: all 0.9s ease-in-out;
}
.parent:hover::before {
height: 100%;
bottom: 0;
-webkit-transition: height 0.9s ease;
transition: height 0.9s ease;
}
<div class="parent">
<img class="child1" src="https://picsum.photos/200/300">
</div>
</div>
I have such structure:
<div class="body">
<div class="wrapper">
<div class="dialog">
<div class="content-0"></div>
<div class="content-1"></div>
<div class="content-2"></div>
</div>
</div>
</div>
Parent element .dialog holds three content items which are horizontally aligned. Visible is only active .content-*. Other content items are hidden. When user clicks button, active item is sliding to the left to the hidden area, and next item becomes active and visible
Here is fiddle to demonstrate the behaviour: https://jsfiddle.net/fmbn28xs/
My question here - how can I adjust parent (.dialog) height every time user clicks button according to visible content (.content-*) item height only with CSS, is that possible?
Update:
Height of content items is not known in advance.
You can do it with custom css properties(preview with full page):
var index = 0;
function slide() {
index++;
var current = index % 3;
var target = document.querySelector(`.dialog`);
target.style.setProperty('--index', current);
}
.body {
background-color: #fff;
width: 100%;
height: 100%;
position: relative;
}
.wrapper {
background-color: grey;
position: absolute;
top: 50%;
right: 50%;
transform: translate(50%, 20%);
overflow: hidden;
}
.dialog {
--index: 0;
width: 300px;
display: flex;
height: calc(200px + 50px * var(--index));
transition: transform 400ms, height 400ms;
transform: translateX(calc(var(--index) * -100%));
}
.content-0, .content-1, .content-2 {
width: 300px;
flex: 0 0 100%;
position: relative;
}
.content-0 {
background-color: tomato;
height: calc(200px + 50px * 0);
}
.content-1 {
background-color: yellow;
height: calc(200px + 50px * 1);
}
.content-2 {
background-color: green;
height: calc(200px + 50px * 2);
}
button {
position: relative;
}
<div class="body">
<div class="wrapper">
<div class="dialog">
<div class="content-0"></div>
<div class="content-1"></div>
<div class="content-2"></div>
</div>
<button onclick="slide()">Next</button>
</div>
</div>
But you have to assign the height for all the content manually.
If you're using a precompile css library(such as scss), you can also automate this:
.dialog > *{
#for $i from 1 through 3 {
&:nth-child(#{$i}) {
height: calc(200px + 50px * #{$i});
}
}
}
Update
If the height is dynamic, you can use tricks with animation associate with alternating position from relative to absolute to make the container height
adapts accordingly, but this way you can't animate the height change, since the height is determined by the height of its children.
var index = 0;
function slide() {
index++;
var current = index % 3;
var target = document.querySelector(`.dialog`);
target.style.setProperty('--index', current);
target.setAttribute('data-index', current);
}
.body {
background-color: #fff;
width: 100%;
height: 100%;
position: relative;
}
.wrapper {
background-color: grey;
position: absolute;
top: 50%;
right: 50%;
transform: translate(50%, 20%);
overflow: hidden;
}
.dialog {
--index: 0;
width: 300px;
position: relative;
}
.dialog > * {
width: 300px;
position: absolute;
z-index: 0;
animation: popout 400ms both;
top: 0;
}
.dialog[data-index='0'] > *:nth-child(1),
.dialog[data-index='1'] > *:nth-child(2),
.dialog[data-index='2'] > *:nth-child(3) {
position: relative;
z-index: 1;
animation: popin 400ms both;
}
.content-0 {
background-color: tomato;
height: 200px;
}
.content-1 {
background-color: yellow;
height: 250px;
}
.content-2 {
background-color: green;
height: 300px;
}
button {
position: relative;
}
#keyframes popin {
from {
transform: translateX(100%);
}
to {
transform: translateX(0);
}
}
#keyframes popout {
from {
transform: translateX(0);
}
to {
transform: translateX(-100%);
}
}
<div class="body">
<div class="wrapper">
<div class="dialog" data-index="0">
<div class="content-0"></div>
<div class="content-1"></div>
<div class="content-2"></div>
</div>
<button onclick="slide()">Next</button>
</div>
</div>
Click on the image in snippet (expand full page) to run transform and look more closely at bottom right corner when animated card goes behind, you will see it overlaps slightly when it shouldn't. I happens when I apply z-index on each box div in CSS. If I remove z-index, there is no flash, but I need z-indexes on my box divs. Otherwise I cant have stack behave in such when I shuffle them (unless I change DOM order which I don't want). I have tried with some backface-visibility in CSS but with no luck. How could I get rid of such flash?
$('body').on('click', function() {
var box = $('#a2')
box.one("transitionend", function() {
box.css("zIndex", -1).one("transitionend", function() {
}).removeClass('t').addClass('t2')
}).addClass('t')
})
.box {
position: absolute;
width: 250px;
padding: 10px;
background: #fff;
box-shadow: 1px 1px 5px #484848;
left: 0;
top: 0;
height: 370px;
box-sizing: content-box;
transition-duration: 0.5s;
transition-timing-function: ease;
backface-visibility: hidden;
}
.box img {
display: block;
position: relative;
backface-visibility: hidden;
user-select: none;
}
#a1 {
z-index: 0;
transform: rotate(-4.5884deg);
}
#a2 {
z-index: 1;
transform: rotate(7deg);
}
.t {
transform: translateX(370px) rotate(23deg) !important;
}
.t2 {
transform: translateX(0) rotate(-7deg) !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="box" id="a1">
<img src="http://interactivepixel.net/tst/01.jpg" alt="" />
</div>
<div class="box" id="a2">
<img src="http://interactivepixel.net/tst/02.jpg" alt="" />
</div>
Happens in all browsers from what I can see.
The fix is actually simple - just add transition-property: transform because that is what you want to transform (transition-property: all is the default and z-index is also transitioned).
See demo below:
$('body').on('click', function() {
var box = $('#a2')
box.one("transitionend", function() {
box.css("zIndex", -1).removeClass('t').addClass('t2')
}).addClass('t')
});
.box {
position: absolute;
width: 250px;
padding: 10px;
background: #fff;
box-shadow: 1px 1px 5px #484848;
left: 0;
top: 0;
height: 370px;
box-sizing: content-box;
transition-duration: 0.5s;
transition-timing-function: ease;
backface-visibility: hidden;
transition-property: transform; /* added */
}
.box img {
display: block;
position: relative;
backface-visibility: hidden;
user-select: none;
}
#a1 {
z-index: 0;
transform: rotate(-4.5884deg);
}
#a2 {
z-index: 1;
transform: rotate(7deg);
}
.t {
transform: translateX(370px) rotate(23deg) !important;
}
.t2 {
transform: translateX(0) rotate(-7deg) !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="box" id="a1">
<img src="http://interactivepixel.net/tst/01.jpg" alt="" />
</div>
<div class="box" id="a2">
<img src="http://interactivepixel.net/tst/02.jpg" alt="" />
</div>
Why the flicker?
Note that z-index is an integer and it doesn't make much sense to transition it - the animation type is integer according to MDN:
When animated, values of the data type are interpolated
using discrete, whole steps. The calculation is done as if they were
real, floating-point numbers; the discrete value is obtained using the
floor function. The speed of the interpolation is determined by the
timing function associated with the animation.
See a sample of how you can animate z-index:
div {
position: absolute;
border: 1px solid;
}
.container div {
width: 100px;
height: 100px;
}
.container .box {
background-color: cadetblue;
z-index: 1;
animation: stack 5s infinite linear;
}
.box + div {
top: 10px;
left: 10px;
z-index: 1;
background-color: lightblue;
}
.box + div + div {
top: 20px;
left: 20px;
z-index: 2;
background-color: aliceblue;
}
#keyframes stack {
50% {
z-index: 3;
}
}
<div class="container">
<div class="box"></div>
<div></div>
<div></div>
</div>
This is why you have the flicker in your animation.
I think it is merely an order problem.
Just place the .css (" zIndex ", -1) next to the .addClass ('t'):
this way flash doesn't happen since z-index is applyed before the backward translation
$('body').on('click', function() {
var box = $('#a2')
box.one("transitionend", function() {
box.removeClass('t').addClass('t2')
}).css("zIndex", -1).addClass('t')
})
I just update your code with jQuery update. Actually i just move your box.css("zIndex", -1).addClass('t'); script in setTimeout method. Try this I hove it'll resolve your issue. Thanks
$('body').on('click', function() {
var box = $('#a2')
box.one("transitionend", function() {
box.one("transitionend").addClass('t2');
})
setTimeout(function(){
box.css("zIndex", -1).addClass('t');
})
})
.box {
position: absolute;
width: 250px;
padding: 10px;
background: #fff;
box-shadow: 1px 1px 5px #484848;
left: 0;
top: 0;
height: 370px;
box-sizing: content-box;
transition-duration: 0.5s;
transition-timing-function: ease;
backface-visibility: hidden;
}
.box img {
display: block;
position: relative;
backface-visibility: hidden;
user-select: none;
}
#a1 {
z-index: 0;
transform: rotate(-4.5884deg);
}
#a2 {
z-index: 1;
transform: rotate(7deg);
}
.t {
transform: translateX(370px) rotate(23deg) !important;
}
.t2 {
transform: translateX(0) rotate(-7deg) !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="box" id="a1">
<img src="http://interactivepixel.net/tst/01.jpg" alt="" />
</div>
<div class="box" id="a2">
<img src="http://interactivepixel.net/tst/02.jpg" alt="" />
</div>
I tried increasing the z-index of the succeeding image and it works.
$('body').on('click', function() {
var box = $('#a2')
var i=0;
box.one("transitionend", function() {
// increase the z-index
$("#a1").css("zIndex", 99);
box.css("zIndex", -1).one("transitionend", function() {
}).removeClass('t').addClass('t2')
}).addClass('t')
})
.box {
position: absolute;
width: 250px;
padding: 10px;
background: #fff;
box-shadow: 1px 1px 5px #484848;
left: 0;
top: 0;
height: 370px;
box-sizing: content-box;
transition-duration: 0.5s;
transition-timing-function: ease;
backface-visibility: hidden;
}
.box img {
display: block;
position: relative;
backface-visibility: hidden;
user-select: none;
}
#a1 {
z-index: 0;
transform: rotate(-4.5884deg);
}
#a2 {
z-index: 1;
transform: rotate(7deg);
}
.t {
transform: translateX(370px) rotate(23deg) !important;
}
.t2 {
transform: translateX(0) rotate(-7deg) !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="box" id="a1">
<img src="http://interactivepixel.net/tst/01.jpg" alt="" />
</div>
<div class="box" id="a2">
<img src="http://interactivepixel.net/tst/02.jpg" alt="" />
</div>
I'm trying to use transformY to animate the sliding down of an element when you click on a link in the header. The issue i'm having is that the element being displayed is nested a few levels deep and this is what I think is causing the problem - I need the element to slide down from behind the parent elements. Setting z-index doesn't appear to work in this context. I've created a JS Fiddle below - grateful for any help! In this demo, the green parent container should be sitting on top of the yellow hidden element.
jQuery('.test-link').on('click', function(e) {
e.preventDefault();
jQuery('.container').toggleClass('active');
});
.outer-container {
background: green;
width: 100%;
position: relative;
z-index: 5;
}
.container .hidden-content {
transition: all 0.2s ease;
transform: translateY(-100%);
position: absolute;
z-index: -1;
z-index: 1;
width: 100vw;
left: 0;
right: 0;
background: yellow;
}
.test-link {
margin-left: 100px;
display: block;
position: relative;
z-index: 3;
width: 200px;
background: red;
}
.container.active .hidden-content {
transform: translateY(0%);
}
.other-content {
position: relative;
z-index: 4;
background: blue;
}
.test-content {
position: relative;
z-index: 5;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class="outer-container">
<div class="test-content">
<div class="container">
TEST LINK
<div class="hidden-content">
<h1>My Hidden Content</h1>
<h1>My Hidden Content</h1>
</div>
</div>
</div>
<div class="other-content">
<h2>This should be overlaid by the sliding out content</h2>
</div>
</div>
You can do that with a negative z-index
jQuery('.test-link').on('click', function(e) {
e.preventDefault();
jQuery('.container').toggleClass('active');
});
.another-container {
position: relative;
z-index: 1;
}
.outer-container {
background: green;
width: 100%;
position: relative;
}
.container .hidden-content {
transition: all 0.2s ease;
transform: translateY(-100%);
position: absolute;
background: yellow;
z-index: -1;
}
.test-link {
display: block;
position: relative;
width: 200px;
background: red;
}
.container.active .hidden-content {
transform: translateY(0%);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="another-container">
<div class="outer-container">
<div class="test-content">
<div class="container">
TEST LINK
<div class="hidden-content">
<h1>My Hidden Content</h1>
<h1>My Hidden Content</h1>
</div>
</div>
</div>
</div>
</div>
<div>yellow box should be on top</div>
I am just trying to make the effect of an element appearing as the cursor hovers over an image. I want a box to appear where I can put content inside, possibly a video or an image. Here is what I have so far as the hover effects go and I tried writing a script to add the class but I'm not sure why it's not working.
<div id="scripture">
<div class="hover11 column wholeimage">
<div>
<figure><img src="img/large.jpg" class="largeimage largerimage" /></figure>
</div>
</div>
</div>
<script type="text/javascript">
$(‘.column).hover(
function(){$(this).toggleClass(hoveritem);}
);
</script>
CSS
.largerimager {
opacity: 1
width: 100%;
height: auto;
z-index: -1000;
}
.wholeimage {
width: 100%;
height: 500px;
margin-bottom: 50px;
}
.hover11 figure img {
opacity: 1;
-webkit-transition: .3s ease-in-out;
transition: .3s ease-in-out;
}
.hover11 figure:hover img {
opacity: .75;
}
.largeimage {
max-width: 100%;
}
.hoveritem {
width: 200px;
height: 600px;
background-color: black;
}
Wrap your code in a document ready function, add simple quotes to the toggled class and the column selector
<script type="text/javascript">
$(function(){
$('.column').hover(
function(){$(this).toggleClass('hoveritem');}
);
});
</script>
better go with a mouseenter-mouseleave events
Quotes are wrongly placed.And try with $(document).ready(function(){}
$(document).ready(function(){
$('.column').hover(
function(){$(this).toggleClass('hoveritem');}
);
})
.largerimager {
opacity: 1
width: 100%;
height: auto;
z-index: -1000;
}
.wholeimage {
width: 100%;
height: 500px;
margin-bottom: 50px;
}
.hover11 figure img {
opacity: 1;
-webkit-transition: .3s ease-in-out;
transition: .3s ease-in-out;
}
.hover11 figure:hover img {
opacity: .75;
}
.largeimage {
max-width: 100%;
}
.hoveritem {
width: 200px;
height: 600px;
background-color: black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="scripture">
<div class="hover11 column wholeimage">
<div>
<figure><img src="img/large.jpg" class="largeimage largerimage" /></figure>
</div>
</div>
</div>