包含带有HTML的SVG文件,并且仍然可以为其应用样式吗?

时间:2016-03-03 21:31:33

标签: javascript jquery html css svg

您可以通过embed objectsvg标记将SVG文件添加到HTML文件中。

  • 使用embedobject代码需要将图片与网址相关联。 (这是我更喜欢的,因为我不喜欢我的HTML代码中的所有SVG代码,所以我想保持这种方式。)
  • 使用svg代码(AFAIK)需要在HTML代码中内嵌SVG代码。

我的问题是:

如何将SVG图标,图像和其他文件包含到我的HTML文件中,而无需将整个SVG代码放入其中,并且仍然可以将样式应用于它们?通过JS应用它们也很好。

注意:

当我通过objectembed添加它们时,我似乎无法通过jQuery访问它们,即使使用$("#my-svg-div").find("svg")(顺便提一下,几乎每个答案都是如此)在SO上说我应该)。我得到undefined

谢谢!

2 个答案:

答案 0 :(得分:20)

简答

您可以通过编程方式内联SVG图像。这样的图像可以基本上与实际的内联<svg>元素相同地处理,包括能够应用样式。

如果您在<object><iframe>元素(e)中引用了SVG图像,则可以按如下方式对其进行内联:

e.parentElement.replaceChild(e.contentDocument.documentElement.cloneNode(true), e);

如果您在<embed>元素中引用了SVG图片,请将上述代码中的.contentDocument替换为.getSVGDocument()

如果在<img>元素中引用了SVG图像,则可以使用完全不同的策略(包括AJAX并在下面描述)来内联图像。

一般策略

如果您的外部SVG图像文件是同源的(例如,图像是从与HTML代码相同的位置加载的),那么允许对这些图像进行样式设置的一种方法是以编程方式将它们内联如下:

  • 检索外部SVG文件的内容。
  • 将该内容直接添加回与原始引用元素位于同一HTML DOM位置的HTML文件中,即将其放入&#34;内嵌&#34;。
  • 删除最初引用外部SVG文件的元素。

优势

这种内联策略为您提供了两个世界中最好的:

  1. 您可以获得单独图像文件的好处,包括:

    • 独立于HTML组织您的图像文件,
    • 保持原始HTML文件不受图像细节的影响,
    • (可能)允许浏览器缓存图像(但请参阅下面关于最后一点的内容)。
  2. 然而,您仍然可以对最终内联的SVG图像执行任何操作,您可以对<svg>真正内联的元素执行此操作,包括:

    • 将CSS样式应用于它们,
    • 将事件侦听器应用于各个SVG形状或组等
  3. 实施

    对于<object><iframe>元素:

    您可以按如下方式内联外部引用的SVG代码:

    // using vanilla JavaScript (as shown above):
    e.parentElement.replaceChild(e.contentDocument.documentElement.cloneNode(true), e);
    
    // using jQuery:
    $e.replaceWith($($e[0].contentDocument.documentElement).clone());
    

    ...其中e$e是vanilla或jQuery变量(分别),您在其中选择了外部SVG引用<object><iframe>元素

    要包含<embed>元素:

    如果您正在使用外部SVG引用<embed>元素,则可以通过将上述代码中的.contentDocument替换为.getSVGDocument()来内联SVG内容(请注意额外的括号)。请注意,.contentDocument不适用于<embed>元素,而.getSVGDocument()实际上适用于所有三种元素类型。但是,只有在您确实需要.getSVGDocument()元素时才应使用<embed> is deprecated等。

    要包含<img>元素:

    上述两种策略均不适用于<img>元素。要内联这些内容,您可以检索src元素的<img>属性,为该文件发出AJAX请求,使用检索到的SVG代码创建新的<svg>元素并替换原始{带有新<img>元素的{1}}元素。如果您希望此策略适用于所有四种元素类型,那么请注意引用的SVG图像的URL保存在<svg>src和{{<iframe>属性中。 1}}元素,但在<embed>元素的<img>属性中。该策略可以实现如下:

    data

    实施例

    以下示例演示了上述策略的用途,并且不允许将外部CSS样式应用于原始外部SVG图像。 (由于需要引用本地外部文件,我没有创建代码段或jsfiddle。)

    以下两个屏幕截图显示了内联之前和之后的CSS样式(红色三角形)或缺少(黑色三角形)。它显示最初嵌入HTML(<object>)或在指定元素中引用的SVG图像的结果(// using vanilla JavaScript: var xhr = new XMLHttpRequest(); xhr.open("GET", e.getAttribute(e.nodeName === "OBJECT" ? "data" : "src"); xhr.send(); xhr.onreadystatechange = function() { if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) { e.outerHTML = xhr.responseText; } }; // using jQuery: $.get($e.attr($e.prop("nodeName") === "OBJECT" ? "data" : "src"), function(data) { $e.replaceWith(data.documentElement); }); <svg><object><iframe> )。这三行显示了使用三种指示策略的内联结果。

    在单击按钮之前,尚未尝试内联,屏幕如下所示。只有嵌入式SVG元素(第1列)的样式为:

    svg polygon styling by CSS before svg inlining

    单击按钮后,尝试进行内联,屏幕现在看起来像这样。 CSS样式已成功应用于某些元素:

    svg polygon styling by CSS after svg inlining

    此示例所需的代码如下:

    <embed> (外部引用的文件,即未嵌入HTML中):

    <img>

    image.svg (显然,如果不使用jQuery,请删除jQuery脚本行):

    <svg xmlns="http://www.w3.org/2000/svg" width="50px" height="50px">
      <polygon points="25,5 45,45 5,45 25,5"/>
    </svg>
    

    index.html (只有<!DOCTYPE html> <head> <link href="styles.css" rel="stylesheet"> <script src="//code.jquery.com/jquery-1.12.0.min.js"></script> <script src="main.js"></script> </head> <body> <button>Click to attempt to inline svg images.</button> <table> <tr> <th></th> <th>svg </th> <th>object</th> <th>iframe</th> <th>embed </th> <th>img </th> </tr> <tr> <td>contentDocument</td> <td><svg xmlns="http://www.w3.org/2000/svg" width="50" height="50"><polygon points="25,5 45,45 5,45 25,5"/></svg></td> <td><object data="image.svg" type="image/svg+xml"></object></td> <td><iframe src="image.svg" width="50" height="50" style="border: none;"></iframe></td> <td><embed src="image.svg" type="image/svg+xml" /></td> <td><img src="image.svg" /></td> </tr> <tr> <td>getSVGDocument()<br />(deprecated)</td> <td><svg xmlns="http://www.w3.org/2000/svg" width="50" height="50"><polygon points="25,5 45,45 5,45 25,5"/></svg></td> <td><object data="image.svg" type="image/svg+xml"></object></td> <td><iframe src="image.svg" width="50" height="50" style="border: none;"></iframe></td> <td><embed src="image.svg" type="image/svg+xml" /></td> <td><img src="image.svg" /></td> </tr> <tr> <td>XMLHttpRequest</td> <td><svg xmlns="http://www.w3.org/2000/svg" width="50" height="50"><polygon points="25,5 45,45 5,45 25,5"/></svg></td> <td><object data="image.svg" type="image/svg+xml"></object></td> <td><iframe src="image.svg" width="50" height="50" style="border: none;"></iframe></td> <td><embed src="image.svg" type="image/svg+xml" /></td> <td><img src="image.svg" /></td> </tr> </table> </body> </html> 行对于演示内联非常重要):

    styles.css

    polygon (jQuery版):

    polygon {fill: red;}
    table {border-collapse: collapse;}
    td, th {border: solid black 1px; padding: 0.4em;}
    

    main.js (vanilla JavaScript版):

    $(document).ready(function() {
      $("button").click(function() {
        ["object", "iframe", "embed", "img"].forEach(function(elmtType) {
          var $e, $threeElmts = $(elmtType);
          $e = $($threeElmts[0]);
          if ($e[0].contentDocument) $e.replaceWith($($e[0].contentDocument.documentElement).clone());
          $e = $($threeElmts[1]);
          if ($e[0].getSVGDocument) $e.replaceWith($($e[0].getSVGDocument().documentElement).clone());
          $e = $($threeElmts[2]);
          $.get($e.attr($e.prop("nodeName") === "OBJECT" ? "data" : "src"), function(data) {
            $e.replaceWith(data.documentElement);
          });
        });
      });
    });
    

    请注意以下事项:

    • 此策略要求您处理与原始引用元素相关的任何特征,例如:后备图片,main.jsdocument.addEventListener("DOMContentLoaded", function() { document.querySelector("button").addEventListener("click", function() { ["object", "iframe", "embed", "img"].forEach(function(elmtType) { var e, threeElmts = document.querySelectorAll(elmtType); e = threeElmts[0]; if (e.contentDocument) e.parentElement.replaceChild(e.contentDocument.documentElement.cloneNode(true), e); e = threeElmts[1]; if (e.getSVGDocument) e.parentElement.replaceChild(e.getSVGDocument().documentElement.cloneNode(true), e); e = threeElmts[2]; var xhr = new XMLHttpRequest(); xhr.open("GET", e.getAttribute(e.nodeName === "OBJECT" ? "data" : "src")); xhr.send(); xhr.onreadystatechange = function() { if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) e.outerHTML = xhr.responseText; }; }); }); }); (或任何其他)属性,事件监听器,id功能等。
    • 确保在实际加载图像文件后才尝试内联。
    • 考虑在服务器端进行内联以允许提供单个文件,但在客户端进行内联以允许图像文件缓存。
    • 我在Firefox 44.0,Chrome 49.0和Opera 35.0(Mac和Windows),Safari 9.0(Mac)和IE 11(Windows)中验证了此策略。我没有检查Edge或任何移动浏览器。
    • 此解决方案解决了来自classiframeobjectiframe元素的SVG文件的引用问题。它不涉及CSS embed属性或img上下文的background-image函数中引用的外部SVG图像。我怀疑那些不会以这种方式工作,但我还没有检查过。
    • 如果您尝试通过复制和保存代码来复制本地计算机上的示例代码,然后打开drawImage,Chrome和Opera就会设置安全设置。要使这些浏览器在这种本地配置中工作,您需要按照this other SO question中的说明运行本地服务器。如果您在正常的服务器托管网站中使用内联策略,则不应存在此类问题。

答案 1 :(得分:3)

这是(1)在HTML中使用SVG的不同方式以及(2)通过CSS / JS对SVG的各个部分(即:路径)进行样式设置的最全面的演练。

https://css-tricks.com/using-svg/

  1. 在图片标记中(例如:<img src="picture.svg" />或CSS中的背景图片=没有样式

  2. 内联样式,但它会混乱你的HTML。 PHP在这里有所帮助,或者您可以使用gulp构建任务或其他东西来防止SVG混乱您的工作代码,同时仍然是内联的。

  3. 作为对象,您现在可以在<。strong> .svg文件中添加CSS

    <svg ...>
      <style>
        /* SVG specific fancy CSS styling here */
      </style>
      ...
    </svg>
    

    <?xml-stylesheet type="text/css" href="svg.css" ?>
    
  4. 数据URI - 可以很好地用于背景图像。没有造型。