Как изменить цвет SVG-изображения с помощью CSS (jQuery SVG image replacement)?

это самостоятельный вопрос и ответ на удобный кусок кода, который я придумал.

В настоящее время нет простого способа встроить изображение SVG, а затем получить доступ к элементам SVG через CSS. Существуют различные методы использования фреймворков JS SVG, но они слишком сложны, если все, что вы делаете, это создание простого значка с состоянием опрокидывания.

Итак, вот что я придумал, и я думаю, что это самый простой способ использовать SVG-файлы на веб-сайте. Она берет свое понятие из ранние методы замены текста на изображение, но, насколько мне известно, никогда не были сделаны для SVGs.

вот вопрос:

как вставить SVG и изменить его цвет в CSS без использования фреймворка JS-SVG?

17 ответов


во-первых, используйте тег IMG В HTML для встраивания SVG-графики. Я использовал Adobe Illustrator для создания графики.

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

Это похоже на то, как вы вставляете нормальное изображение. Обратите внимание, что вам нужно установить IMG для класса svg. Класс "социальная связь" - это просто для примера. ID не требуется, но полезен.

затем используйте этот код jQuery (в отдельном файле или встроенном в голове).

    /*
     * 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');

        });

что делает приведенный выше код, это искать все IMG с классом " svg " и замените его встроенным SVG из связанного файла. Огромным преимуществом является то, что он позволяет использовать CSS для изменения цвета SVG сейчас, например:

svg:hover path {
    fill: red;
}

код jQuery, который я написал, также переносит исходный идентификатор и классы изображений. Так что этот 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');
    });
});

Если вы можете включить файлы (PHP include или include через вашу CMS выбора) на Вашей странице, вы можете добавить код SVG и включить его в свою страницу. Это работает так же, как вставка источника SVG на страницу, но делает разметку страницы более чистой.

преимущество в том, что вы можете нацеливать части вашего SVG через CSS для наведения -- не требуется javascript.

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

вам просто нужно использовать правило CSS, например это:

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

отметим, что !important бит необходим для переопределения цвета заливки.


в качестве альтернативы вы можете использовать CSS mask, выдано поддержка браузеров не очень хорошо, но вы можете использовать запасной вариант

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

теперь вы можете использовать в CSS filter свойства на большинство современных браузеров (включая Edge, но не IE11). Он работает как на SVG изображениях, так и на других элементах. Вы можете использовать hue-rotate или invert для изменения цветов, хотя они не позволяют изменять разные цвета независимо. Я использую следующий класс CSS, чтобы показать "отключенную" версию значка (где оригинал-это изображение SVG с насыщенным цветом):

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

это делает его светло-серый в большинство браузеров. В IE (и, вероятно, Opera Mini, который я не тестировал) он заметно выцветает свойством непрозрачности, которое все еще выглядит довольно хорошо, хотя и не серое.

вот пример с четырьмя различными классами CSS для Twemoji значок колокола: оригинальный (желтый), выше "отключенный" класс,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>

@Drew Baker дал отличное решение для решения проблемы. Код работает правильно. Однако те, кто использует AngularJs, могут найти много зависимости от jQuery. Следовательно, я подумал, что это хорошая идея вставить для пользователей AngularJS код, следующий за решением @Drew Baker.

AngularJs путь того же кода

1. HTML-код: используйте тег bellow в 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, но просто напоминание, если это небольшое, простое изображение - вы всегда можете открыть его в Notepad++ и изменить путь / 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"/>

Это может спасти тонну уродливого сценария. Извините, если это не так, но иногда простые решения можно упустить из виду.

...даже замена нескольких изображений SVG может быть меньше по размеру, чем некоторые фрагменты кода на этот вопрос.


Я написал директиву для решения этой проблемы с AngularJS. Он доступен здесь - 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
}

вот версия для 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.

это решение полностью заменяет img тег с SVG и любые дополнительные привязки не будут соблюдаться.


здесь нет кода фреймворка, только чистый 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)
        })

существует библиотека с открытым исходным кодом SVGInject, которая использует onload атрибут для запуска инъекции. Вы можете найти проект 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-файла, представленного в .

это решает несколько вопросов с инъекцией SVG:

  1. Свгс могут быть скрыты до инъекций закончила. Это важно, если стиль уже применяется во время загрузки, что в противном случае вызовет краткую "незаполненную вспышку содержимого".

  2. на <img> элементы впрыснуть автоматически themselved. Если вы добавляете SVGs динамически, вам не нужно беспокоиться о вызове функции инъекции снова.

  3. случайная строка добавляется каждый идентификатор в SVG, чтобы избежать одного и того же идентификатора несколько раз в документе, если SVG вводится более одного раза.

SVGInject-простой Javascript и работает со всеми браузерами, поддерживающими SVG.

отказ от ответственности: я являюсь соавтором SVGInject


Если у нас есть большее количество таких изображений svg, мы также можем воспользоваться помощью файлов шрифтов.
Такие сайты, какhttps://glyphter.com/ может получить нам файл шрифта из нашей svgs.


Э. Г.

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

поскольку SVG-это в основном код, вам нужно только содержание. Я использовал PHP для получения контента, но вы можете использовать все, что вы хотите.

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

затем я напечатал содержимое "как есть" внутри контейнера div

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

для finnaly установить правило SVG childs контейнера на CSS

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

я получил эти результаты с помощью значка материала SVG:

  1. Mozilla Firefox 59.0.2 (64-разрядная версия) В Linux

enter image description here

  1. Google Chrome66.0.3359.181 (Build oficial) (64 бита) Linux

enter image description here

  1. Opera 53.0.2907.37 Linux

enter image description here


выбранное решение отлично, если вы хотите, чтобы jQuery обрабатывал все элементы 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();

для этого вы можете использовать data-image. используя data-image (data-URI), вы можете получить доступ к SVG like inline.

вот эффект опрокидывания с использованием чистого CSS и SVG.

Я знаю грязный но вы можете сделать так.

 .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 в url-адрес данных вот!--3-->

  1. https://codepen.io/elliz/full/ygvgay
  2. https://websemantics.uk/tools/svg-to-background-image-conversion/

для: анимации событий наведения мы можем оставить стили внутри 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>

проверьте это на svgshare


Если это статическое изменение, откройте файл SVG в Adobe Illustrator (или любом подходящем редакторе SVG) измените цвет и сохраните его.