How to implement CSS animations based on media-query breakpoints being hit? - css

As part of making our websystem responsive to mobile devices, I'm using CSS media queries to alternate between having a header bar and a hamburger menu.
Now I thought it'd be a nice gimmick if it animated between the two layouts when desktop users adjusted the size of their browser window beyond the bounds defined by the media queries. As a proof-of-concept test I've been experimenting with the transition between our large logo and the small one.
My animations.scss file contains these two animations:
#mixin ToSmallLogo() {
background-image: url('../../../../PageAssets/fissmall.png');
width: 7%;
animation-iteration-count: 1;
animation-timing-function: ease-in;
animation-duration: 1s;
animation-name: SwapToSmallLogo;
#keyframes SwapToSmallLogo {
0% {
width: 100%;
background-image: url('../../../PageAssets/Fis.png');
}
100% {
background-image: url('../../../../PageAssets/fissmall.png');
width: 7%;
}
}
}
#mixin SwapToBigLogo() {
width: 100%;
background-image: url('../../../PageAssets/Fis.png');
animation-iteration-count: 1;
animation-timing-function: ease-in;
animation-duration: 1s;
animation-name: SwapToBigLogo;
#keyframes SwapToBigLogo {
0% {
background-image: url('../../../../PageAssets/fissmall.png');
width: 7%;
width: 100%;
background-image: url('../../../PageAssets/Fis.png');
}
100% {
width: 100%;
background-image: url('../../../PageAssets/Fis.png');
}
}
}
Then I've got a SCSS file specifically for the media queries, containing:
#import '../../Variables/Sizes.scss';
#import '../Animations/animations.scss';
#media screen and (max-width: $bigToSmallFISLogo) {
#franklin {
#include ToSmallLogo();
}
}
#media screen and (min-width: $bigToSmallFISLogo){
#franklin{
#include SwapToBigLogo();
}
}
While the CSS before application of the media queries is this:
#franklin {
display: block;
width: 100%;
background-image: url('../../../PageAssets/Fis.png');
background-repeat: no-repeat;
background-size: 100%;
height: 72px;
}
My issue is, while shrinking the screen past the defined size works perfectly, going back up just snaps to the larger image with no animation. I'd thought that the culprit was that I had the image defined in the CSS before application of the media queries, so I removed that part of it; but that just resulted in having no image.
Then while typing this question I had the idea use a media query to determine the direction of the animation, like so:
#mixin SwapLogo() {
/* background-image: url('../../../../PageAssets/fissmall.png');
width: 7%;*/
animation-iteration-count: 1;
animation-timing-function: ease-in;
animation-duration: 1s;
animation-name: SwapLogo;
#media screen and (max-width: $bigToSmallFISLogo) {
animation-direction: normal;
background-image: url('../../../../PageAssets/fissmall.png');
width: 7%;
}
#media screen and (min-width: $bigToSmallFISLogo) {
animation-direction: reverse;
width: 100%;
background-image: url('../../../PageAssets/Fis.png');
}
#keyframes SwapLogo {
0% {
width: 100%;
background-image: url('../../../PageAssets/Fis.png');
}
100% {
background-image: url('../../../../PageAssets/fissmall.png');
width: 7%;
}
}
}
That resulted in the animation being ran on page load, but not at the resize.
Is there any way to do what I'm looking for?

Option 1 contains some faulty css
You've set the starting to width: 100%; on your SwapToBigLogo
#keyframes SwapToBigLogo {
0% {
background-image: url('../../../../PageAssets/fissmall.png');
width: 7%;
width: 100%; <---- culprit
background-image: url('../../../PageAssets/Fis.png');
}
Essentially, you're animation from width: 100% to width:100%. If you remove that line, it will probably work.
Option 2 tricky with reversing
When you reverse an animation, it will not reset iteration count and progress of the animation.
IE if you 'reverse' an animation at 100% finished. it will just apply the 100% finished of the 'reverse' state. not start from 0% reverse and animate to 100% reversed
see my answer to this question if you want to circumvent that
Alternative, use Transitions instead
If you have no need for complex animations and just want to smoothly transition from one state to another.
I would prefer to use css transitions.
#franklin {
display: block;
width: 100%;
background-image: url('../../../PageAssets/Fis.png');
background-repeat: no-repeat;
background-size: 100%;
height: 72px;
transition: width 2s ease-in; // <--- this will animate when the media query kicks in.
}
#media screen and (max-width: $bigToSmallFISLogo) {
#franklin {
background-image: url('../../../../PageAssets/fissmall.png');
width: 7%;
}
}
#media screen and (min-width: $bigToSmallFISLogo){
#franklin{
width: 100%;
background-image: url('../../../PageAssets/Fis.png');
}
}
Bonus
You can apply transitions to a * selector. (I would not recommend that for production grade websites, but it's fun to toy with.) It will cause everything to smoothly transition when your media query changes widths/layouts.
* {
transition: all 2s;
}
body {
background-color: red;
color: black;
font-size: 30px;
}
.logo {
width: 200px;
border: 5px solid black;
border-radius: 30px;
padding:20px;
}
/* On screens that are 992px wide or less, the background color is blue */
#media screen and (max-width: 630px) {
body {
background-color: blue;
color: white;
font-size: 20px;
}
.logo {
width: 100px;
border: 3px solid orange;
border-radius: 10px;
padding:10px;
}
}
/* On screens that are 600px wide or less, the background color is olive */
#media screen and (max-width: 400px) {
body {
background-color: lime;
color: white;
font-size: 12px;
}
.logo {
width: 50px;
border: 1px solid indigo;
border-radius: 5px;
padding:2px;
}
}
<h1>Resize window</h1>
<p>
<img class="logo" src="http://placekitten.com/200/300" alt="logo">
</p>

After a lot of experimentation, I've finally sussed it out. Essentially, as Lars pointed out, I'd forgotten to delete a couple of bits; but the solution I ended up with (which seems a bit smoother, as it fades one image into the other) is to have the base CSS as:
#franklin {
display: block;
background-repeat: no-repeat;
background-size: 100%;
height: 72px;
}
Then the mixin to apply the animation as follows:
#mixin SwapLogo($img, $width, $startIMG, $startWidth, $animationName) {
animation-iteration-count: 1;
animation-timing-function: ease-in;
animation-duration: 1s;
animation-name: $animationName;
background-image: $img;
width: $width;
#keyframes #{$animationName} {
0% {
width: $startWidth;
background-image: $startIMG;
}
100% {
background-image: $img;
width: $width;
}
}
}
With the media queries being:
#media screen and (max-width: calc($bigToSmallFISLogo + 10px)) { //This overlap of 10px basically allows for the animation to take effect as the other animation is removed.
#franklin {
#include SwapLogo(url('../../../../PageAssets/fissmall.png'), 7%, url('../../../../PageAssets/Fis.png'), 100%, LogoGoSmall);
margin-top: 13px;
}
}
#media screen and (min-width: $bigToSmallFISLogo) {
#franklin {
#include SwapLogo(url('../../../../PageAssets/Fis.png'), 100%, url('../../../../PageAssets/fissmall.png'), 7%, LogoGoBig);
}
}
#media screen and (max-width: $minSizeForDesktopMenu) and (min-width: $bigToSmallFISLogo) {
#franklin {
margin-top: 26px;
}
}
#media screen and (min-width: $minSizeForDesktopMenu) {
#franklin {
margin-top: 13px;
}
}

Related

CSS animations default to slow fade in-out, is there a way to change that?

New to using CSS animations. Created an animation with 8 pictures for a total animation-duration 100sec. Using keyframes percentages I have the first 6 frames 10sec, 7th frame 30sec, last frame 10sec specifying the pictures using a background-image url. When implemented the pictures fade-in and fade-out very slowly barely accomplishing that in the 10sec time of the frame. The W3schools website I'm learning this from doesn't give any option to speed the fades up or specify a different type of slide transition. I'm not finding answers to this anywhere else on the web. Am I missing something? See code below:
.homeslider {
width: 950px;
height: 400px;
padding-left: 25px;
animation-name: homepics;
animation-duration: 100s;
}
#keyframes homepics {
0% { background-image: url('images/pic1.png'); }
10% { background-image: url('images/pic2.png'); }
20% { background-image: url('images/pic3.png'); }
30% { background-image: url('images/pic4.png'); }
40% { background-image: url('images/pic5.png'); }
50% { background-image: url('images/pic6.png'); }
80% { background-image: url('images/pic7.png'); }
90% { background-image: url('images/pic8.png'); }
}
<div class="homeslider"></div>
background-image is an animatable property so you are getting fading in and out of the images throughout the sequence - at no point does an image 'stay still' with full opacity.
This snippet takes a rather simplistic approach to minimising the transition time between background images - showing an image for nearly 10% in the case of the first few, then transitioning to the next image very quickly.
There are drawbacks to this method - the system doesn't look forward to bring in background images until they are needed, so the first time through there can be quite a flashy gap as it loads the next image. [A 'fix' of running the animation once, potentially out of sight, very quicly to get images loaded in advance has been removed as it didn't seem to be what was wanted].
.homeslider {
width: 950px;
height: 400px;
padding-left: 25px;
animation-name: homepics;
animation-duration: 100s;
animation-iteration-count: 1;
animation-fill-mode: forwards;
background-repeat: no-repeat;
background-size: cover;
background-position: center;
}
#keyframes homepics {
0%,
9.9999% {
background-image: url(https://picsum.photos/id/1015/200/300);
}
10%,
19.9999% {
background-image: url(https://picsum.photos/id/1016/200/300);
}
20%,
29.9999% {
background-image: url(https://picsum.photos/id/1018/200/300);
}
30%,
39.9999% {
background-image: url(https://picsum.photos/id/1019/200/300);
}
40%,
49.9999% {
background-image: url(https://picsum.photos/id/1020/200/300);
}
50%,
79.999% {
background-image: url(https://picsum.photos/id/1021/200/300);
}
80%,
89.999% {
background-image: url(https://picsum.photos/id/1022/200/300);
}
90%,
100% {
background-image: url(https://picsum.photos/id/1023/200/300);
}
}
<div class="homeslider"></div>
There are many other ways of simulating an image slider using pure HTML/CSS - for example having all the images stacked on top of each other and 'moving them' with z-index, or playing with opacities.
In order to illustrate your issue on the site, I created a snippet using background colors instead of images:
.homeslider {
width: 950px;
height: 400px;
padding-left: 25px;
animation-name: homepics;
animation-duration: 100s;
}
#keyframes homepics {
0% { background-color: red; }
10% { background-color: orange; }
20% { background-color: yellow; }
30% { background-color: green; }
40% { background-color: blue; }
50% { background-color: indigo; }
80% { background-color: violet; }
90% { background-color: purple; }
}
<div class="homeslider"></div>
In the below example, I think I resolved your issue by adding additional keyframes right before the threshold of the next change, so that the transition doesn't occur until the last possible moment:
.homeslider {
width: 950px;
height: 400px;
padding-left: 25px;
animation-name: homepics;
animation-duration: 100s;
}
#keyframes homepics {
0% { background-color: red; }
9% { background-color: red; }
10% { background-color: orange; }
19% { background-color: orange; }
20% { background-color: yellow; }
29% { background-color: yellow; }
30% { background-color: green; }
39% { background-color: green; }
40% { background-color: blue; }
49% { background-color: blue; }
50% { background-color: indigo; }
79% { background-color: indigo; }
80% { background-color: violet; }
89% { background-color: violet; }
90% { background-color: purple; }
99% { background-color: purple; }
}
<div class="homeslider"></div>

Responsive background scrolling with constant speed

I want to use a responsive div with a scrolling background image.
In the example I showed it small and large. I want the entire scroll to be constant - so the small div should take x seconds and the large div should also take x seconds (rather than the small one taking less time to complete a whole image pan than the larger one).
I've tried using percentage values in background-position-x but it stops the animation.
.offset {
background-image: url('https://upload.wikimedia.org/wikipedia/commons/c/c4/PM5544_with_non-PAL_signals.png');
background-size: 100%;
animation: slideLeft768px 5s linear infinite;
}
.div1 {
width: 76.8px;
height: 57.6px;
}
.div2 {
width: 768px;
height: 576px;
}
#keyframes slideLeft768px {
0% {
background-position-x: 768px;
}
100% {
background-position-x: 0px;
}
}
<div class="offset div1"></div>
<div class="offset div2"></div>
====================
This is based on Temani Afif's answer:
.offset {
background-image: url('https://upload.wikimedia.org/wikipedia/commons/c/c4/PM5544_with_non-PAL_signals.png');
background-size: 100%;
animation: slideLeft 5s linear infinite;
width: var(--p);
--p: 40vw;
height: 30vw;
}
.div1 {
--p: 12vw;
height: 9vw;
}
#keyframes slideLeft {
0% {
background-position-x: var(--p);
}
100% {
background-position-x: 0px;
}
}
<div class="offset div1"></div>
<div class="offset div2"></div>
I made it only use responsive units so it adjusts when you resize the window.
You can consider CSS variable to make the animation dynamic:
.offset {
background-image: url('https://upload.wikimedia.org/wikipedia/commons/c/c4/PM5544_with_non-PAL_signals.png');
background-size: 100%;
animation: slideLeft768px 5s linear infinite;
width: var(--p);
}
.div1 {
--p: 76.8px;
height: 57.6px;
}
.div2 {
--p:768px;
height: 576px;
}
#keyframes slideLeft768px {
0% {
background-position: var(--p,0px) 0px;
}
100% {
background-position: 0px 0px;
}
}
<div class="offset div1"></div>
<div class="offset div2"></div>
And since your are using the same image with known dimension you can optimize your code like below:
.offset {
background-image: url('https://upload.wikimedia.org/wikipedia/commons/c/c4/PM5544_with_non-PAL_signals.png');
background-size: 100%;
animation: slideLeft768px 5s linear infinite;
width: calc(768px * var(--p,1));
height: calc(576px * var(--p,1));
}
.div1 {
--p: 0.1;
}
.div2 {
--p:0.2;
}
#keyframes slideLeft768px {
0% {
background-position: calc(768px * var(--p,1)) 0px;
}
100% {
background-position: 0px 0px;
}
}
<div class="offset div1"></div>
<div class="offset div2"></div>
<div class="offset" style="--p:0.8"></div>
You can also check this answer (https://stackoverflow.com/a/51734530/8620333) to understand why percentage value won't work and how to make it working.
The trick is to use a percentage for the background-position. Since setting the background-size to 100% makes this impossible, we need to set it to another value.
A trick is to use the padding for this. Create a padding right the same dimension than the width. Making the background origin the paddin box, and clip tghe content box, now we can set the size to 50%. Visually, nothing will change. (In case that the extra padding is a problem, you could set a negative margin or a clip-path). And now, the background-position can be moved in percentages:
.offset {
background-image: url('https://upload.wikimedia.org/wikipedia/commons/c/c4/PM5544_with_non-PAL_signals.png');
background-size: 50%;
background-origin: border-box;
background-clip: content-box;
animation: slideLeft768px 5s linear infinite;
}
.div1 {
width: 76.8px;
padding-right: 76.8px;
height: 57.6px;
}
.div2 {
width: 768px;
padding-right: 768px;
height: 576px;
}
#keyframes slideLeft768px {
0% {
background-position-x: 100%;
}
100% {
background-position-x: 0%;
}
}
<div class="offset div1"></div>
<div class="offset div2"></div>

Fade in Image on load using transition

Im a designer so excuse me if my question is simple
I need the background image to fade in when the page loads.
this code was done by a template, so i need to change this background to fade in, because the entire page is already fade in with a plugin on wordpress.
I have this code:
body {
background-position: 100% 60px;
background-repeat: no-repeat;
transition: background-position 700ms cubic-bezier(0.23, 1, 0.32, 1);
}
#media(min-width: 1025px) {
body {
background-image: url(/wp-content/uploads/2018/08/girl-banner-desktop.png);
background-size: 552px 616px;
}
body.load-done:not(.menu-open) {
background-position: 100% 60px;
}
}
#media(max-width: 1024px) and (min-width: 768px) {
body.load-done {
background-image: url(/wp-content/uploads/2018/08/girl-banner-tablet.png);
background-size: 351px 327px;
}
body.load-done:not(.menu-open) {
background-position: 100% 60px;
}
}
#media(max-width: 767px) {
body.load-done {
background-image: url(/wp-content/uploads/2018/08/girl-banner-mobile.png);
background-size: 264px 268px;
background-position: 100% 340px;
}
selector {
height: 397px;
}
}
#keyframes fadeInOpacity {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}

Making pure css image slider responsive

The following pure css slider is working well, but I need to make it responsive. I've tried replacing the pixel-based sizes with percentages and with vw, but it doesn't line up. I'd be grateful for any ideas.
Here's the html:
<section class="slideshow">
<div class="slideshow-container slide">
<img src="images/anim/home-animation1.jpg" alt="pills">
<img src="images/anim/home-animation2.jpg" alt="scientist">
<img src="images/anim/home-animation3.jpg" alt="chemical structure">
<img src="images/anim/proudmembermassbio.jpg" alt="proud member of MassBio"> </div>
</section>
And the css:
/*general styles*/
html { box-sizing: border-box; }
*, *:before, *:after { box-sizing: inherit; }
/* SLIDESHOW STYLES */
.slideshow-container {
width: 1400px; /* the entire "stage" */
font-size: 0;
transition: 1s ease;
height: 315px;
}
.slideshow-container:hover { animation-play-state: paused; }
.slideshow { /* the visible "stage" */
width: 350px;
margin: 1rem auto -1rem;
overflow: hidden;
border: solid 1px white;
}
img, .text-container {
width: 350px;
height: auto;
display: inline-block;
font-size: 16px;
text-align: center;
}
.text-container { /* for text slides */
height: 195px;
position: relative;
}
.slide { animation: slide 10s ease infinite; }
#keyframes slide {
0% { transform: translateX(0%); }
12.5% { transform: translateX(0%); }
25% { transform: translateX(-25%); }
37.5% { transform: translateX(-25%); }
50% { transform: translateX(-50%); }
62.5% { transform: translateX(-50%); }
75% { transform: translateX(-75%); }
87.5% { transform: translateX(-75%); }
99% { transform: translateX(-75%); }
100% { transform: translateX(0); }
}
.p {
margin-top: 140px;
text-align: center;
}
Maybe this is too late for the user that posted this question, but can be helpful for someone else that want a pure responsive CSS slider.
I have created a working example in this CodePen that is working as requested using percentages for widths and in the animation, and for this reason it is responsive and works really well in each resolutions.
All the main solution to have the responsiveness is here:
slider__container {
display: flex;
position: relative;
animation: 30s slide infinite;
font-size: 0;
width: 1000%; /* because I am using 10 slides */
}
The width should be calculated accordingly to how many slides are there in the slider: slides x 100% (slides times 100%, in my example 1000%).

Safari not rerendering keyframes on window resize

I'm using CSS3 to translate and fade in an element to different locations depending on two different screen widths with #media queries. It works exactly as I expect it to in both the latest Chrome and Firefox. The problem comes with Safari 10. When the window is resized, regardless of whether the #media query is triggered again, the 100% keyframe is not rerendered. The div with the "animate-div" class stays right where it last translated to in a fixed position from the initial page load. Here's a snippet of what I'm talking about. Thanks!
And yes, I have a viewport HTML tag in the head.
.animate-div {
opacity: 0;
animation: divIn 2800ms forwards ease-in-out;
}
#media only screen and (min-width: 768px) {
#keyframes divIn {
0% {
height: 12vw;
width: 12vw;
opacity: 0;
transform: translate(44vw, calc(50vh - 6vw));
}
50% {
height: 16vw;
width: 16vw;
opacity: 1;
transform: translate(42vw, calc(50vh - 8vw));
}
100% {
height: 17vw;
width: 17vw;
opacity: 1;
transform: translate(2vw, 2vw);
margin-bottom: 3vw;
}
}
}
#media only screen and (max-width: 768px) {
#keyframes divIn {
0% {
height: 26vw;
width: 26vw;
opacity: 0;
transform: translate(37vw, calc(50vh - 13vw));
}
50% {
height: 30vw;
width: 30vw;
opacity: 1;
transform: translate(35vw, calc(50vh - 15vw));
}
100% {
height: 30vw;
width: 30vw;
opacity: 1;
transform: translate(35vw, 1vw);
margin-bottom: 2vw;
}
}
}

Resources