首页 文章

如何使用CSS(jQuery SVG图像替换)更改SVG图像的颜色?

提问于
浏览
401

这是我提出的一个方便的代码的自我问答 .

目前,没有一种简单的方法来嵌入SVG图像,然后通过CSS访问SVG元素 . 有各种使用JS SVG框架的方法,但如果你所做的只是制作一个带有翻转状态的简单图标,它们就会过于复杂 .

所以这就是我提出的,我认为这是迄今为止在网站上使用SVG文件的最简单方法 . 它从早期的文本到图像替换方法中获取其概念,但据我所知,从未对SVG进行过 .

这是一个问题:

如何在不使用JS-SVG框架的情况下嵌入SVG并在CSS中更改其颜色?

17 回答

  • 49

    我写了一个指令来解决AngularJS的这个问题 . 它可用here - ngReusableSvg .

    它在渲染后替换SVG元素,并将其置于 div 元素内,使其CSS易于更改 . 这有助于在不同的地方使用不同的尺寸/颜色使用相同的SVG文件 .

    用法很简单:

    <object oa-reusable-svg
            data="my_icon.svg"
            type="image/svg+xml"
            class="svg-class"
            height="30"  // given to prevent UI glitches at switch time
            width="30">
    </object>
    

    之后,您可以轻松拥有:

    .svg-class svg {
        fill: red; // whichever color you want
    }
    
  • 4

    如果我们有更多这样的svg图像,我们也可以借助font-files .
    https://glyphter.com/这样的网站可以从我们的svgs获取一个字体文件 .


    例如 .

    @font-face {
        font-family: 'iconFont';
        src: url('iconFont.eot');
    }
    #target{
        color: white;
        font-size:96px;
        font-family:iconFont;
    }
    
  • 18

    您可以使用数据图像 . 使用数据图像(data-URI),您可以像内联一样访问SVG .

    Here is rollover effect using pure CSS and SVG.

    我知道 messy 但你可以这样做 .

    .action-btn {
        background-size: 20px 20px;
        background-position: center center;
        background-repeat: no-repeat;
        border-width: 1px;
        border-style: solid;
        border-radius: 30px;
        height: 40px;
        width: 60px;
        display: inline-block;
     }
    
    .delete {
         background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg version='1.1' id='Capa_1' fill='#FB404B' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' width='482.428px' height='482.429px' viewBox='0 0 482.428 482.429' style='enable-background:new 0 0 482.428 482.429;' xml:space='preserve'%3e%3cg%3e%3cg%3e%3cpath d='M381.163,57.799h-75.094C302.323,25.316,274.686,0,241.214,0c-33.471,0-61.104,25.315-64.85,57.799h-75.098 c-30.39,0-55.111,24.728-55.111,55.117v2.828c0,23.223,14.46,43.1,34.83,51.199v260.369c0,30.39,24.724,55.117,55.112,55.117 h210.236c30.389,0,55.111-24.729,55.111-55.117V166.944c20.369-8.1,34.83-27.977,34.83-51.199v-2.828 C436.274,82.527,411.551,57.799,381.163,57.799z M241.214,26.139c19.037,0,34.927,13.645,38.443,31.66h-76.879 C206.293,39.783,222.184,26.139,241.214,26.139z M375.305,427.312c0,15.978-13,28.979-28.973,28.979H136.096 c-15.973,0-28.973-13.002-28.973-28.979V170.861h268.182V427.312z M410.135,115.744c0,15.978-13,28.979-28.973,28.979H101.266 c-15.973,0-28.973-13.001-28.973-28.979v-2.828c0-15.978,13-28.979,28.973-28.979h279.897c15.973,0,28.973,13.001,28.973,28.979 V115.744z'/%3e%3cpath d='M171.144,422.863c7.218,0,13.069-5.853,13.069-13.068V262.641c0-7.216-5.852-13.07-13.069-13.07 c-7.217,0-13.069,5.854-13.069,13.07v147.154C158.074,417.012,163.926,422.863,171.144,422.863z'/%3e%3cpath d='M241.214,422.863c7.218,0,13.07-5.853,13.07-13.068V262.641c0-7.216-5.854-13.07-13.07-13.07 c-7.217,0-13.069,5.854-13.069,13.07v147.154C228.145,417.012,233.996,422.863,241.214,422.863z'/%3e%3cpath d='M311.284,422.863c7.217,0,13.068-5.853,13.068-13.068V262.641c0-7.216-5.852-13.07-13.068-13.07 c-7.219,0-13.07,5.854-13.07,13.07v147.154C298.213,417.012,304.067,422.863,311.284,422.863z'/%3e%3c/g%3e%3c/g%3e%3c/svg%3e ");
         border-color:#FB404B;
         
     }
     
     .delete:hover {
         background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg version='1.1' id='Capa_1' fill='#fff' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' width='482.428px' height='482.429px' viewBox='0 0 482.428 482.429' style='enable-background:new 0 0 482.428 482.429;' xml:space='preserve'%3e%3cg%3e%3cg%3e%3cpath d='M381.163,57.799h-75.094C302.323,25.316,274.686,0,241.214,0c-33.471,0-61.104,25.315-64.85,57.799h-75.098 c-30.39,0-55.111,24.728-55.111,55.117v2.828c0,23.223,14.46,43.1,34.83,51.199v260.369c0,30.39,24.724,55.117,55.112,55.117 h210.236c30.389,0,55.111-24.729,55.111-55.117V166.944c20.369-8.1,34.83-27.977,34.83-51.199v-2.828 C436.274,82.527,411.551,57.799,381.163,57.799z M241.214,26.139c19.037,0,34.927,13.645,38.443,31.66h-76.879 C206.293,39.783,222.184,26.139,241.214,26.139z M375.305,427.312c0,15.978-13,28.979-28.973,28.979H136.096 c-15.973,0-28.973-13.002-28.973-28.979V170.861h268.182V427.312z M410.135,115.744c0,15.978-13,28.979-28.973,28.979H101.266 c-15.973,0-28.973-13.001-28.973-28.979v-2.828c0-15.978,13-28.979,28.973-28.979h279.897c15.973,0,28.973,13.001,28.973,28.979 V115.744z'/%3e%3cpath d='M171.144,422.863c7.218,0,13.069-5.853,13.069-13.068V262.641c0-7.216-5.852-13.07-13.069-13.07 c-7.217,0-13.069,5.854-13.069,13.07v147.154C158.074,417.012,163.926,422.863,171.144,422.863z'/%3e%3cpath d='M241.214,422.863c7.218,0,13.07-5.853,13.07-13.068V262.641c0-7.216-5.854-13.07-13.07-13.07 c-7.217,0-13.069,5.854-13.069,13.07v147.154C228.145,417.012,233.996,422.863,241.214,422.863z'/%3e%3cpath d='M311.284,422.863c7.217,0,13.068-5.853,13.068-13.068V262.641c0-7.216-5.852-13.07-13.068-13.07 c-7.219,0-13.07,5.854-13.07,13.07v147.154C298.213,417.012,304.067,422.863,311.284,422.863z'/%3e%3c/g%3e%3c/g%3e%3c/svg%3e ");        
         background-color: #FB404B;
        }
    
    <a class="action-btn delete">&nbsp;</a>
    

    您可以在此处将svg转换为数据网址

  • 11

    如果这是静态更改,则在Adobe Illustrator(或任何合适的SVG编辑器)中打开SVG文件,更改颜色并保存 .

  • 7

    @Drew Baker为解决问题提供了很好的解决方案 . 代码工作正常 . 但是,那些使用AngularJs的人可能会发现很多依赖于jQuery . 因此,我认为粘贴AngularJS用户是一个好主意,这是一个遵循@Drew Baker解决方案的代码 .

    AngularJs way of the same code

    1. Html:在你的html文件中使用bellow标签:
    <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));
            });
          }
        };
      }]);
    
    1. 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]);
      });
    });
    
  • 23

    我意识到你想用CSS完成这个,但只是提醒一下,如果它是一个小而简单的图像 - 你总是可以在记事本中打开它并改变路径/ whateverelement的填充:

    <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图像的大小可能比这个问题的一些代码片段小 .

  • 2

    有一个名为SVGInject的开源库,它使用 onload 属性来触发注入 . 你可以在https://github.com/iconfu/svg-inject找到GitHub项目

    这是使用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> 元素将被 src 属性中提供的SVG文件的内容替换 .

    它解决了SVG注入的几个问题:

    • SVG可以隐藏,直到注射完成 . 如果在加载时已经应用了样式,则这很重要,否则会导致短暂的“无格式内容闪烁” .

    • <img> 元素自动注入 . 如果动态添加SVG,则不必担心再次调用注入函数 .

    • 随机字符串被添加到SVG中的每个ID,以避免在多次注入SVG时在文档中多次使用相同的ID .

    SVGInject是简单的Javascript,适用于所有支持SVG的浏览器 .

    免责声明:我是SVGInject的合着者

  • 24

    或者你可以使用CSS mask ,授予browser support不是很好,但你可以使用后备

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

    由于SVG基本上是代码,因此您只需要内容 . 我用PHP来获取内容,但你可以使用你想要的任何东西 .

    <?php
    $content    = file_get_contents($pathToSVG);
    ?>
    

    然后,我在div容器中“按原样”打印内容

    <div class="fill-class"><?php echo $content;?></div>
    

    最终在CSS上将规则设置为容器的SVG子项

    .fill-class > svg { 
        fill: orange;
    }
    

    我用物料图标SVG得到了这个结果:

    • Mozilla Firefox 59.0.2(64位)Linux

    enter image description here

    • 谷歌Chrome66.0.3359.181(Build oficial)(64位)Linux

    enter image description here

    • Opera 53.0.2907.37 Linux

    enter image description here

  • 4

    这是基于接受的答案的 knockout.js 的版本:

    Important: 它确实需要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 标记,并且不会遵守任何其他绑定 .

  • 2

    如果您希望jQuery处理DOM中的所有svg元素并且DOM的大小合理,则所选解决方案很好 . 但是如果你的DOM很大并且你决定动态加载你的部分DOM,那么必须重新扫描整个DOM是没有意义的DOM只是为了更新svg元素 . 相反,使用jQuery插件来执行此操作:

    /**
     * A jQuery plugin that loads an svg file and replaces the jQuery object with its contents.
     *
     * The path to the svg file is specified in the src attribute (which normally does not exist for an svg element).
     *
     * The width, height and class attributes in the loaded svg will be replaced by those that exist in the jQuery object's
     * underlying html. Note: All other attributes in the original element are lost including the style attribute. Place
     * any styles in a style class instead.
     */
    (function ($) {
        $.fn.svgLoader = function () {
            var src = $(this).attr("src");
            var width = this.attr("width");
            var height = this.attr("height");
            var cls = this.attr("class");
            var ctx = $(this);
    
            // Get the svg file and replace the <svg> element.
            $.ajax({
                url: src,
                cache: false
            }).done(function (html) {
                let svg = $(html);
                svg.attr("width", width);
                svg.attr("height", height);
                svg.attr("class", cls);
                var newHtml = $('<a></a>').append(svg.clone()).html();
                ctx.replaceWith(newHtml);
            });
    
            return this;
        };
    
    }(jQuery));
    

    在你的html中,指定一个svg元素,如下所示:

    <svg src="images/someSvgFile.svg" height="45" width="45" class="mySVGClass"/>
    

    并应用插件:

    $(".mySVGClass").svgLoader();
    
  • 23

    首先,在HTML中使用IMG标记嵌入SVG图形 . 我使用Adobe Illustrator制作图形 .

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

    这就像你嵌入正常图像一样 . 请注意,您需要将IMG设置为具有svg类 . “社交链接”类只是为了举例 . 该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;
    }
    

    You can see an example of it working here: http://labs.funkhausdesign.com/examples/img-svg/img-to-svg.html

    We have a more complicated version that includes caching here: https://github.com/funkhaus/style-guide/blob/master/template/js/site.js#L32-L90

  • 1

    您现在可以在most modern browsers中使用CSS filter property(包括Edge,但不是IE11) . 它适用于SVG图像以及其他元素 . 您可以使用 hue-rotateinvert 来修改颜色,但它们不允许您单独修改不同的颜色 . 我使用以下CSS类来显示图标的"disabled"版本(其中原始图片是饱和色的SVG图片):

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

    这使得它在大多数浏览器中都是浅灰色 . 在IE(可能还有Opera Mini,我还没有测试过)中,不透明度属性明显褪色,虽然它不是灰色的,但仍然看起来相当不错 .

    以下是Twemoji响铃图标的四个不同CSS类的示例:原始(黄色),上面的"disabled"类, 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>
    
  • 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)
            })
    
  • 511

    样式

    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');
        });
    });
    
  • 0

    如果您可以在页面中包含文件(PHP包括或通过您选择的CMS包含),您可以添加SVG代码并将其包含在您的页面中 . 这与将SVG源粘贴到页面中的工作方式相同,但使页面标记更清晰 .

    好处是你可以通过CSS定位SVG的部分悬停 - 不需要javascript .

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

    你只需要使用这样的CSS规则:

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

    请注意, !important 位是覆盖填充颜色所必需的 .

  • 1

    for:悬停事件动画我们可以将样式留在svg文件中,就像一个

    <svg xmlns="http://www.w3.org/2000/svg">
    <defs>
      <style>
      rect {
        fill:rgb(165,225,75);
        stroke:none;
        transition: 550ms ease-in-out;
        transform-origin:125px 125px;
      }
      rect:hover {
        fill:rgb(75,165,225);
        transform:rotate(360deg);
      }
      </style>
    </defs>
      <rect x='50' y='50' width='150' height='150'/>
    </svg>
    

    check this on svgshare

相关问题