[jquery] CSS를 사용하여 SVG 이미지의 색상을 변경하는 방법 (jQuery SVG 이미지 교체)?

이것은 내가 생각해 낸 편리한 코드의 자체 Q & A입니다.

현재 SVG 이미지를 포함하고 CSS를 통해 SVG 요소에 액세스하는 쉬운 방법은 없습니다. JS SVG 프레임 워크를 사용하는 방법에는 여러 가지가 있지만 롤오버 상태의 간단한 아이콘을 만드는 것만으로는 너무 복잡합니다.

그래서 내가 생각해 낸 것은 웹 사이트에서 SVG 파일을 사용하는 가장 쉬운 방법이라고 생각합니다. 초기 텍스트를 이미지로 대체하는 방법에서 개념을 취하지 만 SVG에 대해서는 결코 알고 있지 않은 한.

이것이 질문입니다.

JS-SVG 프레임 워크를 사용하지 않고 SVG에서 SVG를 포함시키고 색상을 변경하려면 어떻게해야합니까?



답변

먼저 HTML에 IMG 태그를 사용하여 SVG 그래픽을 포함시킵니다. 그래픽을 만들기 위해 Adobe Illustrator를 사용했습니다.

<img id="facebook-logo" class="svg social-link" src="/images/logo-facebook.svg"/>

이것은 일반 이미지를 삽입하는 방법과 같습니다. svg 클래스를 갖도록 IMG를 설정해야합니다. ‘social-link’클래스는 단지 예를위한 것입니다. ID는 필요하지 않지만 유용합니다.

그런 다음이 jQuery 코드를 사용하십시오 (별도의 파일 또는 HEAD의 인라인).

    /**
     * Replace all SVG images with inline SVG
     */
        jQuery('img.svg').each(function(){
            var $img = jQuery(this);
            var imgID = $img.attr('id');
            var imgClass = $img.attr('class');
            var imgURL = $img.attr('src');

            jQuery.get(imgURL, function(data) {
                // Get the SVG tag, ignore the rest
                var $svg = jQuery(data).find('svg');

                // Add replaced image's ID to the new SVG
                if(typeof imgID !== 'undefined') {
                    $svg = $svg.attr('id', imgID);
                }
                // Add replaced image's classes to the new SVG
                if(typeof imgClass !== 'undefined') {
                    $svg = $svg.attr('class', imgClass+' replaced-svg');
                }

                // Remove any invalid XML tags as per http://validator.w3.org
                $svg = $svg.removeAttr('xmlns:a');

                // Replace image with new SVG
                $img.replaceWith($svg);

            }, 'xml');

        });

위 코드는 ‘svg’클래스를 가진 모든 IMG를 찾아 링크 된 파일의 인라인 SVG로 대체합니다. 가장 큰 장점은 CSS를 사용하여 SVG의 색상을 다음과 같이 변경할 수 있다는 것입니다.

svg:hover path {
    fill: red;
}

필자가 작성한 jQuery 코드는 원래 이미지 ID 및 클래스를 포팅합니다. 따라서이 CSS도 작동합니다.

#facebook-logo:hover path {
    fill: red;
}

또는:

.social-link:hover path {
    fill: red;
}

http://labs.funkhausdesign.com/examples/img-svg/img-to-svg.html에서 작동하는 예를 볼 수 있습니다.

우리는 여기에 캐싱을 포함하는보다 복잡한 버전이 있습니다 :
https://github.com/funkhaus/style-guide/blob/master/template/js/site.js#L32-L90


답변

스타일

svg path {
    fill: #000;
}

스크립트

$(document).ready(function() {
    $('img[src$=".svg"]').each(function() {
        var $img = jQuery(this);
        var imgURL = $img.attr('src');
        var attributes = $img.prop("attributes");

        $.get(imgURL, function(data) {
            // Get the SVG tag, ignore the rest
            var $svg = jQuery(data).find('svg');

            // Remove any invalid XML tags
            $svg = $svg.removeAttr('xmlns:a');

            // Loop through IMG attributes and apply on SVG
            $.each(attributes, function() {
                $svg.attr(this.name, this.value);
            });

            // Replace IMG with SVG
            $img.replaceWith($svg);
        }, 'xml');
    });
});


답변

이제 대부분의 최신 브라우저 에서 IE11이 아닌 Edge를 포함 하여 CSS filter속성 을 사용할 수 있습니다 . SVG 이미지뿐만 아니라 다른 요소에서도 작동합니다. 다른 색상을 독립적으로 수정할 수는 없지만 색상을 사용 하거나 수정할 수 있습니다 . 다음 CSS 클래스를 사용하여 아이콘의 “비활성화 된”버전을 표시합니다 (원본은 채도가 높은 SVG 그림).hue-rotateinvert

.disabled {
    opacity: 0.4;
    filter: grayscale(100%);
    -webkit-filter: grayscale(100%);
}

대부분의 브라우저에서 밝은 회색으로 표시됩니다. IE (그리고 아마도 테스트하지 않은 Opera Mini)에서는 불투명 속성에 의해 눈에 띄게 희미 해집니다. 회색이 아니지만 여전히 꽤 좋아 보입니다.

다음은 Twemoji 벨 아이콘에 대한 네 가지 CSS 클래스 인 원본 (노란색), 위의 “비활성화 된”클래스 hue-rotate(녹색) 및 invert(파란색)의 예입니다.


답변

또는 당신은 CSS를 사용할 수 mask, 부여 브라우저 지원이 잘되지 않습니다하지만 당신은 대체를 사용할 수 있습니다

.frame {
    background: blue;
    -webkit-mask: url(image.svg) center / contain no-repeat;
}


답변

페이지에 파일을 포함시킬 수 있으면 (PHP 포함 또는 선택한 CMS를 통해 포함) SVG 코드를 추가하여 페이지에 포함 할 수 있습니다. 이것은 SVG 소스를 페이지에 붙여 넣는 것과 동일하게 작동하지만 페이지 마크 업을 더 깨끗하게 만듭니다.

이점은 자바 스크립트가 필요없는 CSS를 통해 SVG의 일부를 대상으로 지정할 수 있다는 것입니다.

http://codepen.io/chriscoyier/pen/evcBu

다음과 같은 CSS 규칙을 사용해야합니다.

#pathidorclass:hover { fill: #303 !important; }

!important채우기 색상을 무시 하려면 비트가 필요합니다.


답변

@Drew Baker는이 문제를 해결하기위한 훌륭한 솔루션을 제공했습니다. 코드가 제대로 작동합니다. 그러나 AngularJ를 사용하는 사람들은 jQuery에 많은 의존성을 찾을 수 있습니다. 따라서 @Drew Baker의 솔루션을 따르는 코드 인 AngularJS 사용자에게 붙여 넣는 것이 좋습니다.

동일한 코드의 AngularJs 방식

1. HTML : html 파일에 다음 태그를 사용하십시오.

<svg-image src="/icons/my.svg" class="any-class-you-wish"></svg-image>

2. 지시문 : 이것은 태그를 인식해야하는 지시문입니다.

'use strict';
angular.module('myApp')
  .directive('svgImage', ['$http', function($http) {
    return {
      restrict: 'E',
      link: function(scope, element) {
        var imgURL = element.attr('src');
        // if you want to use ng-include, then
        // instead of the above line write the bellow:
        // var imgURL = element.attr('ng-include');
        var request = $http.get(
          imgURL,
          {'Content-Type': 'application/xml'}
        );

        scope.manipulateImgNode = function(data, elem){
          var $svg = angular.element(data)[4];
          var imgClass = elem.attr('class');
          if(typeof(imgClass) !== 'undefined') {
            var classes = imgClass.split(' ');
            for(var i = 0; i < classes.length; ++i){
              $svg.classList.add(classes[i]);
            }
          }
          $svg.removeAttribute('xmlns:a');
          return $svg;
        };

        request.success(function(data){
          element.replaceWith(scope.manipulateImgNode(data, element));
        });
      }
    };
  }]);

3. CSS :

.any-class-you-wish{
    border: 1px solid red;
    height: 300px;
    width:  120px
}

4. 카르마 재스민으로 단위 테스트 :

'use strict';

describe('Directive: svgImage', function() {

  var $rootScope, $compile, element, scope, $httpBackend, apiUrl, data;

  beforeEach(function() {
    module('myApp');

    inject(function($injector) {
      $rootScope = $injector.get('$rootScope');
      $compile = $injector.get('$compile');
      $httpBackend = $injector.get('$httpBackend');
      apiUrl = $injector.get('apiUrl');
    });

    scope = $rootScope.$new();
    element = angular.element('<svg-image src="/icons/icon-man.svg" class="svg"></svg-image>');
    element = $compile(element)(scope);

    spyOn(scope, 'manipulateImgNode').andCallThrough();
    $httpBackend.whenGET(apiUrl + 'me').respond(200, {});

    data = '<?xml version="1.0" encoding="utf-8"?>' +
      '<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->' +
      '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">' +
      '<!-- Obj -->' +
      '<!-- Obj -->' +
      '<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"' +
      'width="64px" height="64px" viewBox="0 0 64 64" enable-background="new 0 0 64 64" xml:space="preserve">' +
        '<g>' +
          '<path fill="#F4A902" d=""/>' +
          '<path fill="#F4A902" d=""/>' +
        '</g>' +
      '</svg>';
    $httpBackend.expectGET('/icons/icon-man.svg').respond(200, data);
  });

  afterEach(function() {
    $httpBackend.verifyNoOutstandingExpectation();
    $httpBackend.verifyNoOutstandingRequest();
  });

  it('should call manipulateImgNode atleast once', function () {
    $httpBackend.flush();
    expect(scope.manipulateImgNode.callCount).toBe(1);
  });

  it('should return correct result', function () {
    $httpBackend.flush();
    var result = scope.manipulateImgNode(data, element);
    expect(result).toBeDefined();
  });

  it('should define classes', function () {
    $httpBackend.flush();
    var result = scope.manipulateImgNode(data, element);
    var classList = ["svg"];
    expect(result.classList[0]).toBe(classList[0]);
  });
});


답변

CSS를 사용 하여이 작업을 수행하려고한다는 것을 알고 있지만 작고 간단한 이미지 인 경우 알림을 제공합니다. 메모장 ++에서 언제든지 열어서 경로 / 요소의 채우기를 변경할 수 있습니다.

<path style="fill:#010002;" d="M394.854,205.444c9.218-15.461,19.102-30.181,14.258-49.527
    ...
    C412.843,226.163,402.511,211.451,394.854,205.444z"/>

그것은 추악한 스크립트를 저장할 수 있습니다. 기본이 아닌 경우 죄송하지만 때로는 간단한 솔루션을 간과 할 수 있습니다.

… 여러 svg 이미지를 교체 하더라도이 질문의 일부 코드 스 니펫보다 크기가 작을 수 있습니다.