I'm implementing a toolbar using flex boxes and want optional sections to appear by smoothly sliding in from the left.
At the start, the bar should look as if the new element didn't exist, and at the end as if the animation never took place
Animating 0% { margin-left: -<width> } works exactly as intended, but only when the element's width is known at that point; I need it to work with width: auto (i.e. unset width) or other non-lengths like when flexing.
#keyframes appear {
0% { margin-left: -30ch; }
}
div.a {
width: 30ch; /* << should work without that */
flex: none; /* << stretch: should work with flex */
animation: appear 1s ease-in-out infinite alternate;
}
.root {
margin: 10px;
border: 1px solid black;
display: flex;
overflow: hidden;
}
.a, .b, .c {
box-sizing: border-box;
padding: 5px;
flex: 1;
}
.b { flex: 2 }
.a { background: #88f }
.b { background: #8d8 }
.c { background: #f88 }
<div class="root">
<div class="a">Some new stuff</div>
<div class="b">Hello</div>
<div class="c">World</div>
</div>
<div class="root">
<div class="a">Some longer content sliding in</div>
<div class="b">Hello</div>
<div class="c">World</div>
</div>
Width:auto; is not animatable. Use max-width:1000px; or something larger than the width will ever need to be. So the code would be:
width:auto;
max-width:1000px;
Related
I want to change my code so that the when my layout changes there is a sliding animation.
It is a 3 column layout and I want the left-most column to shrink a but when the user is focused on the right 2/3 of the screen.
I wrote a simple codepen demoing my code.
I am using JS to transition between two CSS classes, but I wanted to add an sliding transition to it.
I'm not sure if this should be 100% CSS or if I need to use some jQuery animation to get the desired effect.
Codepen: https://codepen.io/glennferrie/pen/vYaLpXo
const leftPane = document.getElementById('leftpane');
const centerPane = document.getElementById('centerpane');
const rightPane = document.getElementById('rightpane');
var addMode2 = function() {
leftPane.classList.add("mode-2");
rightPane.classList.add("mode-2");
centerPane.classList.add("mode-2");
}
var removeMode2 = function() {
leftPane.classList.remove("mode-2");
rightPane.classList.remove("mode-2");
centerPane.classList.remove("mode-2");
}
leftPane.addEventListener("mouseover", function(ev) {
removeMode2();
});
centerPane.addEventListener("mouseover", function(ev) {
addMode2();
});
rightPane.addEventListener("mouseover", function(ev) {
addMode2();
});
.container {
background-color: lightblue;
font-family: sans-serif;
font-size: 1.1em;
}
.left-pane,
.center-pane,
.right-pane {
padding-block-start: 10vh;
display: inline-block;
outline: dotted 2px #333;
height: 95vh;
text-align: center;
}
.left-pane {
width: 25vw;
background-color: yellow;
}
.center-pane {
width: 40vw;
}
.right-pane {
width: 33vw;
background-color: aquamarine;
}
.left-pane.mode-2 {
width: 10vw;
}
.center-pane.mode-2 {
width: 47vw;
}
.right-pane.mode-2 {
width: 40vw;
}
<div class="container">
<div class="left-pane" id="leftpane">
Left Pane Content
</div>
<div class="center-pane" id="centerpane">
Center Pane Content
</div>
<div class="right-pane" id="rightpane">
Right Pane Content
</div>
</div>
You can use a grid and animate the width of the columns. The solution below uses the has() pseudo-code which is not yet supported by Firefox.
* {
box-sizing: border-box;
}
.container {
background-color: lightblue;
font-family: sans-serif;
font-size: 1.1em;
display: grid;
/* Default setting equal width for all columns */
grid-template-columns: 2fr 2fr 2fr;
transition: grid-template-columns 0.5s ease-in-out;
}
.left-pane,
.center-pane,
.right-pane {
outline: dotted 2px #333;
height: 95vh;
text-align: center;
}
.left-pane {
background-color: yellow;
}
.right-pane {
background-color: aquamarine;
}
/* When center pane OR right pane is hovered, adjust the width of the columns of the parent */
.container:has(.center-pane:hover), .container:has(.right-pane:hover) {
grid-template-columns: 1fr 2.5fr 2.5fr;
}
<div class="container">
<div class="left-pane">
Left Pane Content
</div>
<div class="center-pane">
Center Pane Content
</div>
<div class="right-pane">
Right Pane Content
</div>
</div>
You can achieve that by adding transition property for your .left-pane, .center-pane, .right-pane elements inside CSS. It is best to have it for all three panes as they all change their width on hover.
Here's an example:
.left-pane, .center-pane, .right-pane {
padding-block-start: 10vh;
display: inline-block;
outline: dotted 2px #333;
height: 95vh;
text-align: center;
/* Transition for the width */
transition: 250ms width ease;
}
As you can see I added 3 properties for the transition.
First is time which defines how long will your animation take to complete. Second is property you want to animate, in your case it's width and the last one is the interpolator, by default it is set to linear which might be something you want but you can change it, I set it to ease to make effect more pleasing to the eyes.
You can read more about transition to learn about all the possibilities in the docs.
I would like to bring "Hello world" inside a white container from left to right but I don't want the container to move.
Need to move just text and the text flashes from left to right like a quick slider movement pleasing to the eye.
How to achieve this using CSS animation?
body {
background: red
}
.container {
background: white;
color: black;
padding: 20px;
margin: 20px;
}
<div class="container">
<h1>Hello world</h1>
</div>
for making the animation use #keyframes
and for making the text not visible if outside use overflow
forwards for saving the last keyframes of animation.
body {
background: red
}
.container {
background: white;
color: black;
padding: 20px;
margin: 20px;
}
.container {
overflow: auto; /* use "hidden" instead if it shows a unnecessary scrollbar. */
}
h1 {
animation: toRight 0.2s ease-in forwards;
transform: translateX(-50%);
}
#keyframes toRight {
100% {
transform: translateX(0);
}
}
<div class="container">
<h1>Hello world</h1>
</div>
So here is my code...
I understand how to make the text disappear by making it transparent but i want it to stay gone after hovering over it so it doesnt come back - how do I accomplish this?
.disappear {
margin-top: 60px;
text-align: center;
transition: all 5s ease .3s;
font-family: Bungee Spice;
}
.disappear:hover {
color: transparent;
}
you need to use onmouseover and remove() like this
function bye() {
const dis = document.getElementById("dis");
dis.remove();
}
* {
padding: 0;
margin: 0;
/* border: 1px solid red; */
overflow-x: hidden;
}
div {
height: 50vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
font-size: xx-large;
overflow: auto;
background: lightblue;
}
<div class="div">
<h2 onmouseover="bye()" id="dis">will go on hover</h2>
</div>
I don't think it's possible to make it run smoothly with pure CSS, so far, this is what I think is close to what you want to accomplish. So before hover, the animation to make it gone is already set, but the animation is not running yet, the animation will run only if the element is hovered. The problem here is that when it's hovered then it's unhovered before it's gone, the element will be half gone as the animation is paused.
.container {
width: 100%;
height: 800px;
background: #dddddd;
}
.disappear {
margin-top: 60px;
text-align: center;
font-family: Bungee Spice;
background: yellow;
animation: example 5s linear forwards;
animation-play-state: paused;
}
.disappear:hover {
animation-play-state: running;
}
#keyframes example {
from {opacity: 1}
to {opacity: 0}
}
<div class="container">
not disappear
<div class="disappear">
DISAPPEAR
</div>
</div>
The better way would be to use javascript and use onmouseover to add the animation instead of using :hover, the difference is that when you onmouseout, the function is still executed (the animation persists). This is with JS:
function fade(elm) {
elm.style.animation = "example 5s linear forwards";
}
.container {
width: 100%;
height: 800px;
background: #dddddd;
}
.disappear {
margin-top: 60px;
text-align: center;
font-family: Bungee Spice;
background: yellow;
}
#keyframes example {
from {
opacity: 1
}
to {
opacity: 0
}
}
<div class="container">
not disappear
<div class="disappear" onmouseover="fade(this)">
DISAPPEAR
</div>
</div>
I have tried many different setups, including snap to the page, and sticky with motion effect and I cannot seem to replicate this well at all. I would love to achieve the section to "stick" only once reached and then the content inside to have motion effect of the scroll and once content is done, remove sticky to resume page. The effect I am looking for is very much this effect on this page https://eiger-extreme.mammut.com/en/technology (the blue section) I have done a short screencast of the effect https://www.screencast.com/t/c8P1xsWOfx9q. I'm happy to even use plugins for elementor if needed
Looks like the left "sticky" section is just a lot of li-elements stacked on top of eachother? E.g. a very high ul-list. Sorry if I'm totally off here, but you can probably create elements that takes up 100vh (or more) in left column, and then make right section sticky? The animation (fade text in and out, changing right column background-image, and change the graphics in right column) could be done with javascript. This is not a good final approach, but it'll maybe give you some sort of help:
// Just a simple scroll-animation that add class to change bg (not implemented to revert bg when scrolling up again)
document.addEventListener('scroll', function(e) {
const heading1 = document.querySelector(".heading1").getBoundingClientRect();
const heading2 = document.querySelector(".heading2").getBoundingClientRect();
const heading3 = document.querySelector(".heading3").getBoundingClientRect();
const heading4 = document.querySelector(".heading4").getBoundingClientRect();
if (heading1.top <= 0 && heading1.top > -100) {
document.querySelector(".s2c2").classList.add("heading1bg");
} else if (heading2.top <= 0 && heading2.top > -100) {
document.querySelector(".s2c2").classList.add("heading2bg");
} else if (heading3.top <= 0 && heading3.top > -100) {
document.querySelector(".s2c2").classList.add("heading3bg");
}
});
body {
margin: 0;
color: white;
}
.s1 {
background-color: red;
padding: 30px;
height: 100vh;
}
.s2 {
display: flex;
flex-direction: row;
}
.s2c1 {
background-color: blue;
flex: 1 0 50%;
padding: 30px;
}
.s2c1 > div {
margin: 50vh auto;
text-align: center;
font-size: 30px;
font-weight: bold;
}
.s2c2 {
background-color: green;
flex: 1 0 50%;
padding: 30px;
}
.s2c2 > div {
position: -webkit-sticky;
position: sticky;
margin: 50% 0;
top: 50%;
text-align: center;
}
.s3 {
background-color: cadetblue;
padding: 30px;
height: 100vh;
}
.heading1bg {
background-color: chocolate;
transition: background-color 200ms linear;
}
.heading2bg {
background-color: purple;
transition: background-color 200ms linear;
}
.heading3bg {
background-color: orange;
transition: background-color 200ms linear;
}
<div class="container">
<div class="s1">First section</div>
<div class="s2">
<div class="s2c1">
<div class="heading1">Heading 1</div>
<div class="heading2">Heading 2</div>
<div class="heading3">Heading 3</div>
<div class="heading4">Heading 4</div>
</div>
<div class="s2c2">
<div>Fixed graphic</div>
</div>
</div>
<div class="s3">Last section</div>
</div>
Run code snippet in full page for best view
I've been asked to take a pure CSS3 loading spinner and make it dynamically resizable by pixels to use in different places in a program.
My current code is: (Which apparently doesn't run well in SO's snippets)
.loader {
animation:spin 1s infinite linear;
border:solid 2vmin transparent;
border-radius:50%;
border-right-color:#71c491;
border-top-color:#f7941d;
box-sizing:border-box;
height:20vmin;
left:calc(50% - 10vmin);
position:fixed;
top:calc(50% - 10vmin);
width:20vmin;
z-index:1;
&:before {
animation:spin 2s infinite linear;
border:solid 2vmin transparent;
border-radius:50%;
border-right-color:#21409a;
border-top-color:#92278f;
box-sizing:border-box;
content:"";
height:16vmin;
left:0;
position:absolute;
top:0;
width:16vmin;
}
&:after {
animation:spin 3s infinite linear;
border:solid 2vmin transparent;
border-radius:50%;
border-right-color:#13b0e6;
border-top-color:#18244c;
box-sizing:border-box;
content:"";
height:12vmin;
left:2vmin;
position:absolute;
top:2vmin;
width:12vmin;
}
}
#keyframes spin {
100% {
transform:rotate(360deg);
}
}
<div class="loader"></div>
I googled and tried transform:scale() but as far as I can tell that only takes specific input and increases/decreases the size by percentage. (2 = 200% size)
I'm thinking I need some sort of wrapper, but I'm not too familiar with advanced CSS to get the effect. When I tried to create my own, only the top border of the spinner would be resized into a weird shape and not the inner borders. I'm just stumped. If you could point me in the right direction, I'd be appreciative. Thank you.
You could try a mix of CSS var() / calc() / clamp() / grid ... and relative/absolute positionning to lay the loader over the parent where you need it , if that inspire you :
demo with a few loader within a div sized and the possibility to set an average size to start from, % size based on the width of the parent.
value to reset in the demo is --size ; you may also tune the other --MyVarCss values to your needs.
* {
box-sizing: border-box;
}
:root { /* init for the var() values */
--size: 20;/* value used to set the loader's width and adjust border's width */
--width: calc(var(--size) * 1%);
--widthBorder: calc( clamp(20px, 6vw, 80px) * var(--size) * 0.005);
}
.a,/* for the demo , just a bunch of containers */
.b,
.c,
.d,
.d,
.e {
position: relative;
/* what the parent loader needs to be (absolute/fixed/sticky works too, static not) */
float: left;
border: solid;
margin: 1em;
}
div.a {
--size: 50; /* reset the value used to set the loader's width */
width: 50%;
padding-top: 50%;
}
.b {
--size: 10;/* reset the value used to set the loader's width */
width: 600px;
height: 200px;
}
.c {
--size: 15;/* reset the value used to set the loader's width */
width: 25%;
padding-top: 20%;
}
.d {
--size: 30;/* reset the value used to set the loader's width */
width: 800px;
height: 400px;
}
.e {
--size: 14;/* reset the value used to set the loader's width */
width: 90%;
min-height: 20vh;
}
div {
width: 20%;
padding-top: 20%;
}
/* loader styles */
.loader {
position: absolute;
top: 0;
left: 0;
display: flex;
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
.loader b {
display: grid;
animation: rotate 3s -1s infinite linear;
border: solid var(--widthBorder) transparent;
padding: calc(var(--widthBorder) / 2);
border-radius: 50%;
border-right-color: #71c491;
border-top-color: #f7941d;
grid-row: 1;
grid-column: 1;
margin: 0;
}
.loader>b {
margin: auto;
width: var(--width);
}
.loader>b:before {
content: "";
padding-top: 100%;
grid-row: 1;
grid-column: 1;
}
.loader b b {
border-right-color: #21409a;
border-top-color: #92278f;
}
.loader b b b {
border-right-color: #13b0e6;
border-top-color: #18244c;
padding: 0;
}
#keyframes rotate {
100% {
transform: rotate(360deg);
}
}
<div class=a>
<div class="loader"><b><b><b></b></b>
</b>
</div>
</div>
<div class=b>
<div class="loader"><b><b><b></b></b>
</b>
</div>
</div>
<div class=c>
<div class="loader"><b><b><b></b></b>
</b>
</div>
</div>
<div class=d>
<div class="loader"><b><b><b></b></b>
</b>
</div>
</div>
<div class=e>
<div class="loader"><b><b><b></b></b>
</b>
</div>
</div>