I have a div with a fixed position that is supposed to slide up/down on click. I'm trying to get this to work with a smooth CSS transition but it only jumps up/down when clicked. I'm probably missing something obvious here but can't figure out what.
Any ideas?
I've created a demo here.
My CSS:
.wrapper {
position: fixed;
bottom: 30px;
top: initial;
background: green;
width: 100%;
height: 20px;
-webkit-transition: all 1s ease;
-moz-transition: all 1s ease;
-o-transition: all 1s ease;
-ms-transition: all 1s ease;
transition: all 1s ease;
}
.wrapper.slide-up {
top: 0px;
bottom: initial;
}
.wrapper.slide-down {
top: auto;
bottom: 36px;
}
My JS:
var wrapper = $('.wrapper');
$(wrapper).click(
function () {
if (wrapper.hasClass('slide-up')) {
wrapper.addClass('slide-down').removeClass('slide-up');
} else {
wrapper.removeClass('slide-down').addClass('slide-up');
}
});
You can't use top and bottom interchangeably. You need to have one style you need to change.
For example:
.wrapper.slide-up {
top: 0px;
}
.wrapper.slide-down {
top: calc(100% - 36px);
}
JSFiddle
You can use the calc css function to work out exactly what you need.
top: calc(100% - 36px);
But you need to make sure that when you're doing transitions, you keep it to one element that you need to change. So top will give it the animation when you have two different top values, but when you introduce bottom when it's not set, it will just 'jump'.
Be careful when using calc() as it isn't fully supported in older browsers:
Can I use - Calc()
I think the reason is in moving from 0 to auto value. You must specify the numbers in both cases, see fiddle.
I changed CSS only: you can calculate the position in both classes based on top only
.wrapper.slide-up {
top: 0px;
}
.wrapper.slide-down {
top: calc(100% - 20px);
}
Maybe it won't work for your business case but for this example it does.
By the way 20px in calc(100% - 20px) is the height of the block.
Check this fiddle if it suit your needs: https://jsfiddle.net/8d19f59q/12/
top: calc(100vh - 20px - 36px);
this made the trick...
Related
Please can you help troubleshoot the transition in this CSS? My browser can see the code in the inspector but no transition is taking place. I have tried operating the transition on different properties including width and position but nothing works.
#header-image {
position: absolute;
top: 30px;
right: 30px;
background: transparent;
width: 250px;
margin-left: 10px;
opacity: 1;
transition: opacity 2s linear 1s;
}
I know I'm probably being thick so apologies in advance.
In order for the transition to work.. the property value should change. only then it will trigger the transition.
i.e) lets say #header-image initially has opacity: 0; width: 50px;.
but when you hover it you want to increase the opacity and width opacity: 1; width: 250px;
so your css will look like..
#header-image {
position: absolute;
top: 30px;
left: 30px;
background: blue;
width: 100px;
height: 100px;
margin-left: 10px;
animation: fadeIn 2s linear;
}
#keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
<div id="header-image"></div>
Then your transition will work. So basically transition will work only when there is a change in the value. But in your case you are setting the opacity:1 initially by default.
If you want to add this effect on page load then you have to use css animation or javascript. Below I have given an example snippet on how it can be achieved using css animation.
However if you are planning to use many animations then I recommend to use some popular libraries like Animista, Animate.css, wow.js
I'm working on this mobile menu where you can expand and collapse different categories. When doing so, a sliding animation should be performed on the expanded submenu (when expanding) or on the top-level menu (when collapsing).
The structure of the HTML is the following:
<div class="slideOpenMainMenu">
<div class="sideMenuGeneral">
...Top-level menu...
</div>
<div class="sideMenuPanelMainChildren">
...Expanded submenu...
</div>
</div>
By adding and removing classes, I show the appropriate div while hiding the other from view. As you'll notice, I go out of my way to not use anything like display:none; since then I won't be able to animate the containers. Instead I use a combination of width, height, visibility and flex properties to hide and show the containers.
/* Menu parent container */
.slideOpenMainMenu {
position: fixed;
width: 100%;
box-sizing: border-box;
background: linear-gradient(90deg, #12416e 0%, #0d3050 100%);
display: flex;
justify-content: center;
}
/* Top-level menu - Initial state */
.sideMenuGeneral {
width: 100%;
max-width: 620px;
display: flex;
flex-flow: column;
padding: 20px 16px 0 16px;
box-sizing: border-box;
overflow: hidden;
}
/* item submenu - Initial state */
.sideMenuPanelMainChildren {
width: 0;
height: 0;
flex: 0 1 0;
max-height: 100vh;
overflow: hidden;
visibility: hidden;
-webkit-overflow-scrolling: touch;
}
/* Top-level menu - Expanded state */
.slideOpenMainMenu.item-expanded .sideMenuGeneral {
width: 0%;
padding: 0 !important;
visibility: hidden;
}
.slideOpenMainMenu.item-expanded .sideMenuPanelMainChildren {
flex: 1 1 auto;
flex-flow: column;
width: 100%;
height: auto;
overflow: scroll;
visibility: visible;
}
For the animation, I use transform:translateY and opacity properties to create the sliding effect I want.
/* Initial state */
.slideOpenMainMenu .sideMenuPanelMainChildren {
opacity: 0;
transform: translateX(30%);
transition: opacity 0.5s ease, transform 0.5s ease, visibility 0s ease;
}
.slideOpenMainMenu .sideMenuGeneral {
opacity: 1;
transform: translateX(0%);
transition: opacity 0.5s ease, transform 0.5s ease, visibility 0s ease;
}
/* Expanded state */
.slideOpenMainMenu.item-expanded .sideMenuPanelMainChildren {
opacity: 1;
transform: translateX(0%);
}
.slideOpenMainMenu.item-expanded .sideMenuGeneral {
opacity: 0;
height: 0px;
transform: translateX(-50%);
}
As you can see on this fiddle, the animation works well in Chrome and Firefox. Not so well on Webkit and Edge. From what I can tell, there seems to be some kind of conflict between the change in width and the transitions, because when I disable changes in width, you can see the animation play out. What could cause the change in behavior between platforms? Is there a way to correctly sequence the changes?
So while writing this question, I arrived at the answer (as it often happens). The issue seems to be rooted in that the sequence of CSS property changes is different on different browsers. by adding a tiny delay (0.01s) to the transform transition I got it to work, like so:
transition: opacity 0.3s ease, transform 0.3s ease 0.01s, visibility 0s ease;
Still, I find this a little odd and also interesting. If anyone has info on how these things are sequenced in the browser that'd be really great to learn.
I have a parent div wrapped around a scaled child div. The child div starts off with transform:scale(0,0); & expands to transform:scale(1,1); when a button is clicked.
.content-wrapper {
display: inline-block;
background-color: #ddf;
padding: 10px;
clear: both;
}
.content {
padding: 10px;
background-color: #fff;
display: flex-block;
overflow: hidden;
transform:scale(0,0);
transform-origin:top;
transition:transform 1s ease-out;
}
.content.open {
transform:scale(1,1);
}
However the parent div content-wrapper stays at the same size of the child div content - even when the child is "closed".
The desired behaviour is when the child div is closed the parent div shrinks to only wrap around the button.
JSFiddle of Example
Is it possible to wrap the parent div around the child div when it's "closed" in this example?
This will be a little challenging because the background color is attached to the content container. I would remove the background color from the main container, then make it a separate div positioned absolute
<div class="content">
...
<div class="content-bg"> //contains your background color
then manipulate that based on your click handler.
I've updated the JSFiddle http://jsfiddle.net/ztxa5kwu/90/
CSS for the new div:
.content-bg{
position: absolute;
background-color: #ddf;
left: 0;
right: 0;
bottom: 0;
top: 0;
z-index: -1;
transition: all .5s ease;
transform-origin: bottom right;
}
Notice the transform-origin: bottom right; to scale the background towards your button. In the JSFiddle, I made the button take on a border the same color as the background, but you could easily edit the size of the new <div class="content-bg"></div> to fit around your button.
Hope that helps, and gets you in the right direction.
Try this:
.content {
background-color: #fff;
overflow: hidden;
transform:scale(0,0);
transform-origin:top;
transition:transform 1s ease-out;
display: block;
padding: 0;
height: 0; width: 0;
}
.content.open {
padding: 10px;
height: auto; width: auto;
transform: scale(1,1);
}
Edit: Play with this:
.content {
padding: 0;
background-color: #fff;
display: block;
overflow: hidden;
transform-origin:top;
transition: transform 1s ease-out, max-width 0.5s ease-out 0.4s, max-height 1s ease-out;
transform: scale(0,0); max-width: 0; max-height: 0;
}
.content.open {
padding: 10px;
transition: transform 1s ease-out, max-width 1s ease-out, max-height 8s ease-out;
transform: scale(1, 1); max-width: 1920px; max-height: 1080px;
}
I found this comment on an older question:
This method only partially achieves the desired effect but doesn't
actually remove the space. The transformed box acts like a
relatively positioned element - the space is taken up no matter how it
is scaled. Check out this jsFiddle which takes your first one and
just adds some bogus text at the bottom. Note how the text below it
doesn't move up when the box height is scaled to zero. – animuson♦ Jul
29 '13 at 20:37
So with that in mind I used the max-height/ max-width hack to get something close to what I was after: http://jsfiddle.net/BaronGrivet/ztxa5kwu/176/
.content {
padding: 10px;
background-color: #fff;
display: flex-block;
overflow: hidden;
transform:scale(0,0);
transform-origin:top;
transition:all 1s ease-out;
max-width: 0;
max-height: 0;
}
.content.open {
transform:scale(1,1);
max-width: 500px;
max-height: 500px;
}
I have a :before pseudo element displayed on :hover of a particular element.
I'm using font awesome and want to vertically center the content of the :before, but vertical align, margins etc haven't been of much help.
Any ideas?
.tile:before {
font-family: FontAwesome;
font-size: 150px;
color: white;
text-align: center;
border-radius: 15px;
opacity: 0;
z-index: 9999;
width: 100%;
height: 100%;
content: "\f16b";
position: absolute;
background-color: rgba(219,127,8, 0.7);
-webkit-transition: all 0.3s ease-in-out;
-moz-transition: all 0.3s ease-in-out;
-o-transition: all 0.3s ease-in-out;
-ms-transition: all 0.3s ease-in-out;
transition: all 0.3s ease-in-out;
}
.tile:hover:before {
opacity: 1;
}
Here are a few potential suggestions for .tile:before :
1 - use pixel value instead of 100% for height:
height: 100px;
2 - Make sure this is being displayed as an element that can ACCEPT margin, padding, etc.
display: block;
-or-
display: inline-block;
3 - I know you said you tried margins, but did you try padding-top?
padding-top: 20px;
4 - Try setting the overflow to hidden or visible. This often forces elements to behave "better."
overflow:hidden;
I would try all of these TOGETHER and see what happens.
Last, I might try setting a "top:" value since you have "position:absolute;" already. Maybe try this in conjunction with "position:relative;" too.
top: 10px;
Really need all the code (HTML) to tell what would work.
Using :before as the cover background to display on top of the tile element, and an :after with:
.tile:after {
top: 50%;
left: 50%;
/* Both half of font-size */
margin-left: -75px;
margin-top: -75px;
height: 150px;
line-height: 1;
}
Seemed to do the trick. Thanks all.
I am trying to animate/crossfade bg image using CSS3. I know that this works, but only in Chrome for now:
.image {
width: 100%;
height: 100%;
background-size: cover;
transition: background-image .5s ease-in;
background-image: url(../image.jpg);
}
.image:hover {
background-image:url(../image1.jpg;
}
In Chrome this works nicely, with seamless transition from one image to another. I know that I can animate background-position property using CSS3 keyframes and sprite image, but the problem is that I must use cover property. If I know exact dimensions of my holder div, then changing background position with keyframes works like a charm, but when adding background-size:cover in the mix, well, the only thing I can say that the results are not as expected.
Are there any workaround for this?
You can set the second image on a pseudo element, and just change the opacity of that to make the hover effect
.test {
position: relative;
width: 450px;
height: 300px;
background-image: url(http://placekitten.com/300/200);
background-size: cover;
}
.test:after {
content: "";
position: absolute;
top: 0px;
right: 0px;
bottom: 0px;
left: 0px;
background-image: url(http://placekitten.com/600/400);
background-size: cover;
-webkit-transition: opacity 1s;
-moz-transition: opacity 1s;
transition: opacity 1s;
opacity: 0;
}
.test:hover:after {
opacity: 1;
}
fiddle
By the way, this works cross-browser also