Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

161
Visualizações
How to make a box expand and transition from origin to center of screen without affecting DOM?

I'm trying to make it so that a box would expand (in width and height) and transition from its origin to the center of a screen upon being clicked. Here's what I have so far:

I'm running into two problems here -- when I click on the box, the DOM automatically shifts, because the clicked element has its position changed to 'absolute'. The other problem is that the box doesn't transition from its origin, it transitions from the bottom right corner (it also doesn't return to its position from the center of the screen, when make inactive is clicked).

What am I doing wrong here?

import React from "react";
import styled from "styled-components";
import "./styles.css";

export default function App() {
  const [clickedBox, setClickedBox] = React.useState(undefined);

  const handleClick = React.useCallback((index) => () => {
    console.log(index);
    setClickedBox(index);
  });

  return (
    <Container>
      {Array.from({ length: 5 }, (_, index) => (
        <Box
          key={index}
          active={clickedBox === index}
          onClick={handleClick(index)}
        >
          box {index}
          {clickedBox === index && (
            <div>
              <button
                onClick={(e) => {
                  e.stopPropagation();
                  handleClick(undefined)();
                }}
              >
                make inactive
              </button>
            </div>
          )}
        </Box>
      ))}
    </Container>
  );
}

const Container = styled.div`
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  height: 100vh;
`;

const Box = styled.div`
  flex: 1 0 32%;
  padding: 0.5rem;
  cursor: pointer;
  margin: 1rem;
  border: 1px solid red;
  transition: 2s;
  background-color: white;
  ${({ active }) => `
    ${
      active
        ? `
      position: absolute;
      width: 50vw;
      height: 50vh;
      background-color: tomato;
      top: 50%;
      left: 50%; 
      transform: translate(-50%, -50%);
    `
        : ""
    }
  `}
`;

relaxed-galois-iypsj

about 4 years ago · Juan Pablo Isaza
3 Respostas
Responde à pergunta

0

With CSS

Wery unlikely you can achieve that with plain css. And for sure impossible to achieve a versatile solution.

  • You have a dynamic size and position to adopt to (starting div)
  • You have to adapt to the current scrolling position
  • If you remove the div from the layout is almost impossible to avoid screwing up the layout (even if you can, there will always be some edge case).
  • transition from a relative to a fixed position.

With the current css standard is impossible to perform these things.

With JS

The solution is to do some javascript magic. Since you are using React i developed you a solution using react-spring (an animation framework). Here you have a wrapping component that will do what you want:

The complete SandBox

import React, { useEffect, useRef, useState } from "react";
import { useSpring, animated } from "react-spring";

export default function Popping(props) {
  const cont = useRef(null);
  const [oriSize, setOriSize] = useState(null);
  const [finalSize, setFinalSize] = useState(null);

  useEffect(() => {
    if (props.open && cont.current) {
      const b = cont.current.getBoundingClientRect();
      setOriSize({
        diz: 0,
        opacity: 0,
        top: b.top,
        left: b.left,
        width: b.width,
        height: b.height
      });
      const w = window.innerWidth,
        h = window.innerHeight;
      setFinalSize({
        diz: 1,
        opacity: 1,
        top: h * 0.25,
        left: w * 0.25,
        width: w * 0.5,
        height: h * 0.5
      });
    }
  }, [props.open]);

  const styles = useSpring({
    from: props.open ? oriSize : finalSize,
    to: props.open ? finalSize : oriSize,
    config: { duration: 300 }
  });

  return (
    <>
      <animated.div
        style={{
          background: "orange",
          position: "fixed",
          display:
            styles.diz?.interpolate((d) => (d === 0 ? "none" : "initial")) ||
            "none",
          ...styles
        }}
      >
        {props.popup}
      </animated.div>
      <div ref={cont} style={{ border: "2px solid green" }}>
        {props.children}
      </div>
    </>
  );
}

Note: This code uses two <div>, one to wrap your content, and the second one is always fixed but hidden. When you toggle the popup visibility, the wrapping div gets measured (we obtain its size and position on the screen) and the fixed div is animated from that position to its final position. You can achieve the illusion you are looking for by rendering the same content in both <div>, but there is always the risk of minor misalignment.

about 4 years ago · Juan Pablo Isaza Relatório

0

The idea is similar to what newbie did in their post but without any extra libraries. I might have done some things a bit non-standard to avoid using any libraries.

CodeSandbox

import React from "react";
import { StyledBox } from "./App.styles";

export const Box = (props) => {
  const boxRef = React.useRef(null);
  const { index, active, handleClick } = props;
  const handleBoxClick = () => {
    handleClick(index);
  };

  React.useEffect(() => {
    const b = boxRef.current;
    const a = b.querySelector(".active-class");
    a.style.left = b.offsetLeft + "px";
    a.style.top = b.offsetTop + "px";
    a.style.width = b.offsetWidth + "px";
    a.style.height = b.offsetHeight + "px";
  });

  return (
    <StyledBox active={active} onClick={handleBoxClick} ref={boxRef}>
      box {index}
      <div className="active-class">
        box {index}
        <div>
          <button
            onClick={(e) => {
              e.stopPropagation();
              handleClick(undefined);
            }}
          >
            make inactive
          </button>
        </div>
      </div>
    </StyledBox>
  );
};

import styled from "styled-components";

export const StyledContainer = styled.div`
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  height: 100vh;
`;

export const StyledBox = styled.div`
  flex: 1 0 32%;
  padding: 0.5rem;
  cursor: pointer;
  margin: 1rem;
  border: 1px solid red;

  background-color: white;

  .active-class {
    position: absolute;
    transition: 0.3s all ease-in;
    background-color: tomato;
    z-index: -1;

    ${({ active }) =>
      active
        ? `
      width: 50vw !important;
      height: 50vh !important;
      top: 50% !important;
      left: 50% !important; 
      transform: translate(-50%, -50%);
      z-index: 1;
      opacity: 1;
    `
        : `
      z-index: -1;
      transform: translate(0, 0);
      opacity: 0;
    `}
  }
`;

about 4 years ago · Juan Pablo Isaza Relatório

0

first, transition with position or display don't work on css(it can work but without transition).

here you have:

flex: 1 0 32%;

that is equivalent to :

flex-grow: 1;
flex-shrink: 1;
flex-basis: 32%;

so, when active is true, width would jump to 50vw and height to 50vh but roughly without transition. so the solution is to use scale like this:

  z-index: 99;
  transform: scaleY(5) scaleX(2) translate(20%, 20%);
background-tomato: tomato

and you need to tweak the values of scaleY, scaleX and translate (for each Box) until you get it to work.

you can take a look at what i did in this codesandbox: https://codesandbox.io/s/peaceful-payne-ewmxi?file=/src/App.js:1362-1432

here is also a link if you want master flex: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Controlling_Ratios_of_Flex_Items_Along_the_Main_Ax

about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda