퍼블리싱 - 이미지링크 (feat. 이미지호버, button과 a태그의 차이, resize)

이수빈·2023년 6월 9일
1

펫모리플젝

목록 보기
6/9
post-thumbnail
  • 펫모리 프로젝트에서 이미지링크 관련 퍼블리싱을 한 코드 정리

이미지 호버 관련 작업

  • 이미지에 마우스가 호버되었을 때의 작업은 HTML5에서 추가된 figure 태그와 figcaption 태그를 이용해 처리했다.

  • figure태그는 삽화, 다이어그램, 사진, 동영상, 음원 등 해당 콘텐츠에 대한 설명을 입력할 때 사용한다.

  • figcaption는 figure 요소 안에서 콘텐츠에 대한 제목을 출력한다. 반드시 figure 태그 안에서 사용해야한다.

  • div태그를 사용하도 무방하지만, 웹 접근성때문에 figure태그와 figcaption을 사용했다.

이미지 링크관련 작업

  • 이전에는 마크업과정에서 button태그와 a태그를 고민없이 섞어서 사용했었다. 하지만, 두 태그에는 보여지는 기능상에는 차이가 없을지라도 큰 차이점들이 있다.
  • 앨범에서 사진을 누르면 상세페이지로 이동하는 이미지 링크형식이였기 때문에, 이를 구현하기 위해 react-router-dom에서 제공하는 Link태그를 사용했다.

  • a태그를 사용하게 되면 href에 지정된 경로로 페이지 이동을 하면서 새로운 데이터를 다시 불러오게 되지만, Link태그는 SPA방식에 맞게 바뀌어야 하는 화면만 리렌더링 하는 장점이 있다.

Button 태그 vs anchor 태그

  • button태그와 a태그의 차이점은 다음과 같다.

  • 먼저 a태그는 다른 페이지로 이동하거나, 같은 문서내에 다른 anchor 태그로 이동할때 사용한다. 즉 페이지 이동과 관련된 기능에는 a태그를 사용해야한다.

  • 키보드 엔터로 동작하고, 마우스 오른쪽 버튼을 클릭했을 때 여러 기능들이 존재한다.

  • button 태그는 이동기능 외에 여러가지 내용의 일부만 변경되는 경우 사용한다.

  • 예를들어 폼을 전송하거나 취소할 때, 팝업이나 모달을 열거나 메뉴를 열때, 동영상을 플레이 할때 등등을 위해 사용한다.

  • 오른쪽 버튼을 클릭 할 시 별다른 기능이 존재하지 않는다.

  • 이처럼 기능상 동일해보이지만, 두개의 태그는 완전히 다른 기능을 가지고 있다. 스크린 리더상에도 다른 용도로 인식하기 때문에 웹 접근성 관점에서도 기능에 따라 올바르게 태그를 마크업하는 과정이 중요하다.

  • 페이지 이동시에는 a태그를 사용해야하고, 폼을 전송하거나 페이지 내에서 사용자와 상호작용시에는 button태그를 사용해야한다.

이미지 resize 작업

  • Grid 형식의 반응형 웹을 구현했기 때문에, 정사각형 이미지 resize 과정에서 최적화 작업이 필요했었다.

  • 초기에는 이미지 컨테이너 사이즈에 따라 이미지 사이즈가 변하도록 구현하였는데, 이렇게 구현하니 컨테이너 사이즈가 변할때마다 이미지 reflow가 너무 많이 발생하였다.

  • 이를 해결하기 위해, img에 width와 aspect-ratio속성으로 치수를 주는 과정을 통해 reflow를 방지하였고, Lazy loading 속성을 적용하였다.

aspect-ratio속성

  • aspect-ratio 는 요소를 크기 비율대로 조정 할 수 있게 해주는 css 속성이다. 최근 반응형 웹 대부분에서 사용한다.

  • aspect-ratio 속성과 object-fit : cover 속성을 함께 사용하면, 이미지가 깨지지 않으면서 원하는 종횡비를 유지 할 수 있다.

마크업 작업

  • 먼저 마크업 작업은 이미지 링크이기때문에 Link태그로 이미지를 감싸고, 그안에 figure, figcaption태그와 img태그를 넣었다.

  • 여기서 figBox는 글씨를 담고있는 배경이고, figcaption은 배경안에 들어가있는 글자이다.

//AlbumPresenter.tsx
import { Link } from 'react-router-dom';
import { AlbumContainer } from './style/AlbumPresenterStyle';
import type { AlbumContent } from '../../../type/AlbumType';

type AlbumPresenterProps = {
  albumData: AlbumContent[];
};

const AlbumPresenter = ({ albumData }: AlbumPresenterProps) => {
  return (
    <AlbumContainer>
      {albumData.map((item) => (
        <Link to={`${item.albumId}`} className="imgLink" key={item.albumId}>
          <figure>
            <img src={item.imageUrl} loading="lazy" alt={item.title} />
            <div className="figBox">
              <figcaption>
                <div className="figItemBox">
                  <img src="/img/HeartDog.svg" alt="HeartDog" className="figItemImg" />
                  <div>{item.empathyCount}</div>
                </div>
                <div className="figItemBox">
                  <img src="/img/Comment.svg" alt="Comment" className="figItemImg" />
                  <div>{item.commentCount}</div>
                </div>
              </figcaption>
            </div>
          </figure>
        </Link>
      ))}
    </AlbumContainer>
  );
};

export default AlbumPresenter;

CSS작업

  • 마우스가 호버되기 전 상태에서는 figBox는 아무런 배경색이 없고, figcaption의 opacity는 0인 상태이다.

  • 호버되었다면, figBox의 투명도를 0.6으로 배경색을 지정해주고, figcaption의 opacity를 1로 바꿔준다.

  • figBox에 opacity속성을 지정하게 되면 figcaption의 글씨또한 흐려지기 때문에 rgba를 통해 background color의 투명도를 조정해주는 방법을 사용하였다.

//AlbumPresenterStyle.ts
import styled from 'styled-components';

export const AlbumContainer = styled.section`
  margin: min(70px, 5vw) 10vw;
  width: 80vw;
  height: 100vh;
  overflow: auto;
  display: grid;
  grid-template-columns: repeat(4, 1fr);

  grid-gap: 24px;

  img {
    border-radius: 8px;
    object-fit: cover;
    aspect-ratio: 1;
    width: 100%;
  }

  figcaption {
    position: absolute;
    display: flex;
    justify-content: space-evenly;
    align-items: center;
    opacity: 0;
    top: 50%;
    left: 50%;
    transform: translate3d(-50%, -50%, 0);
    border-radius: 8px;
    width: 90%;
    aspect-ratio: 1;
    border: 1px solid ${({ theme }) => theme.color.grayScale.white};
    box-sizing: content-box;
  }

  .figBox {
    position: absolute;
    top: 0;
    left: 0;
    border-radius: 8px;
    width: 100%;
    aspect-ratio: 1;
  }

  .figItemBox {
    display: flex;
    flex-direction: column;
    align-items: center;
  }

  .figItemImg {
    margin-bottom: 15px;
  }

  .imgLink {
    all: unset;
    position: relative;
    color: ${({ theme }) => theme.color.grayScale.white};
    font-family: ${({ theme }) => theme.font.family.gmarketSans_medium};
    font-size: 20px;
    aspect-ratio: 1;

    &:hover {
      cursor: pointer;

      .figBox {
        background-color: rgba(255, 138, 51, 0.6);
      }

      figcaption {
        opacity: 1;
      }
    }
  }

  @media screen and (max-width: 1024px) {
    grid-template-columns: repeat(2, 1fr);

    &.imgLink {
      font-size: 10px;
    }

    &.figItemImg {
      margin-bottom: 10px;
    }
  }
`;

ref) a태그 vs button 태그 :https://1023labs.com/posts/web-accessibility-btn/
이미지 사이즈 최적화 : https://velog.io/@hustle-dev/%EC%9B%B9-%EC%84%B1%EB%8A%A5%EC%9D%84-%EC%9C%84%ED%95%9C-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EC%B5%9C%EC%A0%81%ED%99%94

profile
응애 나 애기 개발자

0개의 댓글