목 차![down-arrow]()
〈
블로그 개발 - display: none과 visibility: hidden 차이 (feat. 다음, 이전 버튼)
2024.06.08.

display: none과 visibility: hidden 차이 (feat. 다음, 이전 버튼)
포스트 페이지의 하단에 다음글, 이전글로 이동할 수 있는 버튼을 만들고 싶었고 디자인은 아래와 같이 설정하였다.
포스트 페이지 하단의 이전버튼, 다음버튼 figma 디자인
🕹️ 버튼 구현하기
1. 페이지 생성 시, gatsby-node.js
// gatsby-node.js
exports.createPages = async ({ actions, graphql, reporter }) => {
const { createPage } = actions
const queryAllMarkdownData = await graphql(
`
{
allMarkdownRemark(
sort: {
order:DESC
fields: [frontmatter___date, frontmatter___title]
}
) {
edges {
node {
id
fields {
slug
}
}
}
}
}
`
)
if (queryAllMarkdownData.errors) {
reporter.panicOnBuild(`Error while running query`)
return
}
const posts = queryAllMarkdownData.data.allMarkdownRemark.edges
posts.forEach((post, index) => {
// 이전 포스트와 다음 포스트의 id
const prevPostId = index === 0 ? null : posts[index - 1].node.id
const nextPostId = index === posts.length - 1 ? null : posts[index + 1].node.id
// 페이지 생성 시, 이전 포스트와 다음 포스트의 id 담아서 생성하기
createPage({
path: post.node.fields.slug,
component: path.resolve(__dirname, "src/templates/PostTemplate.tsx"),
context: {
slug: post.node.fields.slug,
prevPostId,
nextPostId
}
})
})
}2. 이전글, 다음글에 대한 정보 쿼리하기
// PostTemplate에서 쿼리하기
// ...
export const queryMarkdownDataSlug = graphql`
query queryMarkdownDataBySlug($slug: String, $prevPostId: String, $nextPostId: String) {
site {
siteMetadata {
author
}
}
allMarkdownRemark(filter: {fields: {slug: {eq: $slug}}}) {
edges {
node {
html
frontmatter {
title
date(formatString: "YYYY.MM.DD.")
tags
category
thumbnail {
childImageSharp {
gatsbyImageData
}
publicURL
}
}
}
}
}
// gatsby-node.js에서 받은 prevPostId와 같은 id의 slug와 title을 받아 previous로 props 전달
previous: markdownRemark(id: {eq: $prevPostId}) {
fields {
slug
}
frontmatter {
title
}
}
// gatsby-node.js에서 받은 nextPostId와 같은 id의 slug와 title을 받아 next로 props 전달
next: markdownRemark(id: {eq: $nextPostId}) {
fields {
slug
}
frontmatter {
title
}
}
}
`;3. 컴포넌트 간 구조
4. props를 통한 조건부 렌더링
PostTemplate 컴포넌트에서 쿼리한
// PostTemplate.tsx
import PostPrevNextBtns from "components/Blog/Post/PostPrevNextBtns";
const PostTemplate = ({ next, previous }) => {
return (
<div>
<PostPrevNextBtns
previous={previous}
next={next}
/>
</div>
);
};
export default PostTemplate;
export const queryMarkdownDataSlug = graphql`
// ...
previous: ...
next: ...
`;// PostPrevNextBtns.tsx
import PostPrevNextBtn from "components/Blog/Post/PostPrevNextBtn";
const PostPrevNextBtns = () => {
return (
<div>
<PostPrevNextBtn
label="< 이전글"
slug={prevSlug}
title={prevTitle}
/>
<PostPrevNextBtn
label="다음글 >"
slug={nextSlug}
title={nextTitle}
/>
</div>
);
};
export default PostPrevNextBtns;// PostPrevNextBtn.tsx
import styled from "@emotion/styled";
import { Link } from "gatsby";
const PostPrevNextBtnWrapper = styled(Link)<({ label: string, slug: string })>`
// slug가 없을 경우 (가장 맨 앞 포스트로서 이전글이 없음, 가장 맨 뒤 포스트로서 다음글이 없음)
// display: none
// slug가 있을 경우
// display: block
display: ${({ slug }) => slug === "" ? "none" : "block"};
gap: 12px;
width: 100%;
height: auto;
padding: 16px;
background-color: ${({ theme }) => theme.colors.background.prevNext};
border-radius: 12px;
transition: all 0.1s linear;
text-align: ${({ label }) => label === "다음글 >" ? "right" : "left"};
&:hover {
background-color: ${({ theme }) => theme.colors.background.button};
}
`;
const PostPrevNextBtn = ({ label, slug, title }) => {
return (
<PostPrevNextBtnWrapper
to={slug}
label={label}
slug={slug}
>
<label>{label}</label>
<p>{title}</p>
</PostPrevNextBtnWrapper>
);
};
export default PostPrevNextBtn;display 속성과 visibility 속성 비교
이렇게 PostPrevNextBtnWrapper에 Styled Component의 props로 전달받은 slug 값의 따라서 display 속성을 none 또는 block으로 조건부 렌더링을 처음에
처리했었다.
하지만 이렇게 display로 처리하면 가장 맨 앞 포스트, 맨 뒤 포스트에서 버튼이 하나만 있을 때, 아래의 이미지와 같이 하나의 버튼으로 너비가 가득 차버리게 되었다.
하나의 버튼만 있을 경우, 하나의 버튼이 너비를 가득 채우지 않도록 하기위해 display 대신 visibility 속성을 도입하였다.
// PostPrevNextBtn.tsx
import styled from "@emotion/styled";
import { Link } from "gatsby";
const PostPrevNextBtnWrapper = styled(Link)<({ label: string, slug: string })>`
display: flex;
// slug가 없을 경우 (가장 맨 앞 포스트로서 이전글이 없음, 가장 맨 뒤 포스트로서 다음글이 없음)
// visibility: hidden
// slug가 있을 경우
// visibility: visible
visibility: ${({ slug }) => slug === "" ? "hidden" : "visible"};
flex-direction: column;
gap: 12px;
width: 100%;
height: auto;
padding: 16px;
background-color: ${({ theme }) => theme.colors.background.prevNext};
border-radius: 12px;
transition: all 0.1s linear;
text-align: ${({ label }) => label === "다음글 >" ? "right" : "left"};
&:hover {
background-color: ${({ theme }) => theme.colors.background.button};
}
`;
// ...
visibility: hidden으로 처리한 버튼의 모습
1. 정리
| 속성 | display | visibility |
|---|---|---|
| 기능 | 요소를 화면에서 완전히 제거 | 요소를 보이지 않게 하지만 화면에 남아있음 |
| 레이아웃 | 요소가 문서 흐름에서 사라짐 | 요소는 여전히 문서의 흐름에 남아있음 |
| 공간차지 | 요소가 차지하는 공간이 사라짐 | 요소가 차지하는 공간은 그대로 유지됨 |
Sources
- mdn 공식문서 : visibility
https://developer.mozilla.org/ko/docs/Web/CSS/visibility
- JeonggonCho_Blog 템플릿 레포지토리
Blog 포스트 (17)
블로그 개발 - Gatsby로 직접 만든 블로그블로그 개발 - 기술 스 택 선택하기블로그 개발 - 테마 (theme) 설정하기블로그 개발 - Gatsby에서 이미지 처리하기블로그 개발 - 탭 기능 만들기블로그 개발 - Top 버튼 만들기블로그 개발 - 태그 숨기기블로그 개발 - GraphQL 쿼리하기블로그 개발 - URL 파싱블로그 개발 - Slug 적용하기블로그 개발 - 마크다운(Markdown) 문서를 HTML로 출력하기블로그 개발 - favicon 출력하기블로그 개발 - 메타 태그 도입하기블로그 개발 - 검색 기능 개발하기블로그 개발 - display: none과 visibility: hidden 차이 (feat. 다음, 이전 버튼)블로그 개발 - 블로그 목차 TOC (Table Of Contents) 도입하기블로그 개발 - 페이지네이션 (Pagination) 구현하기
