icon
2장 : HTML 기초와 심화

SVG와 캔버스 기초


지금까지 우리는 HTML을 사용하여 웹 페이지의 구조를 만들고, 텍스트, 링크, 일반 이미지(<img>), 그리고 비디오/오디오와 같은 멀티미디어 콘텐츠를 삽입하는 방법을 학습했습니다. 이제는 웹에서 그래픽을 다루는 두 가지 강력한 기술인 SVG와 Canvas에 대해 알아볼 차례입니다.

HTML5는 웹 표준만으로도 복잡하고 동적인 그래픽을 웹 페이지에 구현할 수 있는 길을 열었습니다. 이 장에서는 벡터 기반 그래픽의 대표주자인 SVG(Scalable Vector Graphics) 와 픽셀 기반 그래픽을 위한 Canvas의 기본적인 개념과 각각의 장단점, 그리고 간단한 사용법을 살펴보겠습니다. 이 두 기술은 웹 애플리케이션에서 다이어그램, 차트, 게임, 인터랙티브 애니메이션 등 다양한 시각적 요소를 구현하는 데 필수적인 기반이 됩니다.


SVG: 확장 가능한 벡터 그래픽

SVG는 XML 기반의 벡터 그래픽을 웹에 표현하기 위한 마크업 언어입니다. '벡터 그래픽'이라는 것은 그림을 점, 선, 면 등의 수학적인 형태로 정의한다는 의미입니다. JPG, PNG와 같은 '비트맵 그래픽'(픽셀 기반)과는 근본적으로 다릅니다.

SVG의 특징 및 장점

확장성 (Scalable): 가장 큰 특징이자 장점입니다. 벡터 방식이므로 아무리 확대해도 이미지가 깨지거나 흐려지지 않습니다. 로고, 아이콘, 다이어그램 등 다양한 해상도의 기기에서 선명하게 보여야 하는 그래픽에 매우 적합합니다.

작은 파일 크기: 복잡하지 않은 벡터 그래픽의 경우, 비트맵 이미지보다 파일 크기가 훨씬 작아 로딩 속도를 개선할 수 있습니다.

편집 용이성: SVG 코드는 XML 기반의 텍스트이므로, 텍스트 편집기나 SVG 편집 소프트웨어에서 쉽게 수정할 수 있습니다. 또한 CSS와 자바스크립트를 사용하여 색상, 크기, 위치 등을 동적으로 제어하고 애니메이션을 적용할 수 있습니다.

웹 접근성: SVG 요소는 의미론적인 정보(예: <title>, <desc>)를 포함할 수 있어, 스크린 리더와 같은 보조 기술이 그래픽의 내용을 이해하는 데 도움을 줍니다.

검색 가능: SVG는 텍스트 기반이므로, 검색 엔진이 이미지 내부의 텍스트를 인식할 수 있어 SEO에 유리할 수 있습니다.

SVG 기본 문법과 활용

SVG는 HTML 문서 내에 <svg> 태그를 사용하여 직접 삽입하거나, .svg 파일로 저장하여 <img> 태그나 CSS의 background-image 속성을 통해 참조할 수 있습니다. 여기서는 HTML 내에 직접 삽입하는 방식을 위주로 살펴봅니다.

  • <svg> 태그: SVG 그래픽을 그릴 캔버스 역할을 합니다. widthheight 속성으로 영역을 지정합니다.

    <svg width="200" height="200">
    </svg>
  • 기본 도형 그리기

    • <rect> (직사각형): x, y, width, height, fill, stroke, stroke-width 등의 속성을 사용합니다.
      <svg width="200" height="100">
          <rect x="10" y="10" width="80" height="80"
                fill="blue" stroke="black" stroke-width="3" />
      </svg>
    • <circle> (원): cx, cy (중심점 좌표), r (반지름), fill, stroke 등의 속성을 사용합니다.
      <svg width="200" height="100">
          <circle cx="50" cy="50" r="40" fill="red" stroke="purple" stroke-width="2" />
      </svg>
    • <line> (선): x1, y1 (시작점), x2, y2 (끝점), stroke, stroke-width 등의 속성을 사용합니다.
      <svg width="200" height="100">
          <line x1="10" y1="10" x2="190" y2="90" stroke="green" stroke-width="4" />
      </svg>
    • <polygon> (다각형): points 속성에 점들의 좌표를 공백으로 구분하여 나열합니다.
      <svg width="200" height="200">
          <polygon points="100,10 190,90 10,90" fill="orange" stroke="brown" stroke-width="2" />
      </svg>
    • <text> (텍스트): x, y (텍스트 시작 좌표), fill, font-size 등의 속성을 사용합니다.
      <svg width="200" height="100">
          <text x="10" y="50" fill="darkblue" font-size="20">Hello SVG!</text>
      </svg>
  • CSS와 자바스크립트를 이용한 제어: SVG 요소는 HTML 요소와 마찬가지로 CSS로 스타일링하거나 자바스크립트로 조작할 수 있습니다.

    <style>
        .my-circle {
            fill: #ffd700; /* 금색 */
            stroke: #cc0000;
            stroke-width: 5;
            transition: fill 0.3s ease; /* 호버 시 색상 변화 애니메이션 */
        }
        .my-circle:hover {
            fill: #ff4500; /* 오렌지색 */
        }
    </style>
    
    <svg width="100" height="100">
        <circle cx="50" cy="50" r="40" class="my-circle" id="interactiveCircle" />
    </svg>
    
    <script>
        const circle = document.getElementById('interactiveCircle');
        circle.addEventListener('click', () => {
            alert('SVG 원을 클릭했습니다!');
            circle.setAttribute('r', '50'); // 반지름 변경
        });
    </script>

Canvas: 비트맵 그래픽 그리기

Canvas는 HTML5에서 도입된 <canvas> 태그와 자바스크립트 API를 사용하여 비트맵(픽셀) 기반의 2D 그래픽을 웹 페이지에 직접 그릴 수 있도록 하는 기술입니다. '캔버스'라는 이름처럼, 마치 그림을 그리는 도화지와 같습니다.

Canvas의 특징 및 장점

픽셀 기반: 이미지를 픽셀 단위로 직접 조작합니다. 복잡한 그래픽, 이미지 필터, 게임 그래픽 등 픽셀 단위의 정교한 제어가 필요할 때 적합합니다.

자바스크립트 제어: 모든 그리기는 자바스크립트 코드를 통해 이루어집니다. 이를 통해 매우 동적이고 인터랙티브한 그래픽을 생성할 수 있습니다.

고성능: 복잡한 애니메이션이나 게임처럼 빠른 업데이트가 필요한 경우, Canvas는 웹 브라우저의 GPU 가속을 활용하여 높은 성능을 발휘할 수 있습니다.

다양한 활용: 차트, 그래프, 사진 편집기, 게임, 웹 기반 드로잉 툴 등 다양한 웹 애플리케이션에서 활용됩니다.

Canvas 기본 문법과 활용

  • <canvas> 태그: 그림을 그릴 영역을 정의합니다. widthheight 속성으로 캔버스의 크기를 지정합니다.

    <canvas id="myCanvas" width="400" height="200" style="border:1px solid #000;"></canvas>
    • <canvas> 태그 자체는 비어 있습니다. 모든 그리기 작업은 자바스크립트를 통해 이루어집니다.
    • style 속성은 단순히 캔버스 요소 자체의 시각적 스타일을 지정할 뿐, 캔버스 내부의 그림에는 영향을 주지 않습니다.
  • 자바스크립트를 이용한 그리기

    캔버스 요소 가져오기: document.getElementById()를 사용하여 <canvas> 요소를 가져옵니다.

    렌더링 컨텍스트 얻기: 캔버스에 그림을 그리기 위한 '컨텍스트' 객체를 얻습니다. 2D 그래픽의 경우 getContext('2d')를 사용합니다.

    그리기 명령 실행: 컨텍스트 객체의 메서드를 사용하여 도형, 텍스트, 이미지 등을 그립니다.

    <canvas id="myDrawingCanvas" width="300" height="150" style="border:2px solid #ccc;"></canvas>
    <script>
        const canvas = document.getElementById('myDrawingCanvas');
        const ctx = canvas.getContext('2d'); // 2D 렌더링 컨텍스트 가져오기
        // 1. 사각형 그리기
        ctx.fillStyle = 'green'; // 채우기 색상 설정
        ctx.fillRect(10, 10, 100, 50); // (x, y, width, height)
        // 2. 원 그리기
        ctx.beginPath(); // 새로운 경로 시작
        ctx.arc(180, 75, 40, 0, 2 * Math.PI); // (x, y, 반지름, 시작각도, 끝각도)
        ctx.fillStyle = 'orange';
        ctx.fill(); // 채우기
        ctx.lineWidth = 3; // 선 두께
        ctx.strokeStyle = 'red'; // 선 색상
        ctx.stroke(); // 선 그리기
        // 3. 텍스트 그리기
        ctx.font = '24px Arial';
        ctx.fillStyle = 'darkblue';
        ctx.textAlign = 'center';
        ctx.fillText('Hello Canvas!', canvas.width / 2, 130); // (텍스트, x, y)
    </script>

SVG와 Canvas의 차이점 및 선택 기준

특징SVG (Scalable Vector Graphics)Canvas
기반벡터 기반 (수학적 도형, XML 코드)비트맵/픽셀 기반 (래스터 이미지)
조작 방식각 도형이 DOM 요소로 존재, CSS/JS로 개별 조작 용이전체 캔버스를 하나의 비트맵으로 JS로 픽셀 조작
확장성무한히 확대해도 깨지지 않음 (해상도 독립적)확대하면 픽셀이 보이며 깨짐 (해상도 의존적)
성능복잡한 장면에서 많은 요소가 있으면 성능 저하 가능대량의 픽셀 조작 및 애니메이션에 고성능
주요 용도로고, 아이콘, 다이어그램, 일러스트, 인터랙티브 차트게임, 이미지 편집, 복잡한 데이터 시각화
접근성요소 자체가 의미를 가지므로 접근성 높음캔버스 자체는 이미지이므로 접근성 고려 필요
파일 크기단순한 그래픽은 작고, 복잡한 그래픽은 커질 수 있음해상도와 내용에 따라 다름

언제 무엇을 사용할까?

  • SVG
    • 로고, 아이콘, 지도를 포함한 확장성이 필요한 그래픽.
    • 데이터 변화에 따라 요소별로 색상이나 크기를 바꿔야 하는 인터랙티브 차트/다이어그램.
    • 간단한 애니메이션이나 상태 변화를 CSS/JS로 제어할 필요가 있는 경우.
    • 검색 엔진이나 스크린 리더가 그래픽 내용을 이해해야 하는 경우.
  • Canvas
    • 픽셀 단위의 정교한 그래픽 제어가 필요한 경우 (이미지 필터, 사진 편집기).
    • 높은 프레임 속도를 요구하는 게임이나 복잡한 애니메이션.
    • 수백, 수천 개의 요소가 동적으로 생성/소멸되어야 하는 대규모 데이터 시각화.
    • 그려진 결과물만 중요하고, 각 객체에 대한 개별적인 DOM 조작이 불필요한 경우.

실습: 간단한 Canvas 애니메이션 만들기

두 기술의 기본적인 차이를 직접 경험해 봅시다.

새 파일 준비

  • web-dev-practice 폴더 안에 graphics_playground.html 파일을 새로 생성합니다.

HTML 구조와 SVG, Canvas 코드 작성

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SVG와 Canvas 기초 실습</title>
    <style>
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            margin: 20px;
            background-color: #f8f8f8;
            color: #333;
            text-align: center;
        }
        .container {
            max-width: 900px;
            margin: 20px auto;
            background-color: white;
            padding: 30px;
            border-radius: 10px;
            box-shadow: 0 4px 12px rgba(0,0,0,0.1);
            display: flex;
            flex-wrap: wrap;
            justify-content: space-around;
            gap: 30px;
        }
        section {
            flex: 1 1 45%; /* 유연하게 공간 차지, 최소 너비 45% */
            min-width: 350px;
            padding: 20px;
            border: 1px solid #eee;
            border-radius: 8px;
            background-color: #fafafa;
        }
        h1 {
            color: #007bff;
            margin-bottom: 40px;
        }
        h2 {
            color: #0056b3;
            margin-top: 0;
        }
        svg {
            display: block;
            margin: 20px auto;
            border: 1px solid #ccc;
            background-color: #fff;
            border-radius: 5px;
        }
        .svg-icon-example {
            display: inline-block; /* 아이콘들이 한 줄에 있도록 */
            margin: 10px;
            padding: 10px;
            border: 1px solid #eee;
            border-radius: 5px;
            transition: transform 0.2s ease-out;
        }
        .svg-icon-example:hover {
            transform: scale(1.1);
            box-shadow: 0 0 8px rgba(0,0,0,0.1);
        }
        .svg-icon-example svg {
            border: none; /* 개별 아이콘은 보더 제거 */
            margin: 0;
        }
        canvas {
            border: 1px solid #ccc;
            background-color: #fff;
            border-radius: 5px;
            display: block;
            margin: 20px auto;
        }
        button {
            padding: 10px 20px;
            background-color: #28a745;
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            font-size: 1em;
            margin-top: 15px;
            transition: background-color 0.3s ease;
        }
        button:hover {
            background-color: #218838;
        }
    </style>
</head>
<body>
    <h1>SVG와 Canvas 기초 실습</h1>

    <div class="container">
        <section>
            <h2>SVG 아이콘 예시 (벡터 그래픽)</h2>
            <p>SVG는 확대해도 깨지지 않는 선명한 벡터 이미지를 제공합니다.</p>

            <div class="svg-icon-example" title="홈 아이콘">
                <svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                    <path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path>
                    <polyline points="9 22 9 12 15 12 15 22"></polyline>
                </svg>
            </div>

            <div class="svg-icon-example" title="사용자 아이콘">
                <svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                    <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
                    <circle cx="12" cy="7" r="4"></circle>
                </svg>
            </div>

            <div class="svg-icon-example" title="메일 아이콘">
                <svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                    <path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"></path>
                    <polyline points="22,6 12,13 2,6"></polyline>
                </svg>
            </div>

            <h3>간단한 SVG 도형 그리기</h3>
            <svg width="200" height="150">
                <rect x="20" y="20" width="60" height="60" fill="#ff7f50" stroke="#cd5b45" stroke-width="3">
                    <title>주황색 사각형</title>
                </rect>
                <circle cx="150" cy="75" r="50" fill="#6a5acd" stroke="#483d8b" stroke-width="3">
                    <title>보라색 원</title>
                </circle>
                <text x="100" y="140" text-anchor="middle" font-size="18" fill="#333">SVG 도형들</text>
            </svg>
        </section>

        <section>
            <h2>Canvas 애니메이션 예시 (비트맵 그래픽)</h2>
            <p>Canvas는 자바스크립트로 픽셀 단위의 동적인 그림을 그립니다.</p>

            <canvas id="animatedCanvas" width="350" height="200"></canvas>
            <button id="startButton">애니메이션 시작/정지</button>

            <script>
                const canvas = document.getElementById('animatedCanvas');
                const ctx = canvas.getContext('2d');
                const startButton = document.getElementById('startButton');

                let animationFrameId; // requestAnimationFrame ID
                let x = 50;
                let dx = 2; // x 방향 속도
                let radius = 20;

                function drawCircle() {
                    ctx.clearRect(0, 0, canvas.width, canvas.height); // 캔버스 지우기
                    ctx.beginPath();
                    ctx.arc(x, canvas.height / 2, radius, 0, Math.PI * 2);
                    ctx.fillStyle = 'blue';
                    ctx.fill();
                    ctx.closePath();
                }

                function animate() {
                    drawCircle();
                    x += dx;

                    // 벽에 부딪히면 방향 반전
                    if (x + radius > canvas.width || x - radius < 0) {
                        dx = -dx;
                    }
                    animationFrameId = requestAnimationFrame(animate); // 다음 프레임 요청
                }

                let isAnimating = false;
                startButton.addEventListener('click', () => {
                    if (isAnimating) {
                        cancelAnimationFrame(animationFrameId); // 애니메이션 정지
                        startButton.textContent = '애니메이션 시작';
                    } else {
                        animate(); // 애니메이션 시작
                        startButton.textContent = '애니메이션 정지';
                    }
                    isAnimating = !isAnimating;
                });

                // 페이지 로드 시 초기 상태 그리기
                drawCircle();
            </script>
        </section>
    </div>
</body>
</html>

결과 확인

  • Live Server를 통해 graphics_playground.html 파일을 열어보세요.
  • SVG 섹션에서는 다양한 아이콘과 도형이 선명하게 보일 것입니다. 브라우저에서 확대/축소해도 깨지지 않는지 확인해 보세요.
  • Canvas 섹션에서는 '애니메이션 시작' 버튼을 눌러 원이 좌우로 움직이는 간단한 애니메이션을 확인해 보세요.

이번 장에서는 웹에서 그래픽을 다루는 두 가지 강력한 기술인 SVG와 Canvas에 대해 알아보았습니다. SVG가 벡터 기반으로 확장성과 편집 용이성에 강점이 있다면, Canvas는 픽셀 기반으로 복잡한 동적 그래픽과 고성능 게임 구현에 유리하다는 것을 이해하셨을 것입니다.