새로운 Snap.svg를 사용한 스타일링 및 속성 (기초 - 파트 2)

발행: (2025년 12월 16일 오전 04:52 GMT+9)
7 min read
원문: Dev.to

Source: Dev.to

Introduction

이 글은 Snap.svg 시리즈의 두 번째 튜토리얼입니다. 첫 번째 파트에서는 g(), g_a(), Snap.FORCE_AFTER를 사용해 계층적인 SVG 구조를 만드는 방법을 배웠습니다. 이제는 다음과 같이 모양을 보기 좋게 만들기 위해 배워보겠습니다:

  • attr()를 이용해 fill, stroke, opacity 등 시각 속성을 설정하기
  • setStyle()style 속성에 직접 인라인 스타일 적용하기
  • 스타일 우선순위 계층(인라인 스타일 > CSS > 속성) 이해하기
  • addClass(), removeClass(), toggleClass()로 CSS 클래스를 관리하기
  • getId()로 요소 ID를 자동 생성·조회하기
  • 사용자 클릭에 반응하는 인터랙티브 색상 팔레트 만들기

핵심은 Snap.svg가 세밀한 제어를 제공한다는 점이며, 각각의 접근 방식에 맞는 명확한 메서드를 제공한다는 점입니다.

Forked + extended Snap.svg:
Access to the library:

1. Understanding the Style Precedence Hierarchy

코드에 들어가기 전에, 여러 소스가 같은 속성을 정의했을 때 브라우저가 어떤 스타일을 적용할지 결정하는 방식을 이해하는 것이 중요합니다. 우선순위는 다음과 같습니다:

  1. 인라인 style 속성 (가장 높은 우선순위)
  2. CSS 규칙 (<style> 태그 혹은 외부 스타일시트)
  3. SVG 프레젠테이션 속성 (예: fill="red")

즉:

  • setStyle()(인라인 스타일)은 모든 CSS 규칙이나 속성을 덮어씁니다.
  • CSS 규칙은 프레젠테이션 속성을 덮어씁니다.
  • 프레젠테이션 속성은 기본값이며 가장 낮은 우선순위를 가집니다.

Snap.svg는 이 계층 구조를 그대로 따르며, 각 레벨을 명시적으로 다룰 수 있는 메서드를 제공합니다.

2. Basic Attribute Styling with attr()

attr() 메서드는 속성의 getter와 setter 역할을 동시에 합니다. 값이 프레젠테이션 속성으로 설정될지, style 속성으로 라우팅될지는 상황에 맞게 자동 판단합니다. 이 방식은 가장 낮은 우선순위를 가지지만 SVG 요소를 스타일링하는 가장 일반적인 방법입니다.

Example: Colored Rectangles with Attributes

// basic-attr.js
var s = Snap("#mySvg");

// Create a group to hold our shapes
var group = s.g().attr({ id: "attrGroup" });

// Rectangle 1: Basic fill and stroke via attr() - object syntax
group
  .rect(20, 20, 80, 60)
  .attr({
    fill: "#3498db",        // blue fill
    stroke: "#2c3e50",      // dark border
    strokeWidth: 2
  });

// Rectangle 2: Using attr() with key‑value syntax (alternative way)
var rect2 = group.rect(120, 20, 80, 60);
rect2.attr("fill", "#e74c3c");           // Set fill
rect2.attr("opacity", 0.7);              // Set opacity
rect2.attr("stroke", "#c0392b");
rect2.attr("strokeWidth", 3);
rect2.attr("strokeDasharray", "5,3");    // dashed: 5px dash, 3px gap

// Rectangle 3: No fill, thick rounded stroke
group
  .rect(220, 20, 80, 60)
  .attr({
    fill: "none",
    stroke: "#2ecc71",
    strokeWidth: 4,
    strokeLinecap: "round",  // rounded ends
    strokeLinejoin: "round"   // rounded corners
  });

// Rectangle 4: Gradient‑ready (using a solid color for now)
group
  .rect(320, 20, 80, 60)
  .attr({
    fill: "#f39c12",
    stroke: "#e67e22",
    strokeWidth: 2,
    rx: 10,                  // rounded corners
    ry: 10
  });

Output: 네 개의 사각형이 일렬로 배치되며, 각각 다른 fill, stroke, opacity 설정이 속성으로 적용됩니다.

attr() as Getter and Setter

// Setter
element.attr("fill", "red");                     // single attribute
element.attr({ fill: "red", opacity: 0.5 });    // multiple attributes

// Getter
var currentFill = element.attr("fill");
var currentOpacity = element.attr("opacity");

Using attr_force() for Pure Presentation Attributes

attr()는 일부 속성을 CSS와의 호환성을 위해 style 속성으로 라우팅할 수 있습니다. 마크업에 프레젠테이션 속성으로 반드시 남겨야 할 경우에는 attr_force()를 사용합니다:

// Smart attr() – may route to style or attribute
element.attr("fill", "blue");

// Force as presentation attribute
element.attr_force("fill", "blue");  // Guarantees a presentation attribute

When to use attr_force()

  • 프레젠테이션 속성이 downstream SVG 조작에 필요할 때
  • CSS가 값을 쉽게 덮어쓸 수 있게 하고 싶을 때 (속성은 가장 낮은 우선순위)
  • SVG 편집기나 도구가 프레젠테이션 속성을 기대할 때

Common Attributes

  • Fill: fill – 색상, 그라디언트, 패턴, 혹은 "none"
  • Stroke: stroke, strokeWidth, strokeDasharray, strokeLinecap, strokeLinejoin
  • Opacity: opacity (0 – 1), fillOpacity, strokeOpacity
  • Geometry: 요소별 x, y, width, height, rx, ry, r, cx, cy

3. Inline Styles with setStyle() – Flexible Input

setStyle() 메서드는 요소의 style 속성에 직접 값을 설정하므로 캐스케이드에서 가장 높은 우선순위를 가집니다. 다양한 입력 형식을 지원합니다.

Multiple Ways to Use setStyle()

// inline-style.js
var s = Snap("#mySvg");
var group = s.g().attr({ id: "styleGroup" });

// Create circles for demonstration
var circle1 = group.circle(60, 140, 30);
var circle2 = group.circle(160, 140, 30);
var circle3 = group.circle(260, 140, 30);
var circle4 = group.circle(360, 140, 30);

// Method 1: Object with multiple properties
circle1.setStyle({
  fill: "red",
  stroke: "#c0392b",
  strokeWidth: 3,
  opacity: 0.8
});

// Method 2: Single property with key‑value syntax
circle2.setStyle("fill", "green");
circle2.setStyle("strokeWidth", "2");
circle2.setStyle("stroke", "#27ae60");

// Method 3: CSS string (like inline style attribute)
circle3.setStyle("fill: blue; stroke: navy; stroke-width: 2;");

// Method 4: Mixed – object for one property, then key‑value
circle4.setStyle({ fill: "orange" });
circle4.setStyle("stroke", "darkorange");

// All circles have inline styles that override any CSS or attributes

Understanding the Flexibility

// Object notation (most common)
element.setStyle({
  fill: "purple",
  strokeWidth: 4,
  opacity: 0.5
});

// Property‑value pairs (useful for single properties)
element.setStyle("fill", "purple");
element.setStyle("strokeWidth", 4);
element.setStyle("opacity", 0.5);

// CSS string (useful when copying from CSS)
element.setStyle("fill: purple; stroke-width: 4; opacity: 0.5");

// Note: CSS properties use hyphens (stroke-width), but object properties use camelCase (strokeWidth)

Demonstrating Style Override

setStyle()로 적용한 인라인 스타일은 attr()로 설정한 속성을 덮어씁니다:

// Start with attributes
var rect = s.rect(50, 200, 100, 50).attr({
  fill: "#3498db",
  stroke: "#2c3e50",
  strokeWidth: 2
});

// Apply an inline style that overrides the fill
rect.setStyle("fill", "orange");

// Result: The rectangle appears orange, despite the earlier attribute fill.
Back to Blog

관련 글

더 보기 »

React를 이용한 계산기

오늘 나는 React를 사용한 계산기 연습 프로젝트 중 하나를 완료했습니다. 이 React Calculator 애플리케이션은 기본 산술 연산을 수행합니다. 버튼을 지원합니다.