Home > database >  Keep constraints between two elements when one is getting off screen
Keep constraints between two elements when one is getting off screen

Time:04-21

I would like an element "1" to go off screen (off red square in my example) and to be followed by an element "2" without having to use anything else than CSS constraints.

const right = document.getElementById('right');
const left = document.getElementById('left');

function r(min, max) {
  return Math.floor(Math.random() * (max - min   1)   min);
}

right.style.width = `${r(10, 30)}%`;
left.style.width = `${r(10, 30)}%`;

left.onclick = () => {
    left.classList.toggle('retracted');
}
* {
    padding: 0;
    margin: 0;
    font-family: 'Courier New', Courier, monospace;
    font-weight: bold;
}

body {
    width: 100vw;
    height: 100vh;
}

.container {
    width: 50vw;
    height: 50vh;
    transform: translate(-50%, -50%);
    left: 50vw;
    top: 50vh;
    border: 3px solid red;
    position: absolute;
    display: flex;
    flex-direction: row;
    box-sizing: border-box;
}

.panel {
    width: 30%;
    border: 1px solid rgba(0, 0, 0, 0.1);
    height: 100%;
    position: relative;
    display: flex;
    justify-content: center;
    align-items: center;
    resize: horizontal;
    user-select: none;
    box-sizing: border-box;
    transition: all .2s;
}

.left {
    background-color: rgb(95, 158, 160, 0.5);
}

.left.retracted {
    transform: translateX(-100%);
}

.right {
    background-color: rgb(255, 228, 196, 0.5);
    right: 0;
}

.filler {
    flex: 1;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="index.css" />
    <title>Slide</title>
</head>
<body>
    <div >
        <div id="left" >
            1
        </div>

        <div id="right" >
            2
        </div>

        <div ></div>
    </div>

    <script src="index.js"></script>
</body>
</html>

I can do this by hand by computing sizes and everything I want in js but it's not my goal, I was wondering if there was any way to keep constraints between these two elements and keep the animation.

I only do:

right.style.width = `${r(10, 30)}%`;
left.style.width = `${r(10, 30)}%`;

this to simulate the fact that the two elements does not have the same size and that I'm looking for a self-compute-less solution.

CodePudding user response:

what do you think about adding transform: translateX(-100%) to all .panels ?

const container = document.getElementById('container');
const left = document.getElementById('left');


left.onclick = () => {
    container.classList.toggle('retracted');
}
* {
    padding: 0;
    margin: 0;
    font-family: 'Courier New', Courier, monospace;
    font-weight: bold;
}

body {
    width: 100vw;
    height: 100vh;
}

.container {
    width: 50vw;
    height: 50vh;
    transform: translate(-50%, -50%);
    left: 50vw;
    top: 50vh;
    border: 3px solid red;
    position: absolute;
    display: flex;
    flex-direction: row;
    box-sizing: border-box;
}

.panel {
    width: 30%;
    border: 1px solid rgba(0, 0, 0, 0.1);
    height: 100%;
    position: relative;
    display: flex;
    justify-content: center;
    align-items: center;
    resize: horizontal;
    user-select: none;
    box-sizing: border-box;
    transition: all .2s;
}

.left {
    background-color: rgb(95, 158, 160, 0.5);
}

.container.retracted > * {
    transform: translateX(-100%);
}

.right {
    background-color: rgb(255, 228, 196, 0.5);
    right: 0;
}

.filler {
    flex: 1;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="index.css" />
    <title>Slide</title>
</head>
<body>
    <div  id="container">
        <div id="left" >
            1
        </div>

        <div id="right" >
            2
        </div>

        <div ></div>
    </div>

    <script src="index.js"></script>
</body>
</html>

CodePudding user response:

Check this


Using variables will solve width problem.

Basically you are using variables to make right container move as left container.


:root{
  --left-width: 30%;
  --right-width: 50%;
  --left-value:30;
  --right-value:50;
}

.right.retracted{
  transform: translateX(calc(-100% * var(--left-value) / var(--right-value)));
}

const leftContainer = document.querySelector('.left');
const rightContainer = document.querySelector('.right');

leftContainer.onclick = () => {
    rightContainer.classList.toggle('retracted');
    leftContainer.classList.toggle('retracted');
    
}
*,
*::before,
*::after {
  box-sizing: border-box;
}



body{
  min-height: 100vh;
  overflow: hidden;
  display: grid;
  place-content: center;
  margin:0;
  background-color: white;
}

.container {
  width: 50vw;
  height: 50vh;
  margin:auto;
  border: 3px solid red;
  display: flex;
  flex-direction: row;
  justify-content: start;
  transition: all 1s;
}

.panel {
  border: 1px solid rgba(0, 0, 0, 0.1);
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  resize: horizontal;
  user-select: none;
  transition: all .2s;
}

:root{
  --left-width: 30%;
  --right-width: 50%;
  --left-value:30;
  --right-value:50;
}

.left {
  width: var(--left-width);
  background-color: rgb(95, 158, 160, 0.5);
}
.left.retracted{
  transform: translateX(-100%);
  transition: all .2s; 
}

.right {
  width:var(--right-width);
  background-color: rgb(255, 228, 196, 0.5);
}

.filler {
  flex: 1;
}

.right.retracted{
  transform: translateX(calc(-100% * var(--left-value) / var(--right-value)));
  transition: all .2s; 
}
<div >
      <div >
        <p>1</p>
      </div>

      <div >
        <p>2</p>
      </div>

      <div ></div>
</div>

CodePudding user response:

If you just want them to go off the viewport together you can set them both to a negative left value (big enough to ensure they won't be seen at the end of the transition) on the retract class being set in left.

const right = document.getElementById('right');
const left = document.getElementById('left');

function r(min, max) {
  return Math.floor(Math.random() * (max - min   1)   min);
}

right.style.width = `${r(10, 30)}%`;
left.style.width = `${r(10, 30)}%`;

left.onclick = () => {
  left.classList.toggle('retracted');
}
* {
  padding: 0;
  margin: 0;
  font-family: 'Courier New', Courier, monospace;
  font-weight: bold;
}

body {
  width: 100vw;
  height: 100vh;
}

.container {
  width: 50vw;
  height: 50vh;
  transform: translate(-50%, -50%);
  left: 50vw;
  top: 50vh;
  border: 3px solid red;
  position: absolute;
  display: flex;
  flex-direction: row;
  box-sizing: border-box;
}

.panel {
  width: 30%;
  border: 1px solid rgba(0, 0, 0, 0.1);
  height: 100%;
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  resize: horizontal;
  user-select: none;
  box-sizing: border-box;
  transition: all .2s linear;
  left: 0;
}

.left {
  background-color: rgb(95, 158, 160, 0.5);
}

.right {
  background-color: rgb(255, 228, 196, 0.5);
  right: 0;
}

.left.retracted,
.left.retracted .right {
  left: -100vw;
  transition: all 2s;
}

.filler {
  flex: 1;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="index.css" />
  <title>Slide</title>
</head>

<body>
  <div >
    <div id="left" >
      1
    </div>

    <div id="right" >
      2
    </div>

    <div ></div>
  </div>

  <script src="index.js"></script>
</body>

</html>

  • Related