Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Background is shaking in transition

Tags:

html

css

I have two div elements that the width can be controlled with click event on javascript. Whether on click event (toggling a className) or hover event, the background images of the its pseudo element seems to be shaking (confirmed on chrome, ie, edge, and safari).

I have looked up on SO and google but it seems to be a problem with changing the size of the background itself, which is what I did not do here.

section {
	width: 100%;
	max-width: 1920px;
	position: relative;
	min-height: 700px;
	overflow: hidden;
}

.container {
	width: 99%;
	height: 700px;
	position: absolute;
	transition: 1s linear width;
	overflow: hidden;
}

.left {
	top: 0;
	left: 0;
	background: transparent;
	transform: skew(20deg) translateX(-50%);
	border-radius: 0 20px 20px 0;
}

.left::after {
	content: "";
	position: absolute;
	top: 0;
	left: 50%;
	height: 100%;
	width: 100vw;
	transform: skew(-20deg);
	background-image: url(https://cdn.pixabay.com/photo/2018/12/04/22/38/road-3856796__340.jpg);
	background-size: 100% 100%;
	background-position: center;
	background-repeat: no-repeat;
}

.right {
	top: 0;
	right: 0;
	border-radius: 20px 0 0 20px;
	transform: skew(20deg) translateX(50%);
}

.right::after {
	content: "";
	position: absolute;
	top: 0;
	right: 50%;
	height: 100%;
	width: 100vw;
	transform: skew(-20deg);
	background-image: url(https://media.istockphoto.com/photos/taking-a-walk-in-the-woods-picture-id1130258547?s=2048x2048);
	background-size: 100% 100%;
	background-position: center;
	background-repeat: no-repeat;
}

.right:hover {
	width: 250%;
}
<section>
  <div class="container left"></div>
	<div class="container right"></div>
</section>
like image 899
Ricky Stefano Avatar asked Mar 15 '19 12:03

Ricky Stefano


2 Answers

I have optimized the code and considered the use of left/right to define the size of the element then changed the width transition with a translation.

section {
  max-width: 1920px;
  position: relative;
  overflow: hidden;
  height: 500px;
}

.container {
  position: absolute;
  top: 0;
  bottom:0;
  transition:transform 1s linear;
  overflow: hidden;
  transform: skew(20deg);
}

.left {
  left: -60vw; /*to create the overflow*/
  right: calc(55% + 10px); /*10px distance between both element*/
  border-radius: 0 20px 20px 0;
}

.right {
  right: -80vw;
  left: 45%; /*100% - 55% (the right value of .left)*/
  border-radius: 20px 0 0 20px;
}

.left::after,
.right::after {
  content: "";
  position: absolute;
  top: 0;
  left: -40%;
  bottom: 0;
  right: -40%;
  transform: skew(-20deg);
  background-position: center;
  background-repeat: no-repeat;
  background-size: 100% 100%;
  transition:transform 1s linear;
}

.left::after {
  background-image: url(https://cdn.pixabay.com/photo/2018/12/04/22/38/road-3856796__340.jpg);
  transform-origin: bottom;
}

.right::after {
  transform-origin: top;
  background-image: url(https://media.istockphoto.com/photos/taking-a-walk-in-the-woods-picture-id1130258547?s=2048x2048);
}

.right:hover {
  transform: skew(20deg) translateX(-60vw);
}

.right:hover::after {
  transform: skew(-20deg) translateX(60vw);
}
<section>
  <div class="container left"></div>
  <div class="container right"></div>
</section>
like image 111
Temani Afif Avatar answered Oct 30 '22 02:10

Temani Afif


The shaking stems from the centered background-position of the background-image.

Let's do this by hand:

Image a 200px wide div and a background-image with 200px width.
The image is set to centered background-position and no other background-settings.
The image will then be positioned from 0px through 200px of the div

Now imaging the same div with the same background-image and background-position.
The only difference is: the div is 201px wide, that is just 1 more then before.
The image will now be positioned from 0.5px through 200.5px of the div which will be rounded to 1px through 201px

Now one step further: imagine the width of the div to be 202px without changing any other properties.
The image will be positioned from 1px through 201px. That's exactly the same as before.

Now because your div is centered. The background starts to shake

(This is not always visible. It depends on the context width);

let buttons = document.querySelectorAll('button');
let bg = document.querySelector('#bg')

buttons.forEach((btn) => {
  btn.addEventListener('click', (e) => {
    bg.style.width = btn.getAttribute('w')
  })
})
#bg {
  display: block;
  
  width: 200px;
  height: 200px;
  background-color: gold;
  margin: 10px auto;
  background-image: url('https://picsum.photos/200/200?image=990');
  background-position: center;
  background-repeat: no-repeat;
}

body {
  text-align: center;
  width: 400px;
}
<button w="200px">200</button> 
<button w="201px">201</button>
<button w="202px">202</button>

<div id="bg"></div>

The solution would be: The left image should be positioned from the left by background-position: 0% 50%; and the right image should be positioned from the right by background-position: 100% 50%;

This snippet should be seen in full page view

div {
  height: 800px;
  width: 100vw;
  overflow: hidden;
  margin: 0 auto;
  position: relative;
}
div span {
  position: absolute;
  top: 0;
  bottom: 0;
  z-index: 0;
  -webkit-transform: skew(20deg);
          transform: skew(20deg);
  overflow: hidden;
  border-radius: 20px;
  transition-duration: .3s;
  transition-timing-function: ease-in-out;
  -webkit-animation: at-zb 1s both;
          animation: at-zb 1s both;
}
div span:hover {
  z-index: 200;
  transition-duration: 1s;
  -webkit-animation: at-z 1s both;
          animation: at-z 1s both;
}
div span a {
  position: absolute;
  -webkit-transform: skew(-20deg);
          transform: skew(-20deg);
  background-size: cover;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
}
div span:nth-child(1) {
  left: -160px;
  right: calc(100% / 2 + 10px);
  transition-property: right;
}
div span:nth-child(1) a {
  -webkit-transform-origin: 0% 100%;
          transform-origin: 0% 100%;
  background-image: url("https://picsum.photos/1920/800?image=992");
  background-position: 0% 50%;
  background-repeat: no-repeat;
}
div span:nth-child(1):hover {
  right: -160px;
}
div span:nth-child(2) {
  left: calc(100% / 2 + 10px);
  right: -160px;
  transition-property: left;
}
div span:nth-child(2) a {
  -webkit-transform-origin: 0% 0%;
          transform-origin: 0% 0%;
  background-image: url("https://picsum.photos/1920/800?image=990");
  background-position: 100% 50%;
  background-repeat: no-repeat;
}
div span:nth-child(2):hover {
  left: -160px;
}

@-webkit-keyframes at-z {
  0% {
    z-index: 1;
  }
  1%,99% {
    z-index: 9;
  }
  100% {
    z-index: 10;
  }
}

@keyframes at-z {
  0% {
    z-index: 1;
  }
  1%,99% {
    z-index: 9;
  }
  100% {
    z-index: 10;
  }
}
@-webkit-keyframes at-zb {
  0% {
    z-index: 10;
  }
  1%,99% {
    z-index: 2;
  }
  100% {
    z-index: 1;
  }
}
@keyframes at-zb {
  0% {
    z-index: 10;
  }
  1%,99% {
    z-index: 2;
  }
  100% {
    z-index: 1;
  }
}
body {
  margin: 0;
  padding: 0;
}
<div><span><a></a></span><span><a></a></span></div>

See this codepen: https://codepen.io/HerrSerker/pen/zbWpjB for a SCSS version

like image 29
yunzen Avatar answered Oct 30 '22 03:10

yunzen