Post Detail Page

uiux

Next.js로 기술 블로그 만들기-반응형 UI를 고려한 Grid System 적용하기

반응형 디자인

블로그 디자인이 복잡하지 않으며, 디바이스가 변경되더라도 콘텐츠 일부가 변경되거나 재구성될 필요가 없기 때문에 화면 크기별로 고유한 레이아웃을 만들 필요가 없다.

따라서 적응형 디자인이 아닌 디바이스의 해상도에 따라 레이아웃이 유연하게 대응하는 반응형 디자인으로 진행하기로 했다.

Grid System

그리드 시스템에 정답은 없으므로 사이트 특징에 맞게 적용하면 된다. 주로 랜딩페이지는 1440 그리드 시스템을 많이 사용했었지만 블로그의 특성상 컨텐츠 영역이 너무 넓으면 내용이 한눈에 들어오지 않는 문제가 있어 960px, 12컬럼으로 설정했다.

my-blog-3-image
960px | 12 columns
  • 적용 페이지: Landing, Posts
  • Container: 960px
  • Columns : 12
  • Gutter: 20px
  • Column : 60px

📐 variables 정의

그리드가 적용된 className을 전역 변수로 선언 후 모든 페이지에서 동일한 클래스명으로 접근 가능하도록 SCSS를 설정해야 한다. 먼저 각 디바이스 별로 그리드를 어떻게 적용할지 작성 후 순차적으로 코드로 옮겨보자.

📱 Mobile ( < 768px )
* columns····················4
* gutter·····················20px
* margin·····················6px
* container-size·············100% - (6px * 2)

💻 Tablet ( < 1024px )
* columns····················12
* gutter·····················20px
* margin·····················30px
* container-size·············100% - (30px * 2)

🖥️ Desktop ( > 1023px )
* of columns·················12
* gutter·····················20px
* column·····················60px
* margin·····················auto
* max-container-size·········960px

위의 작성된 내용을 기준으로 column, gutter, margin, max-width를 variables로 선언한다.
모든 디바이스에서 공통으로 사용되는 gutter는 하나의 변수로 선언해 준다.

$gutter: 20px;

$mobile-columns: 4;
$mobile-margin: 6px;
$mobile-max-width: 100%;

$tablet-columns: 12;
$tablet-margin: 30px;
$tablet-max-width: 960px + $tablet-margin * 2;

$pc-columns: 12;
$pc-column: 60px;
$pc-max-width: ($pc-column + $gutter) * $pc-columns;

📐 Column 설정하기

컬럼은 col-${컬럼 수} 형태의 클래스를 가지게 되는데 양옆 거터 10px씩 총 20px을 적용한다

@use 'sass:math';

.container {
  max-width: $pc-max-width;
  margin: 0 auto;

  [class^='col-'] {
    padding: 0 calc($gutter / 2); // 컬럼 양 옆 10px씩 총 20px의 거터값이 적용 됨
  }

  @for $i from 1 through $pc-columns {
    .col-#{$i} {
      width: ($pc-column + $gutter) * $i;
    }
  }

  @include responsive(T) { // 그리드 테블릿 반응형 }
  @include responsive(M) { // 그리드 모바일 반응형}
}

🌟 [class^='col-']
col-4, col-12 등 col-로 시작하는 모든 클래스의 동일한 스타일 적용이 가능하다.

my-blog-3-image
my-blog-3-image
양 옆 gutter 10px 반영

📐 Container 컴포넌트

landing, post 페이지뿐만아니라 특정 컴포넌트에도 사용되기 때문에, children props를 받아 필요한 컴포넌트에 적용할 수 있도록 레이아웃 공용 컴포넌트로 구현했다.

const Container = ({ children }: ContainerProps) => {
  return (
    <div className='container'>
      <div className='row'>
        <div className='col-12'>{children}</div>
      </div>
    </div>
  );
};

export default Container;

Layout

my-blog-3-image

Color

개인적으로 다크 모드를 선호하고 프로젝트의 전반적인 컨셉이 다크였기 때문에 라이트 모드는 고려하지 않았다.
너무 많은 컬러는 identity에 좋지 않고, 무엇보다 피로감을 유발할 수 있기 때문에 메인 컬러인 primary와 두 종류의 시스템 컬러로 구성했다.

my-blog-3-image

📂 styles > variables > _colors.scss

// Primary
$primary: #00d78a;
$ggf-primary: #adff00;
$ticky-tocky-primary: #37e8b4;
$rolling-primary: #a64eff;

// System
$yellow: #ffcc4a;
$yellow-dark: #ffae1b;
$red: #ff7676;
$red-dark: #f64a4a;

// Grayscale
$white: #fff;
$white10: #dedede;
$gray20: #aeaeae;
$gray50: #5e666d;
$gray80: #272727;
$black: #101010;
$black10: #0b0b0b;

// Opacity
$opacity-white-2: rgb(255 255 255 / 2%);
$opacity-white-4: rgb(255 255 255 / 4%);
$opacity-white-10: rgb(255 255 255 / 10%);
$opacity-white-70: rgb(255 255 255 / 70%);
$opacity-yellow-2: rgb(255 184 184 / 2%);
$opacity-yellow-12: rgb(255 184 184 / 12%);
$opacity-red-2: rgb(228 255 119 / 2%);
$opacity-red-12: rgb(228 255 119 / 12%);
$opacity-black-80: rgb(15 16 16 / 80%);

// gradients
$card-gradient-left: linear-gradient(90deg, #070707 35%, rgb(14 14 14 / 0%) 100%);
$card-gradient-right: linear-gradient(-90deg, #070707 35%, rgb(14 14 14 / 0%) 100%);
$card-gradient-bottom: linear-gradient(0deg, #070707 16%, rgb(14 14 14 / 0%) 100%);

Typography

구글에서 제공하는 폰트들 중 퀄리티 높은 폰트들이 많은데, 내 기준 영문이 가장 깔끔한 Plus Jakarta Sans 폰트를 사용했다.

🔗 Google Font X Plus Jakarta Sans

StyleGuide-Typography-image

📂 styles > variables > _typography.scss

$font-main: 'Plus Jakarta Sans', sans-serif;
$browser-font-size: 62.5%;
$font-size-14: 1.4rem;
$font-size-16: 1.6rem;
$font-size-18: 1.8rem;
$font-size-24: 2.4rem;
$font-size-32: 3.2rem;
$font-size-40: 4rem;

📂 styles > mixins > _text-style.scss

@mixin text-style($size, $color: false, $weight: 'regular') {
  @if $size == 14 {
    @include text-style-14;
  }

  @if $size == 16 {
    @include text-style-16;
  }

  @if $size == 18 {
    @include text-style-18;
  }

  @if $size == 24 {
    @include text-style-24;
  }

  @if $size == 32 {
    @include text-style-32;
  }

  @if $size == 40 {
    @include text-style-40;
  }

  @if type-of($color) == color {
    color: $color;
  }

  @if $weight == 'semiBold' {
    font-weight: 600;
  }

  @if $weight == 'bold' {
    font-weight: 700;
  }
}

마무리하며

랜딩 페이지와 포스트 페이지, 두 개의 화면을 구현하는데 그리드 시스템에 대해 생각보다 많은 고민을 했다.
초기 랜딩 페이지 기준 너비를 1440px로 설정했으나 블로그 특성상 컨텐츠 영역이 너무 넓으면 내용이 한눈에 들어오지 않는 문제가 있어 여러 가지 실험을 시도하다 보니 예상보다 많은 시간을 소요하게 됐다.

좀 더 효율적인 방법으로 구현하려는 마음으로 시작했는데 그리드 외에도 슬라이드 배너의 카테고리별 포스팅 개수, 태그의 역할, 필터의 사용성 등 여전히 고민해야 될 부분이 많다.