Slide a div into appearance without jQuery - javascript

I am using onclick method on a link in order to display a div. However, it doesn't slide, it simply appears. How do I make it appear with a slide effect without using jQuery. The reason I don't want to use jQuery is because I want the page to load as fast as possible.
function view() {
document.getElementById('topmenu').setAttribute('style', 'display:block');
}
#topbar {
background-color: yellow;
overflow: auto;
}
#topmenu {
display: none;
}
<header>
<div id="topbar">
<img src="/images/santorini-wedding-photographer-logo.png" style="float: left;">
<span style="float: right;">MENU</span>
</div>
<div id="topmenu">
some text here
</div>
</header>

It can be done using Javascript
setInterval() and clearInterval() functions.
See code samples here
JavaScript slidedown without jQuery

You can't apply transition to display property - you can transition scale instead - see demo below:
function view() {
// add a class to show the element
document.getElementById('topmenu').classList.add('show');
}
#topbar {
background-color: yellow;
overflow: auto;
}
#topmenu {
transform: scaleY(0); /* scale to zero vertically */
transform-origin: top; /* set origin to top */
overflow: hidden;
transition: transform 1s; /* apply transition to only scale */
}
#topmenu.show {
transform: scaleY(1); /* scale to full height */
}
<header>
<div id="topbar">
<img src="https://via.placeholder.com/50" style="float: left;">
<span style="float: right;">MENU</span>
</div>
<div id="topmenu">
some text here
</div>
</header>

Related

Moving an element smoothly to its new position without manually setting its position

My apologies if the subject is a bit non-descriptive. I'm having a hard time trying to explain what I'm trying to achieve in a one-liner.
But in a few sentences: I'm trying to have an element, a DIV in this case, move smoothly to its new position. But the caveat is that I'm not setting its position manually. It receives a new position because I'm removing other DIVs from the page flow.
<!DOCTYPE html>
<html>
<head>
<style>
.block {
width: 200px;
height: 20px;
border: 1px solid black;
margin: 20px;
}
</style>
<script>
function removeBlock() {
document.getElementById("block2").style.display = "none";
}
</script>
</head>
<body>
<div id="block1" class="block">
This is block 1
</div>
<div id="block2" class="block">
This is block 2
</div>
<div id="block3" class="block">
This is block 3
</div>
<button type="button" onclick="removeBlock();">
Remove block 2
</button>
</body>
</html>
Here's the fiddle: https://jsfiddle.net/nfhycrkL/
If you click the button, Block 2 is hidden and Block 3 moves up. I want this move to be smooth. Is this at all possible? I don't want to use absolute positioning since the page is responsive and the position of the DIVs are depending on the page size.
Try This Solution
function removeBlock()
{
document.getElementById("block2").style.height = "0px";
document.getElementById("block2").style.margin = "0px";
document.getElementById("block2").style.borderWidth = "0px";
document.getElementById("block2").style.fontSize = "0px";
}
.block {
width: 200px;
height: 20px;
border: 1px solid black;
margin: 20px;
}
#block2 {
transition:all 0.5s linear;
}
<div id="block1" class="block">
This is block 1
</div>
<div id="block2" class="block">
This is block 2
</div>
<div id="block3" class="block">
This is block 3
</div>
<button type="button" onclick="removeBlock();">
Remove block 2
</button>
You could add a new class to an element with javascript that you want to hide and do css transition.
Here's a small example with remove and toggle options https://jsfiddle.net/nfhycrkL/9/
html:
<div id="block1" class="block">
This is block 1
</div>
<div id="block2" class="block">
This is block 2
</div>
<div id="block3" class="block">
This is block 3
</div>
<button type="button" onclick="toggleBlock();">
Toggle block 2
</button>
<button type="button" onclick="removeBlock();">
Remove block 2
</button>
js :
function toggleBlock() {
document.getElementById("block2").classList.toggle('block-hidden')
}
function removeBlock() {
document.getElementById("block2").classList.add('block-hidden')
}
css:
.block {
width: 200px;
height: 20px;
border: 1px solid black;
margin: 0 20px 20px;
overflow:hidden;
transition: all .25s;
}
.block-hidden {
height: 0px;
margin: 0px;
border: none;
}
$(document).ready(function(){
$("button").click(function(){
//document.getElementById("block2").style.display = "none";
$("#block2").fadeOut(1000);
});
});
.block {
width: 200px;
height: 20px;
border: 1px solid black;
margin: 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.3/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.css" rel="stylesheet"/>
<div id="block1" class="block">
This is block 1
</div>
<div id="block2" class="block">
This is block 2
</div>
<div id="block3" class="block">
This is block 3
</div>
<button type="button">
Remove block 2
</button>
use Jquery effects. I hope this helps.
Here's a simple example in vanillaJS with a CSS transition
Jsfiddle demo
Update your style adding a transition for the .block element
CSS
.block {
width: 200px;
height: 20px;
border: 1px solid black;
margin: 20px 20px 0;
max-height: 500px;
transition: opacity 0s 0s, margin .25s 0s, max-height .25s 0s;
}
.removedBlock {
box-sizing: border-box;
opacity: 0;
margin: 0;
max-height: 0;
}
so that the function can trigger a max-height animation by adding the removedBlock class
<div id="block1" class="block">
This is block 1
</div>
<div id="block2" class="block">
This is block 2
</div>
<div id="block3" class="block">
This is block 3
</div>
<button type="button" onclick="removeBlock('block2');">
Remove block 2
</button>
JS
function removeBlock(id) {
var block = document.getElementById(id);
block.classList.add('removedBlock');
}
When you do a removal, the element disappears due the opacity set to 0, then margin and max-height will make the block collapsing.
Note that since a transition can't be triggered to/from an auto value I've set a huge starting max-height for this purpose. If you want to see a smoother transition either change that property with a lower value or simply increase the duration of the transition.
A more refined version could instead get the height of the element before applying the transition e.g.
function removeBlock(id) {
var block = document.getElementById(id);
var blockHeight = block.offsetHeight;
block.style.height = blockHeight + 'px';
block.classList.add('removedBlock');
}
so the style becomes
.block {
width: 200px;
height: 20px;
border: 1px solid black;
margin: 20px 20px 0;
transition: opacity 0s 0s, margin .5s 0s, height .5s 0s;
}
.removedBlock {
box-sizing: border-box;
opacity: 0;
margin: 0;
height: 0 !important;
}
JsFiddle
Thanks everybody for your answers! And although all of them work somewhat, they do not work as soon as the layout becomes more complex, or if you try to hide/show more/other objects.
So I spend the past few hours creating a Javascript solution that I think will work in any situation (and on any browser too).
In short, how it works is that you "mark" as many elements as you like to be hidden/shown with the SetDisplay() function (see the first button). Once that has been done, you call the same SetDisplay function without any parameters and see the magic happen! The Javascript actually quickly removes the elements and let the page reflow (all invisible to the viewer). It then examines the new positions, reinserts the elements to hide and move all other elements to their new position by setting style.transition and by using position:relative and new top and left values. Once it's done with the transition, it hides the elements permanently, resets all changed style values and let the page reflow again.
SetDisplay( "block2", "none" );
SetDisplay( "block3", "none" );
SetDisplay( "block4", "none" );
SetDisplay();
You can reinsert elements the same way (the second button).
SetDisplay( "block2", "" );
SetDisplay();
https://jsfiddle.net/yq7xor5j/3/
(Edit: made a change to the fiddle to correct a small bug)

Appending to bottom of container (not end of code)

General Info
Working on a chatsystem. When users join a chatroom, they're unable to see any previous messages. I'm trying to make the first new message appear at the bottom of the messages container and then just append followup messages underneath it.
Ideas I've had myself
Make the container relative and each message absolute positioned. Then just give the message bottom: 10px;. This wouldn't work, as it would keep the messages at the bottom and start stacking them up.
Create an invisible div inside the container with a percentage height so most of the empty space is taken and any message appended would appear underneath it. This also wouldn't work because percentage height would remain in effect and keep pushing everything down.
Create an invisible div and use Javascript to give it a static height based on the users screensize. It would work, but issues will arise if the user resizes his screen. Could technically solve that with a custom event handler onresize and resize the invisible div, but it feels like this would be a wrong approach to the issue.
Code
Chatroom messages container:
<div class="chatroom" id="room-roomname"></div>
Example of a message:
<div class="row">
<div class="col s12 chat-msg-container">
<div class="chat-msg">
<span class="default-color">
Username
</span><br/>
<span>
Message
</span>
</div>
<div class="chat-msg-image">
<img class="userImg" src="">
</div>
</div>
</div>
Question
I'm looking for the correct approach to do this. How to append a div at the visual bottom of a div?
Using translateY with fixed whole msg container:
var msgRow = `<div class="row">
<div class="col s12 chat-msg-container">
<div class="chat-msg">
<span class="default-color">
Username
</span><br/>
<span>
Message {{num}}
</span>
</div>
<div class="chat-msg-image">
<img class="userImg" src="">
</div>
</div>
</div>
`;
var scrollbox = document.getElementById('scroll-box');
var chatrooms = document.querySelectorAll('.chatroom');
var chatbox = document.getElementById('chat');
var i = 0;
var id = setInterval(function() {
let room = chatrooms[i % 2];
room.innerHTML += msgRow.replace('{{num}}', i);
if (i == 0 || i == 1) room.classList.add('active');
if (i == 3) window.clearInterval(id);
i++;
}, 1000);
#chatrooms {
position: absolute;
top: 0;
left:0;
width: 100%;
border: 1px solid red;
overflow: hidden;
}
#scroll-box {
height: 170px;
overflow-y: scroll;
display: flex;
}
#chat.container {
margin-top: auto;
}
.chatroom {
align-self: flex-end;
transform:translateY(100%);
transition: transform 0.5s ease-in;
}
.chatroom.active {
transform: translateY(0%);
}
.chat-msg-container {
background-color: lightgrey;
margin-bottom: 10px;
animation: animateElement ease-in .5s;
animation-iteration-count: 1;
}
#keyframes animateElement{
0% {
transform: translateY(100%);
}
100% {
transform: translateY(0%);
}
}
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet"/>
<div id="chatrooms">
<div id="scroll-box">
<div id="chat" class="container">
<div class="row">
<div class="chatroom col-6"></div>
<div class="chatroom col-6"></div>
</div>
</div>
</div>
</div>

CSS transition duration not applying on first instance of transition effect

I'm trying to create a series of sliding divs triggered on press of a button. The idea is that each div will have a thumbnail and some text tied to it. Upon clicking left/right button, the divs will move their position accordingly.
My code can be seen in the jsfiddle below. I'm encountering 3 problems:
1) The "transition: left 2s" rule isn't applying on the first transition effect, it does on the subsequent ones.
2) I'd like the repeat pressing of the corresponding buttons to apply the left property value again so that I can slide the divs repeatedly.
3) Instead of the "right" button re-positioning the "left" property back to 0, I'd like to shift it back in the opposite direction with the previous left property value.
Essentially I'm trying to recreate the slider found on this side.
http://www.euphoriumbakery.com/
Any help or input will be greatly appreciated.
Thank you very much for your help.
https://jsfiddle.net/kshatriiya/g709swLg/1/
window.onload = function() {
$("#left").on("click", function() {
$("#view").css("left", "-262px");
});
$("#right").on("click", function() {
$("#view").css("left", "0px");
});
}
#galwrapper {
width: 650px;
height: 400px;
display: block;
overflow: hidden;
}
#view {
position: relative;
width: 1423px;
transition: left 2s;
}
.col-md {
display: inline-block;
margin-top: 100px;
width: 18%;
}
.thumb img {
opacity: 0.9;
height: auto;
width: auto;
max-height: 150px;
max-width: 150px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="galwrapper">
<div id="view">
<div class="col-md">
<div class="thumb">
<img class="img-rounded" src="http://netdna.walyou.netdna-cdn.com/wp-content/uploads/2010/09/retrocake1.jpg">
<div class="caption">
<h4>Retro Cake</h4>
</div>
</div>
</div>
<div class="col-md">
<a href="#" class="thumb active">
<img class="img-rounded" src="https://i.ytimg.com/vi/dh8ii5sbvyc/maxresdefault.jpg">
<div class="caption">
<h4>Strawberry Cake</h4>
</div>
</a>
</div>
<div class="col-md" id="mid">
<a href="#" class="thumb">
<img src="https://i.ytimg.com/vi/dh8ii5sbvyc/maxresdefault.jpg">
<div class="caption">
<h4>Retro Cake</h4>
</div>
</a>
</div>
#view {
position: relative;
width: 1423px;
left:0;
transition: left 2s;
}
Initially make left:0; for the div with id view https://jsfiddle.net/81tqeof4/6/
and for sliding effect get the current left position and update the position.check fiddle for an example
$("#left").on("click", function(){
var leftPosition = parseInt($("#view").position().left) - 256;
$("#view").css("left", -Math.abs(leftPosition));
});
transition works only on an existing property
So initially(in your CSS) you do not have a left property available in your #view. It is only later on a click that your JavaScript adds the left and your transition starts working.
So basically you need to set the left property to a value in your CSS, before your JavaScript takes effect and adds the left
#view {
position: relative;
width: 1423px;
left: 0; //initiate
transition: left 2s;
}

Issue when animating on hover effects with callbacks

So I am having this issue when I am using the hover event in jQuery. I have two containers side by side. I have hover events on both of them. When hover, a div with additional info slides up into frame. When you hover off, it slides back down.
Simple right? When you hover on an element it should remove the "hide-me" class and start sliding the info up (animating). When you hover off of an element the "hide-me" class should be removed once the animation is complete.This works fine when you hover on and hover off onto an element that is not a grid-item. When you hover off of an item onto another grid-item it seems to just add the class "hide-me" to the currently hovered element. Even though the hover off event hasn't fired yet.
Anyways enough talk here is the code on JS Fiddle:
https://jsfiddle.net/joemoe_1984/2k22yLmd/2/
For testing here is what works:
Hover from below/above image then hover out from below/above image
For testing how it doesn't work:
Hover from below/above image then hover out onto other image
UPDATE
Just to clarify a bit as I had an answer that got me the effect I wanted but didn't exactly solve the issue I was having exactly. I would like to know why the animation callbacks on complete don't properly work when hovering from one image to the other. This is the part that has been bugging me the most. When you hover on an image and then out it removes the class on hover then adds the class after the animation called from the hover out event finishes. This is the expected behaviour. When I hover over an image then onto the other image you will see that instead of adding the class to the first image on hover out, it adds it to the image you are current hovering. Its as if the animation callback is calling the wrong callback function once it animates up on hover.
The on hover state should never have the class added. It should be removed at this point. The class should also not be added during any of the animation states.
Just in case links aren't ok, here is the full html, css and javascript:
HTML
<div class="grid-container">
<div class="grid-item">
<a href="#" class="grid-inner">
<div class="grid-image">
<img src="http://vignette3.wikia.nocookie.net/metroid/images/8/86/Samus_artwork_11.jpg/revision/latest?cb=20100516174330" alt="">
</div>
<div class="grid-info hide-me">
<div class="middle-align">
<h4 class="grid-title">Some title</h4>
<div class="grid-details">
This is some info about this item
</div>
</div>
</div>
</a>
</div>
<div class="grid-item">
<a href="#" class="grid-inner">
<div class="grid-image">
<img src="http://vignette3.wikia.nocookie.net/metroid/images/8/86/Samus_artwork_11.jpg/revision/latest?cb=20100516174330" alt="">
</div>
<div class="grid-info hide-me">
<div class="middle-align">
<h4 class="grid-title">Some title</h4>
<div class="grid-details">
This is some info about this item
</div>
</div>
</div>
</a>
</div>
</div>
CSS
.grid-item {
width: 25%;
float: left;
overflow: hidden;
}
.grid-item img {
max-width: 100%;
height: auto;
}
.grid-inner {
position: relative;
display: block;
}
.grid-info {
position: absolute;
background: blue;
color: white;
width: 100%;
height: 100%;
}
.hide-me {
display: none;
}
.middle-align {
position: relative;
top: 50%;
-webkit-transform: translateY(-50%);
-ms-transform: translateY(-50%);
transform: translateY(-50%);
}
Javascript
$(document).ready(function() {
$('.grid-item').hover(hover_in, hover_out);
function hover_in(e) {
$info = $(e.currentTarget).find('.grid-info');
target_height = $(e.currentTarget).height();
$info.css('top', target_height).removeClass('hide-me');
$info.stop().animate({
'top': 0,
}, 500, function() {
console.log('animated up');
});
}
function hover_out(e) {
$info = $(e.currentTarget).find('.grid-info');
target_height = $(e.currentTarget).height();
$info.stop().animate({
'top': target_height,
}, 500, function() {
console.log('animated down');
$info.addClass('hide-me');
});
}
});
Try substituting using .show() after call to .stop() for .removeClass('hide-me') at hover_in
$(document).ready(function() {
$('.grid-item').hover(hover_in, hover_out);
function hover_in(e) {
$info = $(e.currentTarget).find('.grid-info');
target_height = $(e.currentTarget).height();
$info.css('top', target_height) //.removeClass('hide-me')
.stop()
.show()
.animate({
'top': 0,
}, 500, function() {
console.log('animated up');
});
}
function hover_out(e) {
$info = $(e.currentTarget).find('.grid-info');
target_height = $(e.currentTarget).height();
$info.stop().animate({
'top': target_height,
}, 500, function() {
console.log('animated down');
$info.addClass('hide-me');
});
}
});
.grid-item {
width: 25%;
float: left;
overflow: hidden;
}
.grid-item img {
max-width: 100%;
height: auto;
}
.grid-inner {
position: relative;
display: block;
}
.grid-info {
position: absolute;
background: blue;
color: white;
width: 100%;
height: 100%;
}
.hide-me {
display: none;
}
.middle-align {
position: relative;
top: 50%;
-webkit-transform: translateY(-50%);
-ms-transform: translateY(-50%);
transform: translateY(-50%);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<body>
<h1>Animation grid</h1>
<div class="grid-container">
<div class="grid-item">
<a href="#" class="grid-inner">
<div class="grid-image">
<img src="http://vignette3.wikia.nocookie.net/metroid/images/8/86/Samus_artwork_11.jpg/revision/latest?cb=20100516174330" alt="">
</div>
<div class="grid-info hide-me">
<div class="middle-align">
<h4 class="grid-title">Some title</h4>
<div class="grid-details">
This is some info about this item
</div>
</div>
</div>
</a>
</div>
<div class="grid-item">
<a href="#" class="grid-inner">
<div class="grid-image">
<img src="http://vignette3.wikia.nocookie.net/metroid/images/8/86/Samus_artwork_11.jpg/revision/latest?cb=20100516174330" alt="">
</div>
<div class="grid-info hide-me">
<div class="middle-align">
<h4 class="grid-title">Some title</h4>
<div class="grid-details">
This is some info about this item
</div>
</div>
</div>
</a>
</div>
</div>
</body>
jsfiddle https://jsfiddle.net/2k22yLmd/3/
Ok. So I figured it out. It turned out to be a scope issue. The problem stemmed from using e.currentTarget (or this) within the hover event scope. I stored that instance into a variable and then later used it in the callback of the animation sequence.
It appears that the current target changes from when the animation callback uses it giving me the unexpected results. For the animation callbacks I should have used the instance (this) within the scope of the animation callback function like so:
$info.stop().animate({
'top': target_height,
}, 500, function() {
console.log('animated down');
$(this).addClass('hide-me'); // this refers to the current animated object. This is the correct one.
$info.addClass('wrong-one'); // $info refers to the current hover event target which is the on hover item when it should be the hover off item. This is incorrect
});
You can test it out and see that going from one image to the next will now add the class hide-me to the correct one and add the class wrong-one to the currently hovered item which is not the expected behaviour I was looking for.
Thanks to everyone for pitching in on the answers and providing alternative solutions but this was real issue for me.

JS fade in not working correctly

I have searched for about 2 hours now and I just can't get a hold of this.
I am using bootstrap and I want to have three columns with "col-xs-6" placed next to each other. However, when I click the button, I want the outer column that is visible to collapse in and the column on the other side to show up. The blue column in the middle should not change at all, just the visibility of the outer columns.
I know I could just use display: none but this would not look as smooth as a CSS3 Transition.
The fade Out works perfectly fine, but instead of fading in, the div will just be at 50% width right after the display property has set.
Here is a fiddle:
Fiddle
And here is the Code:
HTML:
<div class="container-fluid">
<div class="row">
<div class="col-xs-6 red fadeIn">
Hello i am the red div
</div>
<div class="col-xs-6 blue">
Hello i am the blue div
</div>
<div class="col-xs-6 green fadeOut is-out">
Hello i am the green div
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div class="pull-right">
<button type="button" class="btn btn-danger">
<span class="glyphicon glyphicon-plus"></span> TOGGLE
</button>
</div>
</div>
</div>
</div>
JS:
$('.btn').click(function(){
var eleForFadeIn;
var eleForFadeOut;
if ($('.green').hasClass('is-out')){
eleForFadeIn = $('.green');
eleForFadeOut = $('.red');
}
else {
eleForFadeIn = $('.red');
eleForFadeOut = $('.green');
}
eleForFadeIn.addClass('fadeIn');
eleForFadeIn.removeClass('fadeOut');
eleForFadeOut.addClass('fadeOut');
eleForFadeOut.removeClass('fadeIn');
setTimeout(function() { doFadeIn(eleForFadeIn); }, 150);
setTimeout(function() { doFadeOut(eleForFadeOut); }, 1500);
});
function doFadeIn(element){
element.removeClass('is-out');
}
function doFadeOut(element){
element.addClass('is-out');
}
CSS:
.red{
background-color: red;
height: 250px;
-webkit-transition: width 2s;
transition: width 2s;
}
.blue{
background-color: blue;
height: 250px;
}
.green{
background-color: green;
height: 250px;
-webkit-transition: width 2s;
transition: width 2s;
}
.fadeOut{
width: 0px;
}
.fadeIn{
width: 50%;
}
.is-out{
display: none;
}
Thanks in Advance!
Edit: The timeout functions are used because i want the display property to be none at the end of the transition. Yes i tried to build in the transition eventlistener but it did not work... So if you know how to implement int i would appreciate any suggestions :-)
Edit2: Trying to express myself a bit more cleary about my goals.
display:none can't really be animated and that is where your problem lies. Change it to this and all should be well.
.is-out {
visibility: hidden;
padding: 0;
}
The JSFiddle you show doesn't produce three adjacent columns. Regardless, the reason the column takes up 50% of the width after the fade out is because it has the class col-xs-6. This class uses Bootstrap's grid system to size the element to 6/12 == 1/2 the available horizontal space.
If you want three adjacent columns, I suggest using col-xs-4 since 12/3 == 4. After fading out the outer two columns. You should adjust the class of the remaining one to be col-xs-12 instead of col-xs-4 so it will take up the entire horizontal width.

Categories