462

これは、私が思いついた便利なコードの自己 Q&A です。

現在、SVG 画像を埋め込み、CSS を介して SVG 要素にアクセスする簡単な方法はありません。JS SVG フレームワークを使用するにはさまざまな方法がありますが、ロールオーバー状態の単純なアイコンを作成するだけだと、非常に複雑になります。

これは、Web サイトで SVG ファイルを使用する最も簡単な方法だと思います。初期のテキストから画像への置換方法からその概念が採用されていますが、私の知る限り、SVG に対して行われたことはありません。

これは質問です:

JS-SVG フレームワークを使用せずに SVG を埋め込んで CSS の色を変更するにはどうすればよいですか?

4

18 に答える 18

553

まず、HTML で IMG タグを使用して SVG グラフィックを埋め込みます。グラフィックの作成には Adob​​e 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

于 2012-08-16T00:05:27.443 に答える
41

現在、ほとんどの最新のブラウザー(Edge を含むが IE11 を除く)でCSSfilterプロパティを使用できます。SVG 画像だけでなく、他の要素でも機能します。またはを使用して色を変更できますが、異なる色を個別に変更することはできません。次の CSS クラスを使用して、アイコンの「無効」バージョンを表示します (元のアイコンは飽和色の SVG 画像です)。hue-rotateinvert

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

これにより、ほとんどのブラウザーでライト グレーになります。IE (およびおそらく私がテストしていない Opera Mini) では、不透明度プロパティによって著しく色あせていますが、グレーではありませんが、それでもかなり見栄えがします。

Twemojiベル アイコンの 4 つの異なる CSS クラスの例を次に示します。オリジナル (黄色)、上記の「無効化」クラス、hue-rotate(緑色)、およびinvert(青色)。

.twa-bell {
  background-image: url("https://twemoji.maxcdn.com/svg/1f514.svg");
  display: inline-block;
  background-repeat: no-repeat;
  background-position: center center;
  height: 3em;
  width: 3em;
  margin: 0 0.15em 0 0.3em;
  vertical-align: -0.3em;
  background-size: 3em 3em;
}
.grey-out {
  opacity: 0.4;
  filter: grayscale(100%);
  -webkit-filter: grayscale(100%);
}
.hue-rotate {
  filter: hue-rotate(90deg);
  -webkit-filter: hue-rotate(90deg);
}
.invert {
  filter: invert(100%);
  -webkit-filter: invert(100%);
}
<!DOCTYPE html>
<html>

<head>
</head>

<body>
  <span class="twa-bell"></span>
  <span class="twa-bell grey-out"></span>
  <span class="twa-bell hue-rotate"></span>
  <span class="twa-bell invert"></span>
</body>

</html>

于 2016-06-28T19:10:37.127 に答える
23

ページにファイル (PHP インクルードまたは選択した CMS 経由でインクルード) を含めることができる場合は、SVG コードを追加してページに含めることができます。これは、SVG ソースをページに貼り付けるのと同じように機能しますが、ページのマークアップがよりきれいになります。

利点は、ホバーのために CSS を介して SVG の一部をターゲットにできることです。JavaScript は必要ありません。

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

次のような CSS ルールを使用するだけです。

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

!important塗りつぶしの色をオーバーライドするにはビットが必要であることに注意してください。

于 2013-10-01T16:01:10.347 に答える
18

@Drew Baker は、問題を解決する優れたソリューションを提供してくれました。コードは正常に動作します。ただし、AngularJs を使用している人は、jQuery に多くの依存関係があることに気付くかもしれません。したがって、AngularJS ユーザー向けに、@Drew Baker のソリューションに続くコードを貼り付けることをお勧めします。

同じコードの 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. karma-jasmine を使用した単体テスト:

'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]);
  });
});
于 2015-01-27T09:34:39.407 に答える
17

I realize you're wanting to accomplish this with CSS, but just a reminder in case it's a small, simple image - you can always pop it open in Notepad++ and change the path/whateverelement's fill:

<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"/>

It could save a ton of ugly script. Sorry if it's off-base, but sometimes the simple solutions can be overlooked.

...even swapping multiple svg images might be smaller in size than some of the code snippets for this question.

于 2018-01-03T22:23:22.807 に答える
5

knockout.js受け入れられた回答に基づくバージョンは次のとおりです。

重要:置き換えには実際には jQuery も必要ですが、一部の人には役立つかもしれないと思いました。

ko.bindingHandlers.svgConvert =
    {
        'init': function ()
        {
            return { 'controlsDescendantBindings': true };
        },

        'update': function (element, valueAccessor, allBindings, viewModel, bindingContext)
        {
            var $img = $(element);
            var imgID = $img.attr('id');
            var imgClass = $img.attr('class');
            var imgURL = $img.attr('src');

            $.get(imgURL, function (data)
            {
                // Get the SVG tag, ignore the rest
                var $svg = $(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');

        }
    };

次にdata-bind="svgConvert: true"、img タグに適用します。

このソリューションでは、タグが SVG に完全に置き換えimgられ、追加のバインディングは無視されます。

于 2016-10-01T02:53:15.067 に答える
4

onload属性を使用してインジェクションをトリガーするSVGInject というオープン ソース ライブラリがあります。GitHub プロジェクトはhttps://github.com/iconfu/svg-injectにあります。

SVGInject を使用した最小限の例を次に示します。

<html>
  <head>
    <script src="svg-inject.min.js"></script>
  </head>
  <body>
    <img src="image.svg" onload="SVGInject(this)" />
  </body>
</html>

画像が読み込まれた後、onload="SVGInject(this)インジェクションがトリガーされ、<img>要素が属性で指定された SVG ファイルの内容に置き換えられsrcます。

SVG インジェクションに関するいくつかの問題を解決します。

  1. インジェクションが完了するまで、SVG を非表示にすることができます。これは、読み込み時にスタイルが既に適用されている場合に重要です。そうしないと、短い「スタイルのないコンテンツ フラッシュ」が発生します。

  2. 要素は<img>自動的に注入されます。SVG を動的に追加する場合、インジェクション関数を再度呼び出すことを心配する必要はありません。

  3. SVG が複数回挿入された場合に、ドキュメント内で同じ ID が複数回使用されるのを避けるために、SVG 内の各 ID にランダムな文字列が追加されます。

SVGInject はプレーンな Javascript であり、SVG をサポートするすべてのブラウザーで動作します。

免責事項: 私は SVGInject の共著者です

于 2018-09-04T16:04:04.020 に答える
3

これはフレームワークなしのコードで、純粋な js のみです:

document.querySelectorAll('img.svg').forEach(function(element) {
            var imgID = element.getAttribute('id')
            var imgClass = element.getAttribute('class')
            var imgURL = element.getAttribute('src')

            xhr = new XMLHttpRequest()
            xhr.onreadystatechange = function() {
                if(xhr.readyState == 4 && xhr.status == 200) {
                    var svg = xhr.responseXML.getElementsByTagName('svg')[0];

                    if(imgID != null) {
                         svg.setAttribute('id', imgID);
                    }

                    if(imgClass != null) {
                         svg.setAttribute('class', imgClass + ' replaced-svg');
                    }

                    svg.removeAttribute('xmlns:a')

                    if(!svg.hasAttribute('viewBox') && svg.hasAttribute('height') && svg.hasAttribute('width')) {
                        svg.setAttribute('viewBox', '0 0 ' + svg.getAttribute('height') + ' ' + svg.getAttribute('width'))
                    }
                    element.parentElement.replaceChild(svg, element)
                }
            }
            xhr.open('GET', imgURL, true)
            xhr.send(null)
        })
于 2017-11-07T20:41:21.797 に答える
2

このような svg 画像が多数ある場合は、フォント ファイルを利用することもできます。https://glyphter.com/
のようなサイトでは、svg からフォント ファイルを取得できます。


例えば

@font-face {
    font-family: 'iconFont';
    src: url('iconFont.eot');
}
#target{
    color: white;
    font-size:96px;
    font-family:iconFont;
}
于 2015-07-07T19:25:46.387 に答える