วิธีการเปลี่ยนสีของภาพ SVG โดยใช้ CSS (การเปลี่ยนรูปภาพ jQuery SVG)?


437

นี่เป็นคำถามและคำตอบเกี่ยวกับโค้ดที่ใช้งานได้ง่าย

ขณะนี้ยังไม่มีวิธีที่ง่ายในการฝังภาพ SVG แล้วเข้าถึงองค์ประกอบ SVG ผ่าน CSS มีวิธีการต่างๆในการใช้เฟรมเวิร์ก JS SVG แต่มีความซับซ้อนมากเกินไปหากสิ่งที่คุณทำคือการสร้างไอคอนอย่างง่ายพร้อมสถานะโรลโอเวอร์

ดังนั้นนี่คือสิ่งที่ฉันคิดขึ้นมาซึ่งฉันคิดว่าเป็นวิธีที่ง่ายที่สุดในการใช้ไฟล์ SVG บนเว็บไซต์ มันใช้แนวคิดจากวิธีการเปลี่ยนข้อความเป็นรูปภาพในระยะแรก แต่เท่าที่ฉันรู้ว่ายังไม่เคยทำสำหรับ SVG

นี่คือคำถาม:

ฉันจะฝัง SVG และเปลี่ยนสีใน CSS ได้อย่างไรโดยไม่ต้องใช้เฟรมเวิร์ก JS-SVG


1
น่าเสียดายที่แท็ก img ไม่สามารถทำงานกับไฟล์ svg ใน IE ได้โปรดจำไว้ว่า IE รู้จักแท็กฝัง อย่างไรก็ตามงานดี!

2
สำหรับ svg คุณควรใช้คุณสมบัติ "fill" css สำหรับรูปภาพควรใช้ "ตัวกรอง" "ตัวกรอง" ใช้งานได้จริงสำหรับทั้งสองอย่าง แต่ไม่จำเป็นที่จะต้องทำงานทั้งหมดสำหรับกราฟิกแบบเวกเตอร์
Samy Bencherif

คำตอบ:


536

ก่อนอื่นให้ใช้แท็ก IMG ใน HTML ของคุณเพื่อฝังกราฟิก 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');

        });

สิ่งที่รหัสข้างต้นจะมองหา IMG ทั้งหมดด้วยคลาส 'svg' และแทนที่ด้วย inline 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


6
บางครั้งมันอาจไม่ทำงานใน Safari (ตัวอย่างเช่น) เพื่อให้แน่ใจว่าข้อมูลที่ส่งคืนสามารถอ่านได้ให้ทำการ remplace });ของ $ .get ด้วย}, 'xml');
Joan

29
คุณอาจจะแทนที่ตัวเลือกด้วยimg[src$=".svg"]และกำจัดความจำเป็นในการsvgเรียน
Casey Chu

2
@LeonGaban ฉันไม่คิดว่าจะมีวิธีกำหนดเป้าหมายภาพพื้นหลัง มันจะมีประโยชน์มากถ้าคุณทำได้!
Drew Baker

3
ช้าไปหน่อย @LeonGaban แต่วิธีที่ดีกว่าในการทำเช่นนั้นอาจเป็นการลบแอตทริบิวต์การเติมทั้งหมดและใช้ไฟล์ CSS เพื่อเพิ่มการเติมลงใน parent svg $('#ico_company path').removeAttr('fill'). จากนั้นคุณสามารถทำได้#ico_company { fill: #ccc }ในไฟล์ CSS ของคุณ
bioball

2
@Soaku มันง่ายที่จะให้ jQuery ตั้งค่าพา ธ ทั้งหมดให้เหมือนกับสีตัวอักษรที่ทำอะไรบางอย่างเช่น `var color = $ img.closest ('p') css ('color'); $ svg.find ('path'). attr ('fill', color); `แต่ฉันคิดว่านี่เป็นงานที่ดีกว่าสำหรับ CSS
Drew Baker

56

สไตล์

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

1
หากคุณไม่มีความกว้าง attr ก็แค่สร้างขึ้นด้วยจำนวนที่ไม่ถูกต้อง width="170.667"ในกรณีของฉัน
stallingOne

2
นี่ไม่สมบูรณ์แบบเนื่องจากเสียมิติ img ไปก่อนหน้านี้
RichieHH

สวัสดีสมมติว่าฉันมี svg ที่แตกต่างกันด้วยสี differnet แต่ละอัน การใช้วิธีนี้สี svg ทั้งหมดของฉันจะเหมือนกับสี svg ตัวแรกที่ถูกลูป ความคิดใดที่ฉันจะจัดทำรอบนี้เพื่อให้แต่ละสียังคงเหมือนเดิม?
tnkh

1
โปรดทราบว่าหาก svg ของคุณถูกสร้างขึ้นมาจากpathรูปร่างที่ไม่เหมือนกัน (เช่นrect) คุณจะต้องจัดการกับพวกเขาด้วย css เช่นกัน
Mugen

33

ตอนนี้คุณสามารถใช้คุณสมบัติCSSfilterในเบราว์เซอร์ที่ทันสมัยที่สุด (รวมถึง 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(สีน้ำเงิน)


เพิ่งสังเกตเห็นว่าการกลับด้านเป็นวิธีแก้ปัญหาที่ดีถ้าคุณไม่ต้องการสร้างแบบอักษรของไอคอน ฉันใช้รหัส jQuery นี้เพื่อเปลี่ยนไอคอนในส่วนหัวของเว็บไซต์ของฉันตามคุณสมบัติสี css (สังเกตว่าฉันใช้ไอคอน png สีขาว):if ($('.w3-top img').css("color") == "rgb(0, 0, 0)") { $('.w3-top img').css("filter", "invert(100%)"); $('.w3-top img').css("-webkit-filter", "invert(100%)"); };
RedClover

วิธีการที่ยอดเยี่ยม แก้ไข SVG xml ของฉันเพื่อเพิ่มสีไอคอนเป้าหมายจากนั้นใช้คลาสที่. ปิดการใช้งานเพื่อทำให้เป็นสีเทา
SushiGuy

โปรดสังเกตว่า Explores เก่าไม่รองรับตัวกรอง: w3schools.com/cssref/css3_pr_filter.asp
JillAndMe

25

หรือคุณสามารถใช้ CSS การสนับสนุนเบราว์เซอร์ที่maskได้รับไม่ดี แต่คุณสามารถใช้ทางเลือกสำรองได้

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

14
MDN ระบุว่า-webkit-maskไม่ควรใช้กับเว็บไซต์การผลิตใด ๆ
vaindil

1
ไม่ได้ระบายสี svg
vishal

อาจเกี่ยวข้องกับการพูดว่าตอนนี้สี่ปีต่อมาโซลูชันนี้ทำงานในเบราว์เซอร์หลักทั้งหมด เพิ่งทดสอบที่นี่และมันก็โอเค 100%
Daniel Lemes

23

หากคุณสามารถรวมไฟล์ (PHP รวมหรือรวมผ่านทาง CMS ที่คุณเลือก) ในหน้าของคุณคุณสามารถเพิ่มรหัส SVG และรวมไว้ในหน้าของคุณ สิ่งนี้ทำงานเหมือนกับการวางแหล่งที่มาของ SVG ลงในหน้า แต่ทำให้มาร์กอัพของหน้าสะอาดขึ้น

ประโยชน์คือคุณสามารถกำหนดเป้าหมายส่วนของ SVG ของคุณผ่าน CSS สำหรับโฮเวอร์ - ไม่จำเป็นต้องใช้จาวาสคริปต์

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

คุณต้องใช้กฎ CSS ดังนี้:

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

โปรดทราบว่า!importantบิตมีความจำเป็นเพื่อแทนที่สีเติม


3
สำหรับผู้ที่ใช้ AngularJS:<div ng-include="'svg.svg'"></div>
Mikel

ไม่ใช่โซลูชันที่สวยงามมากที่เก็บข้อมูล svg ไว้ในฐานข้อมูล ไม่ผิด แต่การบีบอัดข้อมูล xml / html / svg DOM จาก API หรือ CMS แทนที่จะใช้แม่แบบหรือเนื้อหาอื่น ๆ ก็รู้สึกผิด
ChristoKiwi

ขอบคุณสำหรับการสนับสนุนนี้ ... เว็บไซต์ที่ทันสมัยที่สุดในปัจจุบันทำรังข้อมูล svg เพื่อให้สามารถทำกิจกรรมทุกประเภทโดยไม่มีคำตอบนี้ฉันจะไม่เดาเลย!
webMan

นอกจากนี้หาก SVG ของคุณมีพื้นที่โปร่งใสสิ่งเหล่านี้จะไม่นับเป็นโฮเวอร์และคุณอาจพบกับ "โฮเวอร์ฉูดฉาด" ในการแก้ไขปัญหาให้เพิ่มองค์ประกอบ wrapper (<a> หากสะดวก) จากนั้นเพิ่มองค์ประกอบลงในกฎ CSS #pathidorclass:hover, .wrapperclass:hover #pathidorclass { fill: green; }หรือแม้แต่กำจัดการโฮเวอร์เส้นทาง SVG ดั้งเดิมเนื่องจากคุณกำหนดเป้าหมายผ่านองค์ประกอบตัวตัดคำในขณะนี้
Neil Monroe

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. การทดสอบหน่วยด้วยกรรม - มะลิ :

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

1
ทางออกของคุณไม่ทำงานอาจเป็น<div ng-include="/icons/my.svg" class="any-class-you-wish"></div>
Guillaume Vincent

@guillaumevincent หากคุณต้องการใช้กับมันng-includeจากนั้นเพียงแค่เปลี่ยนบรรทัดนี้var imgURL = element.attr('src');เป็นvar imgURL = element.attr('ng-include');
สูงสุด

นี่เป็นวิธีแก้ปัญหาที่มีประโยชน์มาก แต่ควรระวังในการใช้งานมากเกินไปเพราะอาจทำให้ประสิทธิภาพการทำงานค่อนข้างยาก - IE เป็นชุดไอคอนการแบ่งปัน 5 รายการซ้ำ ๆ กันในรายการบทความหรืออะไรทำนองนั้น
skxc

1
มีปัญหากับรหัสของคุณใน IE คุณสามารถใช้เพียงแค่if (typeof(imgClass) !== 'undefined') { $svg.setAttribute("class", imgClass); }แยกและสำหรับวง
Robert Bokori

2
เยี่ยมมาก! แต่สำหรับภาพบางอย่างที่คุณจำเป็นต้องคว้าองค์ประกอบแรกของ SVG ( angular.element(data)[0];) if ($svg.getAttribute('class')) { $svg.setAttribute('class', $svg.getAttribute('class') + ' ' + imgClass); } else { $svg.setAttribute('class', imgClass); }และเพื่อให้การทำงานที่มีการใช้ นอกจากนี้คุณอาจต้องการเพิ่มcache: trueตัวเลือก$http.getมิฉะนั้นหน้าของคุณอาจช้ามาก
leo

16

ฉันรู้ว่าคุณต้องการที่จะทำสิ่งนี้ด้วย CSS แต่เพียงเตือนความจำในกรณีที่มันเป็นภาพขนาดเล็กที่เรียบง่าย - คุณสามารถเปิดมันใน Notepad ++ และเปลี่ยนเส้นทาง / ส่วนเติมของอะไรก็ได้:

<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 หลายภาพอาจมีขนาดเล็กกว่าบางส่วนของโค้ดสำหรับคำถามนี้


7

ฉันเขียนคำสั่งเพื่อแก้ไขปัญหานี้กับ 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
}

สวัสดีขอบคุณที่ให้บริการโซลูชั่นนี้ ฉันได้ลองแล้วและให้: <div ng-click = "eventHandler ()" ng-class = "classEventHandler ()" style = "ความสูง: 30px; ความกว้าง: 30px; float: left;" class = "svg-class" id = "my-svg" height = "30" width = "30"> [[object SVGSVGElement]] </div> ใน html มันจะใส่ [[object SVGSVGElement]] คุณรู้หรือไม่ว่ามีปัญหาอะไร อีกคำถามหนึ่งมันมีผลกระทบอย่างมากต่อประสิทธิภาพหรือฉันสามารถใช้กับ svg จำนวนมากบนหน้าเว็บได้หรือไม่ และสุดท้ายมันก็ยังคงอยู่ที่มุม 1.3 (the bower)
bersling

คุณกำลังใช้แองกูลาร์รุ่นใด ไม่พบปัญหาของคุณ .. อาจเป็นเรื่องของ SVG ใช่ไหม สวิตช์ที่ใช้งานได้ค่อนข้างหนักฉันใช้ตัวเองในแบบที่ 10 และก็โอเค .. ฉันเดาว่าขึ้นอยู่กับจำนวน / ขนาดดังนั้นลองใช้และทดลองกับมัน ปัญหาเกี่ยวกับป่าไม้คืออะไร? คุณใช้เวอร์ชั่นอื่นและมีข้อขัดแย้งหรือไม่?
Omri Aharon

5

TL / DR: ไปที่นี่ -> https://codepen.io/sosuke/pen/Pjoqqp

คำอธิบาย:

ฉันสมมติว่าคุณมี html บางอย่างเช่นนี้:

<img src="/img/source.svg" class="myClass">

ไปที่เส้นทางตัวกรองอย่างแน่นอนเช่น svg ของคุณน่าจะเป็นสีดำหรือสีขาว คุณสามารถใช้ตัวกรองเพื่อให้เป็นสีใดก็ได้ที่คุณต้องการตัวอย่างเช่นฉันมี svg สีดำที่ฉันต้องการสีเขียวมินต์ ก่อนอื่นฉันจะให้มันเป็นสีขาว (ซึ่งเป็นเทคนิคสี RGB ทั้งหมดในแบบเต็ม) จากนั้นเล่นด้วยความอิ่มตัวของสี ฯลฯ เพื่อให้ถูกต้อง:

filter: invert(86%) sepia(21%) saturate(761%) hue-rotate(92deg) brightness(99%) contrast(107%);

ยิ่งไปกว่านั้นคือคุณสามารถใช้เครื่องมือในการแปลง hex ที่คุณต้องการให้เป็นตัวกรองสำหรับคุณ: https://codepen.io/sosuke/pen/Pjoqqp


นี่เป็นทางออกที่ดีเพียง css บวก codepen จากฐานสิบหกถึงตัวกรองนั้นยอดเยี่ยม
Richi González

4

นี่คือรุ่นสำหรับ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 อย่างสมบูรณ์และการผูกใด ๆ เพิ่มเติมจะไม่ได้รับการเคารพ


2
มันเยี่ยมมาก! หากคุณต้องการนำไปใช้ในระดับต่อไปเรามีรุ่นที่อัปเดตซึ่งรวมถึงการแคชดังนั้น SVG เดียวกันจะไม่ถูกร้องขอสองครั้ง github.com/funkhaus/style-guide/blob/master/template/js/…
Drew Baker

ฉันกังวลเล็กน้อยเกี่ยวกับเรื่องนี้ แต่ไม่มีเวลาที่จะตรวจสอบด้วยตัวเอง ต้องการบางสิ่งอย่างรวดเร็ว
Simon_Weaver

1
@DrewBaker ที่จริงฉันกังวลมากขึ้นว่าแท็ก img จะร้องขอไฟล์จากนั้นgetจะขออีกครั้ง ฉันถือว่าการเปลี่ยนsrcเป็นdata-srcคุณลักษณะบนimgแท็ก แต่ได้ข้อสรุปว่าเบราว์เซอร์ที่ทันสมัยอาจฉลาดพอที่จะแคชไฟล์ต่อไป
Simon_Weaver

3

นี่คือไม่มีรหัสเฟรมเวิร์กเฉพาะ pure 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)
        })

3

มีไลบรารี่โอเพ่นซอร์สชื่อ 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 ที่ให้ไว้ในsrcแอตทริบิวต์

มันแก้ปัญหาต่าง ๆ ด้วยการฉีด SVG:

  1. สามารถซ่อน SVG ได้จนกว่าการฉีดจะเสร็จสิ้น สิ่งนี้มีความสำคัญหากมีการนำสไตล์ไปใช้แล้วในระหว่างการโหลดซึ่งอาจทำให้ "แฟลชเนื้อหาที่ไม่มีการจัดเรียง" สั้น ๆ

  2. <img>องค์ประกอบฉีด themselved โดยอัตโนมัติ หากคุณเพิ่ม SVG แบบไดนามิกคุณไม่ต้องกังวลกับการเรียกฟังก์ชั่นการฉีดอีกครั้ง

  3. สตริงสุ่มจะถูกเพิ่มในแต่ละ ID ใน SVG เพื่อหลีกเลี่ยงการมี ID เดียวกันหลายครั้งในเอกสารหาก SVG ถูกฉีดมากกว่าหนึ่งครั้ง

SVGInject เป็น Javascript ธรรมดาและทำงานได้กับเบราว์เซอร์ทั้งหมดที่รองรับ SVG

คำเตือน: ฉันเป็นผู้เขียนร่วมของ SVGInject


1
ฉันชอบโซลูชันนี้ที่สุดเพราะดูแล SVG ที่เพิ่มแบบไดนามิก
VickyB

2

หากเรามีภาพ svg จำนวนมากเราสามารถใช้ไฟล์ฟอนต์ได้
ไซต์เช่นhttps://glyphter.com/สามารถรับไฟล์ฟอนต์จาก svgs ของเราได้


เช่น

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

5
ฉันเกลียดเทคนิค "images as font" มันทำให้ยากที่จะเพิ่ม / แก้ไขภาพเพิ่มมาร์กอัปไร้สาระจำนวนมาก แบบอักษรควรเป็นแบบอักษรรูปภาพควรเป็นรูปแบบอื่น ๆ
Drew Baker

ตกลง คุณต้องจำ / ค้นหาภาพที่กำหนดให้กับตัวละคร แต่สำหรับกรณีที่มีการใช้รูปภาพเป็นไอคอน / ปุ่ม / กระสุนแสดงเป็นข้อความมากกว่าสื่อไฟล์ฟอนต์ก็เป็นทางเลือกได้อีกด้วย
Abhishek Borar

แม้ github จะไม่ใช้แบบอักษรอีกต่อไปสำหรับไอคอนgithub.com/blog/2112-delivering-octicons-with-svg
gagarine

2

คุณสามารถใช้ data-image สำหรับสิ่งนั้นได้ ใช้ data-image (data-URI) คุณสามารถเข้าถึง SVG เช่นอินไลน์

นี่คือเอฟเฟกต์แบบโรลโอเวอร์โดยใช้ 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 เป็น data url ได้ที่นี่

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

สิ่งนี้จะไม่ทำงานสำหรับ SVG ที่ซับซ้อนที่คุณต้องการเส้นทาง / รูปหลายเหลี่ยม / อื่น ๆ บางอย่างเท่านั้นเพื่อเปลี่ยนเมื่อวางเมาส์ไว้ใช่ไหม
Drew Baker

ไม่คุณสามารถ .. แต่มันซับซ้อนมาก
patelarpan

มันเป็นเพียงการแก้ปัญหาสำหรับไอคอน
patelarpan

หากทำงานกับไอคอน ถ้าอย่างนั้นก็ยิ่งใหญ่ Bootstrap 4 ใช้เทคนิคนี้ด้วย
patelarpan

2

เนื่องจาก 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

ป้อนคำอธิบายรูปภาพที่นี่

  1. Google Chrome66.0.3359.181 (Build oficial) (64 บิต) Linux

ป้อนคำอธิบายรูปภาพที่นี่

  1. Opera 53.0.2907.37 Linux

ป้อนคำอธิบายรูปภาพที่นี่


1

โซลูชันที่เลือกนั้นใช้ได้ถ้าคุณต้องการให้ 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();

ใช่มีวิธีที่มีประสิทธิภาพมากกว่าในการใช้รหัสที่ฉันให้ นี่คือวิธีที่เราใช้จริงในเว็บไซต์ผลิต มันแคช SVGs! github.com/funkhaus/style-guide/blob/master/template/js/…
Drew Baker

1

สำหรับ: ภาพเคลื่อนไหวเหตุการณ์โฮเวอร์เราสามารถทิ้งสไตล์ไว้ในไฟล์ svg เช่น a

<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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.