브라우저에서 이미지 크롭퍼 만들기 (간단 단계)

발행: (2026년 5월 23일 PM 04:53 GMT+9)
6 분 소요
원문: Dev.to

📄 브라우저에서 이미지 크롭퍼 만들기 (간단 단계)

프론트엔드 유틸리티를 클라이언트 측에서만 파일을 처리하도록 구축하는 것은 속도를 극대화하고 사용자 프라이버시를 보호하는 최고의 방법 중 하나입니다. 사용자가 큰 이미지를 백엔드 서버에 업로드해 크롭할 필요가 없을 때, 경험은 즉각적이라고 느껴집니다.
이 튜토리얼에서는 바닐라 HTML5, CSS3, JavaScript만 사용해 현대적이고 고성능이며 반응형인 이미지 크롭퍼를 만들겠습니다. 깔끔한 다크 스튜디오 테마와 글라스모픽 요소로 인터페이스를 스타일링해 가볍고 레이아웃 이동을 최소화합니다.

코드를 작성하기 전에, Live Image Cropper Demo에서 우리가 만들고자 하는 완전 최적화 버전을 미리 체험해 볼 수 있습니다.

복잡한 터치 제스처 로직을 직접 구현하는 대신, 업계 표준이자 가벼운 클라이언트‑사이드 크롭 라이브러리인 Cropper.js를 활용합니다.

우리 애플리케이션은 다음과 같은 간단한 흐름을 따릅니다:

  1. 파일 입력: 사용자가 최적화된 파일 입력을 통해 로컬 이미지를 선택합니다.
  2. 객체 변환: JavaScript가 로컬 파일을 Blob URL 로 변환해 서버 업로드 없이 즉시 브라우저에 표시합니다.
  3. 환경 초기화: Cropper 인스턴스를 반응형 이미지 작업 공간에 안전하게 마운트합니다.
  4. 캔버스 추출 및 내보내기: HTML5 를 이용해 선택된 좌표를 추출하고 고품질 다운로드 데이터를 출력합니다.

index.html 파일 만들기

작업 공간을 감싸는 컨테이너를 신중히 격리합니다. 이렇게 하면 크롭 환경이 로드될 때 페이지의 다른 부분이 이동하지 않도록 할 수 있습니다.

<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>클라이언트‑사이드 이미지 크롭퍼</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <div class="cropper-card">
    <div class="app-header">
      <h3>클라이언트‑사이드 이미지 크롭퍼</h3>
      <p>이미지를 즉시 업로드·조정·크롭하세요. 파일이 기기를 떠나지 않습니다.</p>
    </div>

    <div class="upload-zone">
      <label class="custom-file-upload" for="fileInput">
        이미지 파일 선택
      </label>
      <input type="file" id="fileInput" accept="image/*">
    </div>

    <div id="workspaceWrapper" class="image-workspace">
      <img id="imageToCrop" src="" alt="작업 공간 소스">
    </div>

    <div class="control-panel">
      <div class="ratio-buttons">
        <button class="btn btn-secondary">자유 비율</button>
        <button class="btn btn-secondary">1:1 정사각형</button>
        <button class="btn btn-secondary">16:9 와이드</button>
      </div>

      <div class="action-buttons">
        <button id="cropBtn" class="btn btn-primary">크롭 & 다운로드</button>
        <button id="resetBtn" class="btn btn-text">리셋</button>
      </div>
    </div>

    <div class="app-footer">
      다른 미디어 유틸리티가 필요하신가요? <a href="https://onaircode.com/image-tools/">무료 온라인 이미지 도구 모음</a>을 확인해 보세요.
    </div>
  </div>

  <script src="https://unpkg.com/cropperjs@1.5.13/dist/cropper.min.js"></script>
  <script src="script.js"></script>
</body>
</html>

style.css 파일 만들기

프리미엄 소프트웨어 느낌을 주기 위해, 차분한 다크 컬러 스킴과 깔끔한 레이아웃 경계를 사용합니다. CSS 내부의 max-width: 100% 규칙은 이미지 컨테이너가 올바르게 크기를 계산하도록 필수입니다.

/* --- Core Base Overhaul --- */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

:root {
  --canvas-bg: linear-gradient(135deg, #0b0d11 0%, #141822 100%);
  --panel-glass: rgba(26, 31, 44, 0.75);
  --panel-border: rgba(255, 255, 255, 0.06);
  --text-primary: #f8fafc;
  --text-muted: #94a3b8;
  --accent-blue: #2563eb;
  --accent-hover: #1d4ed8;
  --input-dark: #07090d;
  --radius-main: 14px;
  --transition-smooth: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}

body {
  font-family: 'Inter', sans-serif;
  background: var(--canvas-bg);
  color: var(--text-primary);
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background-attachment: fixed;
}

/* --- App Main Layout Card --- */
.cropper-card {
  background: var(--panel-glass);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border: 1px solid var(--panel-border);
  width: 100%;
  max-width: 700px;
  border-radius: var(--radius-main);
  padding: 32px;
  box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
}

.app-header {
  margin-bottom: 24px;
}

.app-header h3 {
  font-size: 1.4rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  margin-bottom: 6px;
}

.app-header p {
  color: var(--text-muted);
  font-size: 0.9rem;
  line-height: 1.5;
}

/* --- Upload Module --- */
.upload-zone {
  margin-bottom: 20px;
  text-align: center;
}

#fileInput {
  display: none;
}

.custom-file-upload {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  background: rgba(255, 255, 255, 0.04);
  border: 1px dashed rgba(255, 255, 255, 0.15);
  padding: 14px 28px;
  border-radius: 10px;
  cursor: pointer;
  font-weight: 500;
  font-size: 0.95rem;
  transition: var(--transition-smooth);
}

.custom-file-upload:hover {
  background: rgba(255, 255, 255, 0.08);
  border-color: var(--accent-blue);
}

/* --- Critical Cropper Container Config --- */
.image-workspace {
  width: 100%;
  max-height: 400px;
  background: var(--input-dark);
  border-radius: 8px;
  overflow: hidden;
  border: 1px solid var(--panel-border);
  margin-bottom: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* THIS RULE KEEPS CROPPER FRAME STABLE */
.image-workspace img {
  display: block;
  max-width: 100%;
  max-height: 400px;
}

/* --- Control Engine Grid --- */
.control-panel {
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding-bottom: 12px;
}

.ratio-buttons, .action-buttons {
  display: flex;
  gap: 10px;
}

/* --- UI Buttons Layout --- */
.btn {
  font-family: inherit;
  font-size: 0.875rem;
  font-weight: 500;
  padding: 10px 18px;
  border-radius: 8px;
  border: none;
  cursor: pointer;
0 조회
Back to Blog

관련 글

더 보기 »

내 스킬

프로젝트를 위한 AI 지시문을 만들고, 설치하고, 관리하세요 — 코딩이 필요 없습니다. CREATE 이름을 정하고, 카테고리를 선택하고, 원하는 것을 설명하세요 — 마법사가 자동으로 구성합니다.