GODRICH
#css애니메이션#버튼#로딩#전환효과#스크롤#대시보드#실전ui#디자인트렌드

네오브루탈리즘 UI 랜딩 부품 9개, 그림자는 안 번진다

네오브루탈리즘 UI는 두꺼운 먹색 테두리와 번짐 없는 직각 그림자, 채도 높은 원색 블록으로 화면을 가감 없이 드러내는 디자인 스타일입니다.

브루탈리즘 디자인의 거친 골격을 원색과 그림자로 다듬은 이 룩이 핀터레스트·드리블 저장 탭을 가장 많이 채웁니다. 직접 짠 원페이지를 먼저 붙였으니, 위 내비 바부터 아래 저작권 줄까지 화면을 한 번 내려보며 전체 톤을 눈에 담아 보십시오. 그림자에 블러가 없다는 것부터 걸릴 겁니다.

새 창에서 원페이지 열기

이 원페이지 하나를 아홉 조각으로 쪼개 아래 격자에 다시 늘어놓았습니다. 순서는 인기투표가 아니라 화면을 처음 여는 사람이 지나가는 동선—눈에 걸리기, 둘러보기, 값 확인하기, 믿을 근거 찾기, 등 떠밀리기, 등록하기—그대로입니다. 아홉 개 중 넷(히어로·번호 배지·요금·버튼)은 흔한 카드 나열이 아니라 회전이나 그림자 이동 같은 동작이 붙은 아이디어형입니다. 같은 design 기둥에서 이 직각 그림자와 정반대로 번짐을 끝까지 밀어붙인 쪽이 오로라 그라디언트 랜딩 부품이고, 같은 원색을 금속 광택으로 바꿔 놓은 쪽이 Y2K 크롬·홀로그램 부품입니다.

자동 재생 · 눌러서 해당 항목으로 · 전부 한 zip

01오프셋 그림자 히어로

무엇이 움직이나

제목 뒤에 깔린 노란 복제본이 인쇄가 살짝 밀린 것처럼 주기적으로 어긋났다 맞물립니다.

오프셋 그림자 히어로
새 창에서 열기

01 · 오프셋 그림자 히어로 — 측정 누적면적 0.671% · 움직인 프레임 10/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

오프셋 텍스트섀도우배지 회전→0radius 0

코드에서 볼 곳

모서리의 스티커 배지는 비뚤게 놓여 있다가 탁 소리 나듯 잠깐 편평해졌다 다시 기웁니다.

<div class="relative border-[3px] border-ink bg-cream p-8 shadow-brutal">
  <span class="absolute -right-3 -top-3 border-[3px] border-ink
               bg-orange px-3 py-1 text-xs font-black text-cream">NEW</span>
  <h1 class="relative font-display text-4xl font-black leading-tight">
    <span class="absolute -left-1 -top-1 -z-10 text-yellow"
          aria-hidden="true">숨김 없는 시작</span>
    숨김 없는 시작
  </h1>
  <button class="mt-3 rounded-full border-[3px] border-ink bg-ink
                 px-6 py-3 text-sm font-black text-cream
                 shadow-[4px_4px_0_#ffd23f]">지금 시작하기</button>
</div>

02스탬프 내비

무엇이 움직이나

현재 메뉴 칸이 도장을 찍듯 확 커졌다 제자리로 튕기며 색 블록으로 들어찹니다.

스탬프 내비
새 창에서 열기

02 · 스탬프 내비 — 측정 누적면적 0.461% · 움직인 프레임 10/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

scale 오버슈트radius 0white-space: nowrap

코드에서 볼 곳

링크 글자는 화면이 좁아져도 줄바꿈 없이 한 줄로 남고, 넘치는 칸은 옆으로 밀립니다.

<nav class="flex items-center gap-4 border-[3px] border-ink bg-ink
            px-4 py-3">
  <span class="shrink-0 whitespace-nowrap font-black text-cream">SLABKIT</span>
  <div class="flex min-w-0 flex-1 gap-2 overflow-x-auto">
    <span class="shrink-0 whitespace-nowrap border-[3px] border-cream
                 bg-orange px-3 py-1.5 text-xs font-bold text-cream">홈</span>
    <span class="shrink-0 whitespace-nowrap px-3 py-1.5 text-xs
                 font-bold text-cream/70">기능</span>
  </div>
  <button class="shrink-0 whitespace-nowrap rounded-full border-[3px]
                 border-cream bg-yellow px-4 py-2 text-xs
                 font-black text-ink">시작하기</button>
</nav>

03그림자 분리 카드

무엇이 움직이나

카드마다 검정 그림자는 자리에 고정된 채 카드 몸통만 왼쪽 위로 움직여, 카드와 그림자 사이 빈틈이 늘었다 줄었다 합니다.

그림자 분리 카드
새 창에서 열기

03 · 그림자 분리 카드 — 측정 누적면적 20.788% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

그림자 고정카드만 이동radius 0

코드에서 볼 곳

네 칸은 시작 시각을 어긋내 파도처럼 순서대로 떴다 가라앉습니다.

<div class="relative">
  <div class="absolute inset-0 translate-x-2 translate-y-2 bg-ink"></div>
  <div class="relative flex flex-col gap-2 border-[3px] border-ink
              bg-cream p-4">
    <span class="block h-6 w-6 bg-blue"></span>
    <p class="text-sm font-bold">빠른 검색</p>
  </div>
</div>

04비뚤어진 번호 배지

무엇이 움직이나

항목 번호가 담긴 사각 배지가 전부 조금씩 다른 각도로 놓여 있다가, 순서대로 잠깐 똑바로 섰다가 다시 비뚤어집니다.

비뚤어진 번호 배지
새 창에서 열기

04 · 비뚤어진 번호 배지 — 측정 누적면적 0.738% · 움직인 프레임 22/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

회전 랜덤순차 정렬radius 0

코드에서 볼 곳

각도가 서로 다르다 보니 셋이 동시에 정렬되는 순간이 없어 계속 살아 있는 느낌을 줍니다.

<li class="flex items-center gap-3 border-[3px] border-ink bg-cream
           p-2 pr-5 shadow-brutal-sm">
  <span class="grid h-9 w-9 flex-none -rotate-6 place-items-center
               border-[3px] border-ink bg-blue text-xs font-black
               text-cream">01</span>
  <span class="text-sm font-bold">빠른 시작</span>
</li>

05붙여놓은 요금 카드

무엇이 움직이나

추천 플랜 카드만 살짝 기울어진 채 다른 칸 위에 포스트잇처럼 얹히고, 나머지 카드는 완전히 수평이라 기울기 하나로 추천이 눈에 띕니다.

붙여놓은 요금 카드
새 창에서 열기

05 · 붙여놓은 요금 카드 — 측정 누적면적 3.044% · 움직인 프레임 10/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

rotate 고정radius 0레이어 겹침

코드에서 볼 곳

기운 채로 숨을 쉬듯 살짝 부풀었다 가라앉아, 표 없이도 어느 쪽을 밀고 있는지 바로 압니다.

<div class="relative -ml-2 flex-[1.1] -rotate-3 border-[3px]
            border-ink bg-yellow p-6 shadow-brutal">
  <span class="absolute -top-3 left-3 border-[3px] border-ink
               bg-blue px-3 py-1 text-xs font-black text-cream">추천</span>
  <p class="font-black">프로</p>
  <p class="mt-1 text-sm text-ink/70">월 12,000원</p>
</div>

06블록 인용부호 후기

무엇이 움직이나

글자가 아니라 카드 왼쪽 한 뼘을 채우는 파란 색 블록이 텍스트 뒤 자기 레인 안에서만 미끄러져 들어왔다 나갑니다.

블록 인용부호 후기
새 창에서 열기

06 · 블록 인용부호 후기 — 측정 누적면적 1.378% · 움직인 프레임 22/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

블록 따옴표정사각 아바타radius 0

코드에서 볼 곳

아바타는 원이 아니라 두꺼운 테두리를 두른 정사각 프레임에 앉아 카드와 같은 각진 어휘를 씁니다.

<div class="relative flex-1 overflow-hidden border-[3px] border-ink
            bg-cream py-4 pl-8 pr-4 shadow-brutal-sm">
  <span class="absolute inset-y-0 left-0 w-6 bg-blue"></span>
  <p class="relative text-sm font-bold">"손끝에 감기는 느낌이에요"</p>
  <p class="relative mt-2 text-xs text-ink/60">오하늘 · 프로덕트 디자이너</p>
</div>

07행진하는 사선 CTA

무엇이 움직이나

밴드 배경 전체에 하드 에지 사선 줄무늬가 깔리고, 배경 위치만 옮겨가며 끝없이 행진합니다.

행진하는 사선 CTA
새 창에서 열기

07 · 행진하는 사선 CTA — 측정 누적면적 31.335% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

사선 스트라이프background-position 루프radius 0

코드에서 볼 곳

버튼은 완전히 불투명한 배경을 얹어 줄무늬가 지나가는 자리에서도 글자가 묻히지 않습니다.

<div class="relative overflow-hidden border-[3px] border-ink bg-ink
            px-10 py-12 shadow-brutal">
  <span class="absolute inset-0" aria-hidden="true"
        style="background-image:repeating-linear-gradient(45deg,
               #17141a 0 24px,#ffd23f 24px 48px)"></span>
  <h3 class="relative font-display text-3xl font-black
             text-cream">지금 팀에 합류시켜 보세요</h3>
</div>

08자로 그은 구분선 푸터

무엇이 움직이나

칼럼 사이 굵은 세로선이 자로 긋듯 위에서 아래로 한 번씩 그려지며 나타나고, 오래 머물다 다음 바퀴를 위해 짧게 풀립니다.

자로 그은 구분선 푸터
새 창에서 열기

08 · 자로 그은 구분선 푸터 — 측정 누적면적 0.15% · 움직인 프레임 16/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

scaleY 드로잉상단 테두리만radius 0

코드에서 볼 곳

상단 테두리만 두껍고 나머지 모서리는 전부 직각을 지킵니다.

<footer class="flex items-stretch border-t-[6px] border-ink
               bg-cream px-4 pb-6 pt-8">
  <div class="flex-1 px-2">
    <p class="mb-2 text-xs font-black text-blue">제품</p>
    <p class="text-sm font-bold">기능</p>
  </div>
  <span class="w-[3px] flex-none bg-ink"></span>
  <div class="flex-1 px-2">
    <p class="mb-2 text-xs font-black text-ink/50">회사</p>
    <p class="text-sm font-bold">소개</p>
  </div>
</footer>

09그림자 자리로 눌리는 버튼

무엇이 움직이나

버튼을 누르면 그림자 오프셋만큼 몸체가 정확히 이동하고 그림자는 동시에 0으로 줄어, 버튼이 원래 그림자가 있던 자리로 파고드는 것처럼 보입니다.

그림자 자리로 눌리는 버튼
새 창에서 열기

09 · 그림자 자리로 눌리는 버튼 — 측정 누적면적 5.142% · 움직인 프레임 19/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

press 오프셋 이동radius pill(버튼만)focus 그림자 팝

코드에서 볼 곳

입력창은 포커스 시 그림자가 0에서 뿅 나타나 테두리 색과 함께 바뀝니다.

<form class="flex gap-3 border-[3px] border-ink bg-cream p-6
            shadow-brutal">
  <input class="flex-1 border-[3px] border-ink bg-paper px-4 py-3
                text-sm" type="email" placeholder="이메일 주소">
  <button class="rounded-full border-[3px] border-ink bg-blue
                 px-5 py-3 text-sm font-black text-cream">등록하기</button>
</form>

tailwind.config 커스텀

반경은 0 아니면 완전한 원(rounded-full) 두 값만 이 한 곳에서 정하고, 그림자는 흐림 없는 하드 오프셋 유틸리티 두 개(shadow-brutal·shadow-brutal-sm)로 묶어 뒀습니다. 색도 세 원색(blue·yellow·orange)과 바탕 cream 넷뿐이라, 아홉 부품과 원페이지가 전부 같은 팔레트를 벗어나지 않습니다.

theme: {
  extend: {
    colors: {
      cream: "#fff7e6",
      ink: "#17141a",
      blue: "#2f6df6",
      yellow: "#ffd23f",
      orange: "#ff4d1f",
    },
    boxShadow: {
      brutal: "8px 8px 0 #17141a",
      "brutal-sm": "4px 4px 0 #17141a",
    },
  },
},

바이브코딩 프롬프트

위 설정을 프로젝트에 붙여 넣고, Claude Code나 Cursor에는 아래처럼 규칙 몇 줄만 던지면 됩니다. 프롬프트 전문은 zip 안 prompt.md 파일에 들어 있습니다.

모든 카드·내비·버튼·입력창의 모서리는 완전히 직각(border-radius: 0)으로 통일한다.
예외는 실제로 누르는 버튼(button 태그)만 완전히 둥근 필로 둔다.
테두리는 굵게(3px 이상) ink 색 하나로 통일한다.
그림자는 흐림 없는 하드 오프셋 하나만 쓴다. box-shadow 에 blur 반경을 절대 넣지 않는다.
카드 하나를 강조하고 싶으면 색이나 크기보다 회전(-3deg 정도)을 우선 쓴다.

위 규칙 그대로 page/index.html을 다시 짜게 한 다음, 결과 화면을 1280px 너비로 처음부터 끝까지 캡처했습니다. 아래가 그 화면입니다.

결과

어디서 깨지는가 — 함정

네오브루탈리즘 디자인, 어디서 깨지나요?

폭 320px에서 제일 먼저 문제가 났습니다. 번호 배지 목록 하나가 배지 최소 크기와 칸 사이 여백을 고정값에 가깝게 둔 탓에, 좁은 화면에서 실제 높이가 232px까지 나와 허용된 200px을 32px 넘겼습니다(Playwright로 scrollHeight 실측). 배지 크기와 여백을 더 낮은 하한을 가진 clamp()로 바꾸고 나서야 200px 안에 들어왔습니다.

다음으로 걸린 것

두 번째는 React 포트 쪽이었습니다. 구분선과 칼럼을 나란히 반환해야 하는 푸터 컴포넌트에서 import { Fragment } from "react"를 그대로 썼더니 타입 선언에 따라 "모듈에 그런 이름이 없다"는 오류가 났습니다. import React from "react" 뒤 React.Fragment로 감싸는 쪽이 어떤 설정에서도 막히지 않아 더 안전합니다.

마지막으로 걸린 것

사선 줄무늬 CTA는 background-position을 무늬 한 주기(칸 폭의 두 배)와 정확히 같은 거리만큼만 옮깁니다. 조금이라도 어긋난 거리로 움직이면 루프가 한 바퀴 돌 때마다 줄무늬가 눈에 띄게 튀어 보입니다. 번짐 없는 색 블록을 메일 본문으로 옮겼을 때 어디까지 살아남는지는 이메일 템플릿 디자인에서 따로 쟀습니다. 이 세 가지를 전부 고친 버전이 비밀번호 sfjr6qe2이 걸린 zip에 그대로 들어 있습니다.

아홉 개 데모는 동작을 줄이도록 설정한 방문자에게는 각자 다른 방식으로 멈춥니다 — 복제 텍스트·스탬프·카드 이동은 아예 멈추고, 추천 요금 카드는 MDN prefers-reduced-motion 문서가 권하는 대로 기울기(정보)는 남기고 숨쉬기(장식)만 끕니다.

접근성

챙긴 것

yellow(#ffd23f)는 배경 블록으로만 쓰고 그 위에 작은 글자를 얹지 않습니다 — 밝은 노랑 위 옅은 글자는 대비가 낮아지기 쉬워서, 작은 텍스트는 늘 ink나 cream 중 배경과 확실히 갈리는 색을 씁니다. 카드의 하드 섀도는 MDN box-shadow 문서가 설명하는 오프셋·색만 쓰고 흐림 반경은 0으로 둬, 저시력 사용자에게도 경계가 또렷하게 남습니다. 내비게이션의 브랜드·CTA에는 shrink-0 whitespace-nowrap을, 가운데 링크 묶음에는 min-w-0을 줘서 화면이 좁아져도 글자가 잘리거나 줄 중간에서 꺾이지 않습니다.

더 볼 곳

다른 유행 스타일은 디자인 트렌드 카테고리에서 볼 수 있고, 이 사이트가 뭘 다루는 곳인지는 소개 페이지에 적어 뒀습니다.

FAQ

네오브루탈리즘 스타일은 글래스모피즘·뉴모피즘과 뭐가 다른가요?

글래스모피즘은 반투명한 유리 느낌의 블러 배경을, 뉴모피즘은 배경과 거의 같은 색의 카드에 부드러운 이중 그림자를 씁니다. 네오브루탈리즘은 그 반대로 굵은 테두리와 흐림 없는 원색 블록을 그대로 드러내, 셋 중 가장 대비가 강하고 접근성 관점에서는 오히려 경계가 뚜렷해 유리합니다. 그림자 두 겹만으로 화면을 세우는 쪽은 뉴모피즘 랜딩 UI 키트에서 아홉 조각으로 따로 다뤘습니다.

그림자에 blur를 조금이라도 넣으면 안 되나요?

넣는 순간 이 스타일의 신호가 흐려집니다. box-shadow를 쓰는 자리는 전부 세 번째 값(흐림 반경)을 0으로 고정하고 오프셋과 색만 바꾸며, 그림자를 아예 고정된 색 블록(::before)으로 따로 그린 03번도 흐림 없는 하드 에지를 그대로 유지합니다.

다크 모드에서도 네오브루탈리즘이 어울리나요?

어울립니다. 다만 바탕을 ink로 뒤집고 카드는 cream이나 원색 블록을 그대로 유지해야 합니다. 그림자 색까지 밝게 바꾸면 테두리와 구분이 안 되므로, 그림자는 다크 모드에서도 ink(또는 그보다 더 짙은 색) 그대로 두는 편이 안전합니다.

압축 비밀번호를 입력하세요

비밀번호는 이 글 본문 안에 있습니다. 읽다 보면 나옵니다.