ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 9일 차 (모달창 반응형 + 모달창 페이지 전환)
    project/main 2023. 3. 15. 20:58

    어제 멘토분이 말씀하시길 요즘은 반응형이 기본이다! 라고 하셨다. 초기 기획 당시에는 반응형을 할 생각을 하지 않았다. 그래서 부랴부랴 CSS가 거의 끝난 오늘 해보기로 했다.


    1. 반응형

    요즘에는 인터넷을 컴퓨터로만 접속하는 것이 아닌 태블릿, 핸드폰으로도 접속한다. 그 화면에 맞춰 화면이 다르게 보이는 게 반응형이라고 할 수 있다. 반응형을 하지 않았을 때 화면을 줄이게 되면 화면에 있는 item들이 이상하게 배치되는 것을 확인할 수 있다.

     

    1. 1 @media

    @media only screen and (max-width: ;) {
    	// max-width의 아래 크기일때 적용되는 CSS
    }

    반응형을 구현하기 위해서는 @media를 사용해야 한다. ()안에 조건이 되는 크기 등을 적어 놓는다. 그리고 {}안에는 적용될 CSS를 적어 놓는다.

     


    2. 구현

    2.1 현재 상황의 파악

    • 모달의 배경이 되는 요소가 짧다.
    • 모달의 요소 내용이 한줄로 나열된다. 
    • 모달이 화면 밖까지 넘어간다.

    자, 이제 문제를 파악했으니 수정을 해보자

     

    2.2 모달의 배경이 되는 요소가 짧다.

    처음 스크롤을 하지 않고 모달창을 띄웠을 때는 괜찮지만 스크롤을 한 다음 모달창을 띄우거나 모달창을 띄우고 스크롤을 할 경우 위와 같이 배경이 되는 요소가 잘려있는걸 볼 수가 있다. 

     

    const ArticleModalContainer = styled.div`
      position: absolute;
      top: 0;
      bottom: 0;
      left: 0;
      right: 0;
      margin-top: 65px;
      background-color: rgba(0, 0, 0, 0.4);
      display: flex;
      justify-content: center;
      align-items: center;
    `;

     모달창이 부모요소에 영향을 받지 않게 하려고 position속성에 absolute를 주었고 몇 달전 크루분께서 알려주신 화면 전체의 크기로 만들 수 있는 위,아래, 좌, 우 속성에 모두 0을 주는 방식을 사용하고 있었다.

     

    고쳐보려고 아무리 크기를 주려고 %로 주어도 나중에 높이의 크기를 바꾸면 모달의 배경이 어긋나 버렸다. 그래서 생각을 바꿨다. 그럼 모달창이 고정이 아니라 따라오게 하자! 라는 생각을 하게 되었다. 

    • position속성 fixed로 바꾸기
    • 너비랑 높이 vw,vh로 바꾸기
    const ArticleModalContainer = styled.div`
      position: fixed;
      width: 100vw;
      height: 100vh;
      top: 0;
      bottom: 0;
      left: 0;
      right: 0;
      background-color: rgba(0, 0, 0, 0.4);
      display: flex;
      justify-content: center;
      align-items: center;
      `;

    위의 코드를 적용하면 어디에서 모달을 누르든 꽉 차고 가운데 있는 모달을 볼 수 있다.

     

     

    2.3 모달의 요소 내용이 한줄로 나열된다.

    이 문제는 처음 데스크탑의 기준으로 작성할 때 양쪽에 있는 화살표 버튼의 마진이 너무 큰게 첫번째였고 최소 높이 값이 정해져 있는게 두번째 문제였다.

     

    먼저 양쪽에 있는 화살표 버튼의 마진을 @media를 사용하여 줄였다.

    const ArticleModalArrowButton = styled.div`
      margin: 0 var(--xxx-large);
      font-size: var(--xxx-large);
      color: var(--color-white);
    
      @media only screen and (max-width: 768px) {
        margin: 0 var(--large); //마진 값 바꾸기
      }
    `;

    그리고 모달창의 최소 높이가 너무 커서 최소 높이를 줄이고 최대 높이를 설정했다.

    const ArticleContentContainer = styled.div`
      height: 100%;
      min-height: 1000px; // 정해진 최소높이
      min-width: 800px;
      padding: 0 150px;
      display: flex;
      flex-direction: column;
    
      @media only screen and (max-width: 768px) {
        width: 100%;
        max-height: 800px; // 최대높이 설정
        min-height: 0; // 최소높이 설정
        min-width: 270px;
        padding: 50px;
        margin: none;
      }
    `;

    이후에는 margin과 padding을 조절하고 글씨가 밖으로 나와서 content body의 크기를 정하고 overflow:scroll로 밖으로 나온 부분을 안보이게 하고 스크롤을 사용해서 볼수 있게 했다. 그리고 스크롤바가 공간을 차지하며 이상하게 나올 경우가 있어 스크롤도 안보이게 했다.

    const ArticleContentBodyContainer = styled.div`
      flex: 2 0;
      padding: 0 var(--xx-large);
      display: flex;
      justify-content: center;
      align-items: center;
      font-size: var(--text-medium);
      line-height: 26px;
      text-align: center;
      
      @media only screen and (max-width: 768px) {
        max-height: 450px;
        align-items: flex-start;
        padding: var(--large);
        font-size: var(--text-large);
        line-height: var(--large);
        overflow-x: scroll;
        &::-webkit-scrollbar {
          display: none;
        }
      }
    `;

    2.4 한 가지 문제 발생 ( 외부 스크롤 고정 )

    모달창 내부에도 스크롤이 있고 외부에도 스크롤이 있어서 스크롤을 내리면 외부가 내려가는게 종종 발생했다. 그래서 외부 스크롤을 고정하기로 했다. ( 참고 : https://velog.io/@do_dadu/React%EC%97%90%EC%84%9C-Modal-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0feat.-createPortal-%EC%8A%A4%ED%81%AC%EB%A1%A4-%EB%A7%89%EA%B8%B0 )

    useEffect(() => {
        document.body.style.cssText = `
          position: fixed; 
          top: -${window.scrollY}px;
          overflow-y: scroll;
          width: 100%;`;
        return () => {
          const scrollY = document.body.style.top;
          document.body.style.cssText = "";
          window.scrollTo(0, parseInt(scrollY || "0", 10) * -1);
        };
      }, []);
    • useEffect를 사용하여 모달창이 열렸을때 CSS를 추가해서 외부 화면을 fixed로 고정하고 top에서부터의 위치를 저장한다.
    • 모달창이 닫혔을때 useEffect의 return을 사용하여 CSS초기화하고 저장한 위치로 다시 이동시킨다.

    2.5 모달창 페이지 전환 구현

    나중을 위해 기능을 추가했다. Article 페이지에 페이지 전환하는 것인데 Article의 내용이 많기에 모달창에서 페이지를 넘겨 전환하는 기능을 구현했다.

    const [modalNum, setModalNum] = useState(0);
    const modalRef = useRef<HTMLDivElement>(null);
    
    const handleLeftClick = (e: React.MouseEvent<HTMLElement>) => {
        e.stopPropagation();
        if (modalRef.current) { //modalRef.current가 null일 수 있다는 오류 해결
          if (modalNum !== 0) { // 첫번째 페이지일 경우 못 가게
            modalRef.current.style.cssText = `top: -${modalNum - 1}00%;`;
            setModalNum(modalNum - 1);
          }
        }
      };
    
      const handleRightClick = (e: React.MouseEvent<HTMLElement>) => {
        e.stopPropagation();
        if (modalRef.current) {
          if (modalNum !== 1) { // 마지막 페이지일 경우 못 가게
            // 1인 부분 데이터를 서버에서 받게 되면 데이터의 갯수로 표기
            modalRef.current.style.cssText = `top: -${modalNum + 1}00%;`;
            setModalNum(modalNum + 1);
          }
        }
      };
    •  useRef() 를 사용하여 모달의 DOM 주소를 가져옴
    • 주소를 저장한 변수로 CSS를 조작함 (Typescript를 사용하니 modalRef.current가 null일 수 있다는 오류를 표출했다. 그래서 조건문으로 modalRef.current가 true값을 가질때에만 적용되게하니 오류가 잡혔다.)
    • useState로 현재 페이지 저장
    • 현재 페이지에서 버튼을 누를 경우 페이지 값을 조작해 위치 이동

    'project > main' 카테고리의 다른 글

    11일 차 (서버와 연결)  (0) 2023.03.17
    10일 차 (무한 스크롤 구현)  (0) 2023.03.16
    8일 차 - 이미지 업로드 일부 구현(Toast UI로 통신 결과 받는 것 까지!)  (0) 2023.03.14
    7일차  (0) 2023.03.13
    5일차  (0) 2023.03.09
Designed by Tistory.