CSS Transition Direction - Can It Always Be The Same? - javascript

Here is an example: https://codepen.io/jon424/pen/XWzGNLe
I have a button here that lets you toggle the visibility of an image. When the button is clicked, the image disappears from the bottom to the top. When you click the button again, the image reappears from the top to the bottom.
I would like the transition to move in the same direction each time. So, when the user sees the image and clicks on the button, the image disappears from the bottom to the top. When the user clicks the button again, the image reappears from the bottom to the top.
Is there a way to use transitions without this kind of “alternating” activity?
HTML
<button>Toggle</button>
<div class="parent">
<img class="child1" src="https://picsum.photos/200/300">
<div class="child1 covering"></div>
</div>
CSS
.parent {
position: relative;
overflow: hidden;
width: 300px;
height: 300px;
margin: 10px;
}
.child {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
.covering {
z-index: 1;
background: #fff;
transition: transform 1s ease-in-out;
transform: translateY(100%);
}
.covered {
transform: translateY(0%);
}
JS
const firstTarget = document.querySelector(".firstTarget");
const covering = document.querySelector(".covering");
document.querySelector('button').addEventListener('click', () => { document.querySelector('.covering').classList.toggle('covered');});

You can use keyframes for this, or listen to transitionend.
const btn = document.querySelector('button'),
cover = document.querySelector('.cover');
btn.addEventListener('click', ()=> {
if(cover.classList.contains('covered')){
cover.classList.add('remove_covered');
} else {
cover.classList.add('covered');
}
cover.ontransitionend = () => {
if(cover.classList.contains('remove_covered'))
cover.classList.remove('covered','remove_covered');
};
});
.child {
width: 300px;
height: 300px;
}
.parent {
position: relative;
width: 300px;
height: 300px;
}
.cover {
position: absolute;
bottom: 0;
left: 0;
height: 0;
width: 100%;
background: #fff;
transition: height 1s ease-in-out;
}
.covered {
height: 100%;
}
.remove_covered {
top: 0;
bottom: auto;
height: 0;
}
<button>Toggle</button>
<div class="parent">
<img class="child" src="https://picsum.photos/200/300">
<div class="cover"></div>
</div>

Is that what you want?
const targetClassList = document.querySelector(".image-item").classList;
document.querySelector("button").addEventListener("click", () => {
if (targetClassList.contains("open")) {
targetClassList.remove("open");
targetClassList.add("close");
} else {
targetClassList.add("open");
targetClassList.remove("close");
}
});
.parent {
position: relative;
overflow: hidden;
width: 300px;
height: 300px;
margin: 10px;
}
.child {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
.image-item {
z-index: 1;
background: #fff;
}
.close {
animation: closeAni 1s forwards;
}
.open {
animation: openAni 1s forwards;
}
#keyframes openAni {
from {
transform: translateY(0);
}
to {
transform: translateY(-100%);
}
}
#keyframes closeAni {
from {
transform: translateY(100%);
}
to {
transform: translateY(0);
}
}
<button>Toggle</button>
<div class="parent">
<img class="child" src="https://picsum.photos/200/300">
<div class="child image-item"></div>
</div>

Related

How to animate image from fixed size to fullscreen?

There is a website page which height and width are equal to 100% of the browser viewport (100vw and 100vh).
There is a high quality image (3000x2857px) inside of absolutely positioned wrapper in the center of the page. Image wrapper has max-width in pixels (e.g. 300px).
Also, the image has an overlay. I add .active class to the image wrapper by clicking on overlay. This class makes max-width of image wrapper equal to 100vw.
So, I want to animate this. I added transition to max-width, top, transform properties, but it's laggy. I know that it's due to top and max-width properties because of heavy calculations of the browser. But I don't know how to do it in other ways.
Any help would be welcome!
P.S. While I wrote this question, I found that this implementation is buggy in Safari. I think transform transition doesn't work in this browser, so it will be great if you suggest code that work in it :(
Demo: https://codepen.io/ghettojezuz/pen/ExvGwJB
const imageWrapper = document.getElementById("image-wrapper");
const overlay = document.getElementById("overlay");
function toggleImageWrapper() {
if (imageWrapper.classList.contains('active')) {
imageWrapper.classList.remove('active');
} else {
imageWrapper.classList.add('active');
}
}
overlay.addEventListener("click", () => {
toggleImageWrapper();
})
body {
min-height: 100vh;
overflow-x: hidden;
}
img {
width: 100%;
height: auto;
}
.wrapper {
width: 100vw;
min-height: 100vh;
height: 100%;
}
.image-wrapper {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
max-width: 300px;
width: 100%;
transition: max-width .8s ease, top .8s ease, transform .8s ease;
}
.image-wrapper.active {
max-width: 100vw;
left: 50%;
top: 0;
transform: translate(-50%, 0);
}
.image-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: transparent;
opacity: .7;
transition: background-color .3s ease;
cursor: pointer;
}
.image-overlay:hover {
background-color: #000000;
}
<div class="wrapper">
<div class="image-wrapper" id="image-wrapper">
<img src="https://via.placeholder.com/3000x2857.webp" alt="">
<div class="image-overlay" id="overlay"></div>
</div>
</div>
One method which seems to react to transitioning well is to alter the scale rather than try to reposition and alter width etc.
This snippet keeps the image centered and calculates the scale needed to move from the initial width to 100vw.
Note: it removes margin on elements to ensure the full width of the viewport is covered.
const imageWrapper = document.querySelector('.image-wrapper');
const overlay = document.querySelector('.image-overlay');
function toggleImageWrapper() {
if (imageWrapper.classList.contains('active')) {
imageWrapper.classList.remove('active');
} else {
imageWrapper.classList.add('active');
}
}
overlay.addEventListener("click", () => {
toggleImageWrapper();
})
function init() {
const w = window.innerWidth;
const scale = w / imageWrapper.offsetWidth;
imageWrapper.style.setProperty('--scale', scale);
}
window.onload = init;
window.onresize = init;
* {
padding: 0;
margin: 0;
}
body {
min-height: 100vh;
overflow-x: hidden;
}
img {
width: 100%;
height: auto;
}
.wrapper {
width: 100vw;
min-height: 100vh;
height: 100%;
}
.image-wrapper {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
max-width: 300px;
width: 100%;
transition: .8s ease;
}
.image-wrapper.active {
transform: translate(-50%, -50%) scale(var(--scale));
}
.image-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: transparent;
opacity: .7;
transition: scale .3s ease;
cursor: pointer;
}
.image-overlay:hover {
background-color: #000000;
}
<div class="wrapper">
<div class="image-wrapper" id="image-wrapper">
<img src="https://via.placeholder.com/3000x2857.webp" alt="">
<div class="image-overlay" id="overlay"></div>
</div>
</div>
So, I tried multiple things like different css properties, #keyframes animations etc. None of them worked. But I found out that when the image format is SVG, the freezing disappears. I know, not all images can be converted to SVG, but see what you can do about it.
I change the top and transform with flex, now when you click only width changes, but i guess the lag will happen sometime in transform animation case
const imageWrapper = document.getElementById("image-wrapper");
const overlay = document.getElementById("overlay");
function toggleImageWrapper() {
if (imageWrapper.classList.contains('active')) {
imageWrapper.classList.remove('active');
} else {
imageWrapper.classList.add('active');
}
}
overlay.addEventListener("click", () => {
toggleImageWrapper();
})
body {
min-height: 100vh;
overflow-x: hidden;
}
img {
width: 100%;
height: auto;
}
.img_container {
max-width:300px;
transition: .5s;
position:relative;
}
.wrapper {
width: 100vw;
min-height: 100vh;
height: 100%;
}
.image-wrapper {
position: absolute;
left: 0;
top: 0;
bottom:0;
right:0;
display:flex;
align-items:center;
justify-content:center;
width: 100%;
transition: .5s;
}
.image-wrapper.active .img_container {
max-width: 100vw;
}
.image-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: transparent;
opacity: .7;
transition: background-color .3s ease;
cursor: pointer;
}
.image-overlay:hover {
background-color: #000000;
}
<div class="wrapper">
<div class="image-wrapper" id="image-wrapper">
<div class="img_container">
<img src="https://via.placeholder.com/3000x2857.webp" alt="">
<div class="image-overlay" id="overlay"></div>
</div>
</div>
</div>

How would I mask an element with an animated overlay?

I'm trying to do some page transitions for a project I'm working on, I have an animated overlay that comes onto the screen when the user is navigating the site using Barba but I'm having an issue.
I want a logo centered on the page that rolls in with the overlay but I need it to be positioned separately from the overlay since any transform on the overlay would affect the logo as well. (I want the logo to mask with the overlay element)
What I've tried :
Switching around the Element hierarchy/Z-index (I'm sure the problem lies somewhere in here)
Trying different transforms
Messing with Max Width (Had some success but I need the transform origin property)
Example -
let transitionOpen = false;
$('.transition-cta').on("click", function() {
if (transitionOpen === false) {
$('.transition-background').css("transform", "scaleX(1)");
$(this).css("color", "white");
transitionOpen = true;
} else {
$('.transition-background').css("transform", "scaleX(0)");
$(this).css("color", "black");
transitionOpen = false;
}
});
body {
background-color: lightblue;
}
.someContent {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.transition-wrapper {
overflow: hidden;
}
.transition-background {
width: 100%;
height: 100vh;
position: absolute;
top: 0;
left: 0;
transform-origin: left;
transition: 0.7s ease-in-out;
background-color: #1f1f1f;
transform: scaleX(0);
z-index: 2;
}
.transition-center {
background-image: url('https://i.imgur.com/6um9G9h.png');
z-index: 2;
width: 150px;
height: 150px;
position: absolute;
background-repeat: no-repeat;
background-size: cover;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.transition-cta {
text-decoration: underline;
cursor: pointer;
z-index: 3;
position: absolute;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
<div class="transition-wrapper">
<div class="transition-background"></div>
<!-- I want to clip this with the transition background -->
<div title="I only want this to show with the transition overlay" class="transition-center"></div>
</div>
<div class="transition-cta">Trigger Transition</div>
<div class="someContent">
<h1>Some Content</h1>
</div>
(The globe should roll in with the overlay)
This feels like an extremely simple problem but I'm really struggling to solve it. I can't tell if I'm burned out or this is actually as complicated as my brain is making it.
Thanks!
Use a clip-path animation instead and you can simplify your code by having the logo as background of the transition-wrapper
let transitionOpen = false;
$('.transition-cta').on("click", function() {
$('.transition-wrapper').toggleClass('show');
if (transitionOpen === false) {
$(this).css("color", "white");
transitionOpen = true;
} else {
$(this).css("color", "black");
transitionOpen = false;
}
});
body {
background-color: lightblue;
}
.someContent {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.transition-wrapper {
width: 100%;
height: 100vh;
position: absolute;
top: 0;
left: 0;
transition: 0.7s ease-in-out;
background: url('https://i.imgur.com/6um9G9h.png') center/150px 150px no-repeat;
background-color: #1f1f1f;
clip-path: polygon(0 0, 0% 0, 0% 100%, 0 100%);
z-index: 3;
}
.transition-wrapper.show {
clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);
}
.transition-cta {
text-decoration: underline;
cursor: pointer;
z-index: 3;
position: absolute;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
<div class="transition-wrapper">
</div>
<div class="transition-cta">Trigger Transition</div>
<div class="someContent">
<h1>Some Content</h1>
</div>
I would do something like:
$('.transition-cta').on("click", function() {
$('.transition-wrapper').toggleClass('opened');
$('.transition-content').animate({ width: 'toggle' }, 800);
});
body {
background: lightblue;
}
.content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.transition-content {
background-color: #1f1f1f;
display: none;
overflow: hidden;
position: absolute;
right: 0;
left: 0;
top: 0;
bottom: 0;
width: 100%;
}
.transition-cta {
position: relative;
text-decoration: underline;
z-index: 999;
}
.transition-wrapper.opened .transition-cta {
color: #fff;
}
.transition-content__inner {
width: 100vw;
}
.transition-content__inner img {
width: 150px;
height: 150px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="transition-wrapper">
<div class="transition-cta">Trigger Transition</div>
<div class="content">
<h1>Some Content</h1>
</div>
<div class="transition-content">
<div class="transition-content__inner">
<img src="https://i.imgur.com/6um9G9h.png"/>
</div>
</div>
</div>

Postion a child element absolute to the page, even when the absolute positioned parent is moved

I position a container absolute to the page. In this container there is a span that I need to position absolute to the page as well, because I want to hide it if it overflows the parent container after it's moved.
It should look like this.
I can only hide the span, if it is a child and the parent has its overflow hidden. But then I can't position both absolute.
My current code looks like this:
.container {
overflow: hidden;
position: absolute;
width: 150px;
height: 50px;
background-color: black;
animation: move 2s ease-in-out alternate infinite;
}
.container span {
position: absolute;
left: 20px;
top: 20px;
color: white;
font-size: 16px;
}
#keyframes move {
0% {
top: 0;
}
100% {
top: 200px;
}
}
<div class="container">
<span>Text</span>
</div>
.container {
overflow: hidden;
position: absolute;
width: 150px;
height: 50px;
background-color: black;
animation: move 2s ease-in-out alternate infinite;
}
.container span {
position: absolute;
left: 20px;
top: 20px;
color: white;
font-size: 16px;
animation: move2 2s ease-in-out alternate infinite;
}
#keyframes move {
0% {
top: 0;
}
100% {
top: 200px;
}
}
#keyframes move2 {
0% {
top: 0;
}
100% {
top: -200px;
}
}
<div class="container">
<span>Text</span>
</div>
Use position:fixed with the child and consider clip-path instead of overflow to hide the overflow:
.container {
clip-path:polygon(0 0,100% 0,100% 100%,0 100%);
position: absolute;
width: 150px;
height: 50px;
background-color: black;
animation: move 2s ease-in-out alternate infinite;
}
.container span {
position: fixed;
left: 20px;
top: 20px;
color: white;
font-size: 16px;
}
#keyframes move {
0% {
top: 0;
}
100% {
top: 200px;
}
}
body {
background:blue;
}
<div class="container">
<span>Text</span>
</div>

Check if banner is loaded

Hi i Have a custom made banner with following code
body,
html {
width: 100%;
height: 100%;
margin: 0;
font-family: Arial, serif;
color: #003C78;
}
a {
color: #003C78;
}
.banner-wrap {
display: flex;
width: 728px;
height: 90px;
}
.page-container {
position: relative;
overflow: hidden;
width: 100%;
}
.page-container img {
width: 100%
}
.image-wrapper,
.text-wrapper {
position: absolute;
height: auto;
width: 411px;
}
.image-wrapper {
top: 0;
right: -155px;
z-index: 2;
animation: slideLeft 14.5s infinite ease 0s normal forwards;
}
.image-wrapper img {
position: absolute;
left: 0px;
top: -100px;
width: 150%
}
.text-wrapper h1,
.text-wrapper h2 {
position: absolute;
left: 90px;
padding: 0;
opacity: 0;
z-index: 3;
font-size: 1.3em;
}
.text-wrapper h1 {
animation: fade infinite 14.5s linear 0s normal forwards;
animation-delay: 4s;
top: 15px;
}
.text-wrapper h2 {
animation: fadeNew infinite 14.5s linear 0s normal forwards;
animation-delay: 7.8s;
}
.text-wrapper img {
position: absolute;
left: 50px;
bottom: 30px;
width: 468px;
height: 180px
}
.red-wrapper {
position: absolute;
bottom: 0px;
z-index: 9;
right: -600px;
color: #fff;
animation: slideLeftNew 14.5s infinite ease 0s normal forwards;
animation-delay: 7s;
padding-left: 15px;
border-bottom: 100px solid #E6000A;
border-right: 50px solid transparent;
height: 0;
width: 120px;
}
.red-wrapper h3 {
font-size: 1.1em;
font-weight: 300;
margin-top: 26px;
}
.logo img {
width: 80px;
height: auto;
margin: 17px;
}
img.kitchen {
transform: translateY(-40%);
-webkit-transform: translateY(-40%);
-ms-transform: translateY(-40%);
width: 63%;
position: absolute;
left: -18px;
animation: moveUp 14.5s infinite ease 0s normal forwards;
}
img.wall {
width: 11%;
position: absolute;
left: 0;
z-index: 9;
}
#keyframes slideLeft {
20.95% {
right: -155px
}
85%,
27.19% {
right: 135px;
}
}
#keyframes slideLeftNew {
15.95% {
right: -220px
}
20.19%,
37% {
right: 0
}
42% {
right: -220px;
}
}
#keyframes fade {
0% {
opacity: 0
}
23%,
14.38% {
opacity: 1
}
26% {
opacity: 0
}
}
#keyframes fadeNew {
0% {
opacity: 0
}
30%,
14.38% {
opacity: 1
}
33% {
opacity: 0
}
}
#keyframes moveUp {
0% {
transform: translateY(-40%);
}
50% {
transform: translateY(-45%);
}
}
<!DOCTYPE html>
<html>
<head>
<title>Hawa Sliding Solutions</title>
<meta content="text/html;charset=UTF-8" http-equiv="content-type">
</head>
<body>
<a href="http://hawa-suono.com/" target="_blank">
<div class="banner-wrap">
<div class="logo"><img src="logo.png"></div>
<div class="page-container">
<div class="text-wrapper">
<h1>Den Alltag auf stumm schalten.</h1>
<h2>Hawa Suono – die schalldichte Lösung.</h2>
</div>
<img class="wall" src="wall.png" />
<img class="kitchen" src="kitchen3.jpg" />
<div class="image-wrapper"><img src="tuer2.jpg" /></div>
<div class="red-wrapper">
<h3>Jetzt die Weltneuheit entdecken.</h3>
</div>
</div>
</div>
</a>
</body>
</html>
Now I need to check if the banner is loaded and work, and if it is not, then I need to put another image instead of the banner. I tried a lot of things, to check if image is there, to check if css is loaded, to check is the document loaded, but that solution can not work, because I must only check if the banner is loaded, not the whole document. So now, I am stacked and do not know what to do next.Also, I can not use jquery, only pure javascript.
Any help?
Thanks
If using JS,
function imgError(image) {
image.onerror = "";
image.src = "/images/wall.gif";
return true;
}
<img src="wall.png" onerror="imgError(this);"/>
Without JS,
<img src="wall.png" onError="this.onerror=null;this.src='/images/wall.gif';" />
you can do it with jquery
//check all images on the page
$('img').each(function(){
var img = new Image();
img.onload = function() {
console.log($(this).attr('src') + ' - done!');
}
img.src = $(this).attr('src');
});
working fiddle : http://jsfiddle.net/kalmarsh80/nrAPk/

Keyframes CSS Animation

Hello I'm trying to simulate flip countdown timer But when I wrote the code I discovered that there was a difference between:
#keyframes zindex {
0% {
z-index: 2;
}
5% {
z-index: 4;
}
100% {
z-index: 4;
}
}
and:
#keyframes zindex {
0% {
z-index: 2;
}
100% {
z-index: 4;
}
}
That when I remove 5% the problem will occurred so I'd like to know why this problem ocurres.
Here my code:
body {
font: normal 11px "Helvetica Neue", Helvetica, sans-serif;
}
.wrap {
width: 50px;
height: 100px;
position: absolute;
top: 50%;
left: 50%;
margin: -50px 0px 0px -25px;
}
ul#initial {
list-style-type: none;
width: 100%;
height: 100%;
padding: 0px;
position: relative;
}
ul#initial li {
position: absolute;
top: 0;
left: 0;
text-align: center;
width: 100%;
}
.first {
z-index: 3;
}
.second {
-webkit-animation: zindex 1s 1s linear both;
}
#keyframes zindex {
0% {
z-index: 2;
}
5% {
z-index: 4;
}
100% {
z-index: 4;
}
}
.flipthis {
height: 50px;
width: 50px;
position: absolute;
top: 0;
left: 0;
overflow: hidden;
background: #bbb;
transform-origin: 50% 100%;
color: #fff;
animation: flipthis 1s linear;
}
.flipthis-down {
height: 50px;
width: 50px;
background: #0034ff;
color: #fff;
overflow: hidden;
position: absolute;
top: auto;
left: 0;
bottom: 0;
}
.digit {
height: 200%;
font-size: 80px;
position: absolute;
width: 50px;
text-align: center;
text-shadow:0px 1px 2px rgba(224,224,224,0.87);
}
.flipthis-down .digit {
bottom: 0;
}
#-webkit-keyframes flipthis {
0% {
transform: rotateX(0deg);
}
100% {
transform: rotateX(-90deg);
}
}
.flipthis2 {
height: 50px;
width: 50px;
background: #00ff82;
color: #fff;
overflow: hidden;
position: absolute;
top: 0;
left: 0;
}
.flipthis2-down {
height: 50px;
width: 50px;
background: #00f760;
color: #fff;
-webkit-transform-origin: 50% 0%;
overflow: hidden;
position: absolute;
top: auto;
left: 0;
bottom: 0;
animation: flipthis-down 1s 1s linear;
}
.flipthis2-down .digit {
bottom: 0;
}
#-webkit-keyframes flipthis-down {
0% {
transform: rotateX(90deg);
}
100% {
transform: rotateX(0deg);
}
}
a.derp {
-webkit-perspective: 2000px;
display: block;
width: 50px;
height: 100px;
}
<div class="wrap">
<ul id="initial">
<li class="first">
<a class="derp">
<div class="flipthis">
<div class="digit">1</div>
</div>
<div class="flipthis-down">
<div class="digit">1</div>
</div>
</a>
</li>
<li class="second">
<a class="derp">
<div class="flipthis2">
<div class="digit">2</div>
</div>
<div class="flipthis2-down">
<div class="digit">2</div>
</div>
</a>
</li>
</ul>
</div>
The first example reaches the final value of '4' after only 5% of the animation is done, the second example increases the z-index linearly over the specified animation duration.
Adding multiple '%' values tells your browser at what point in time what value should be reached, so your first animation is basically already finished after 5% of the time has passed.

Categories