开发者

Specify an SVG as a background image and ALSO style the SVG in CSS?

Is it possible to specify an SVG as a background image and ALSO style the SVG in the same CSS file?

I'm very comfortable placing, scaling and clipping SVG images as either single files or sprites, but I haven't been able to work out if it possible to style the SVG within the same CSS file as sets it as a background image.

In pseudo CSS i'd like to d开发者_如何学运维o the following to vary the colour of simple shape based on the class of the parent element:

element1 {
 background-image(icon.svg);
}

element1.black .svg-pathclass {
 fill: #000000;
}

element1.white .svg-pathclass {
 fill: #ffffff;
}

obviously this assumes a path in the SVG having class .svg-pathclass

is this possible?


No, this is not possible. The SVG has to be prepared in one document (which may be a data URI or an externally referenced file) and then used as a background in another file.


You can use SVG and CSS masks to recreate this effect, then use normal CSS to style the inside of the SVG, even background-image

-webkit-mask:   url(filename.svg) 50% 50% / 100px 50px no-repeat;
    -o-mask:    url(filename.svg) 50% 50% / 100px 50px no-repeat;
    -ms-mask:   url(filename.svg) 50% 50% / 100px 50px no-repeat;

background-color: red;
background-image: url(animated.gif);

/* Filename, Position / Size, Repeat */
/* Modernizr.cssmask is the test needed to pass - snippet below */

You can use this to create drop shadows by appending an element to the DOM and styling that, with a lower z-index and setting an opacity.

Hope that helps!

Edit: Links

  • Modernizr Test - http://pastebin.com/w4eVbEKr
  • Some more information - https://www.webkit.org/blog/181/css-masks/


It's actually possible for those who can use preprocessors in production, by "inlining" background SVG, and bit of SASS mixins, which "slice" whole svg gibberish, to get access to parts you want to manipulate via SASS variables.

In your original scenario you have an element
<div class="element1"></div>,

so you need a mixin/function which will inline SVG for you. Let's say you want to control of the fill, so:

@mixin inline-svg($color, $svg-content) {
  $start: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><style>path { fill:#{$color}; }</style>';
  $end:   '</svg>';

  background-image: url('data:image/svg+xml;utf8, #{$start}#{$svg-content}#{$end}');
}

where $svg-content variable is your <svg> stuff excluding <style> element (which you want to access from inside of the mixin) and wrapping svg tag,, ie: $svg-content = "<path .... />"

This just need to be included with values passed inside:
@include inline-svg(salmon, $svg-content);

To sum whole thing up, this is an example SASS code:

$svg-content = "<path .... />"

@mixin inline-svg($color, $svg-content) {
    $start: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><style>path { fill:#{$color}; }</style>';
    $end:   '</svg>';

    background-image: url('data:image/svg+xml;utf8, #{$start}#{$svg-content}#{$end}');
}  

.element1 {
    @include inline-svg(rgba(0,0,0,0.6), $svg-content);
}

I think possibilities here are quite big (there are also limitations here to that approach). I actually pass a SASS map to my mixin with css styles defined as key, value pair, to inject whole bunch of css styles to the <style> part of svg.

So it's technically possible, but require more compexity, but once you get this done, you'll get benefits of reusing this mixin throughout your project(s), which is cool .


Styling the SVG via a separate CSS class didn't work for me, but inline styling did:

&::after {
      content: url("data:image/svg+xml;charset=UTF-8, <svg viewBox='0 0 14 24' xmlns='http://www.w3.org/2000/svg' width='12px' height='18px'><path fill='rgb(13, 132, 254)' d='M2.1.1L0 2.2l8.3 8.3L9.8 12l-1.5 1.5L0 21.8l2.1 2.1L14 12z' /></svg>");
    }

Note: specifying the fill prop as a hexcode colour didn't work, even though it did if in a 'normal' SVG, that's why I converted it to RGB and styled it that way.


Reading all of these answers made me come up with this nice way of dealing with SVG in SASS (.scss), which compiles CSS, for my styling theme and also get the color working. For my use case, I want (need) to use content: url(..svg) since my lib supports Font and now SVG by using content: $my-icon; in a pseudo :before that is the only thing that works with both Font/SVG.

First is to create a SASS function to deal with urlencode of the color (since content: url() needs to be encoded, # needs to become %23). For reference, I copied this function from someone else Gist. For example this will take #fafafa and return %23fafafa that I can then use in fill of the SVG. You could also go without it, just remember to change # to %23 in the fill property.

/* sass-utilities.scss */
@function encodecolor($string) {
    @if type-of($string) == 'color' {
        $hex: str-slice(ie-hex-str($string), 4);
        $string:unquote("#{$hex}");
    }
    $string: '%23' + $string;
    @return $string;
}

My lib has a few SASS variables defined for theme styling so this is what I got working with both Font and/or SVG (I added width and display but it might work without too).

.sort-indicator-desc:before {
    content: $icon-sort-desc;
    display: inline-block;
    width: $icon-sort-font-size;    
    font-size: $icon-sort-font-size;
}

and finally the end user can still use it with a Font Family (like Font Awesome 4)

/* with a Font */
$icon-font-family:     "FontAwesome"; //  Font Awesome 4 
$icon-sort-color:      #0070d2;
$icon-sort-font-size:  13px;
$icon-sort-asc:        "\f0d8";       // unicode value of the icon
$icon-sort-desc:       "\f0d7";
// this compiles to => `content: "\f0d8";

or with SVG (like Font Awesome 5)

@import './sass-utilities'; // sass helper

/* with SVG */
$icon-sort-color:     #0070d2;
$icon-sort-font-size: 13px;
$icon-sort-asc:       url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" fill="#{encodecolor($icon-sort-color)}" viewBox="0 0 24 24" id="arrowdown"><path d="M19.1 9.7c.4-.4.4-.9 0-1.3l-6.9-6.7c-.4-.4-.9-.4-1.3 0L4 8.4c-.4.4-.4.9 0 1.3l1.3 1.2c.3.4.9.4 1.3 0l2.1-2.1c.4-.4 1-.1 1 .4v12.5c0 .5.5.9 1 .9h1.8c.5 0 .9-.5.9-.9V9.2c0-.5.7-.8 1-.4l2.2 2.1c.4.4.9.4 1.3 0l1.2-1.2z"></path></svg>');
$icon-sort-desc:      url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" fill="#{encodecolor($icon-sort-color)}" viewBox="0 0 24 24" id="arrowdown"><path d="M4.4 14.3c-.3.4-.3.9 0 1.3l7 6.7c.3.4.9.4 1.2 0l7-6.7c.4-.4.4-.9 0-1.3l-1.3-1.2c-.3-.4-.9-.4-1.3 0l-2.1 2.1c-.4.4-1.1.1-1.1-.4V2.3c0-.5-.4-.9-.9-.9h-1.8c-.5 0-.9.5-.9.9v12.5c0 .5-.7.8-1.1.4L7 13.1c-.4-.4-1-.4-1.3 0l-1.3 1.2z"></path></svg>');
// this compiles to => `content: url('data:image/svg+xml,<svg>...');

So at the end, I got both the Font & SVG working with SASS variables and that is great because that means that any users of my lib (Angular-Slickgrid) can still use Font Awesome 4 icons (font) while others could also use SVGs (like Font Awesome 5) without having to install the Font Family (.eof, .woff, ...) which tend to be large depending on the lib. The end result is still a compiled CSS file with content to load the SVG with an extra fill property for the SVG color.

and voilà!!! I get the best of both :)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜