4
\$\begingroup\$

I'm new to and still fairly confounded by SVGs. I'm feeling pretty happy with the following hobbled together SCSS code demonstrated here:

//Functions to create svg backgrounds:

@function _buildSVG($bg, $width:'100%', $height:'100%', $viewboxx:'0', $viewboxy:'0', $viewboxw:'274', $viewboxh:'510') {
  $bg: '%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20viewBox%3D%22#{$viewboxx}%20#{$viewboxy}%20#{$viewboxw}%20#{$viewboxh}%22%20width%3D%22#{$width}%22%20height%3D%22#{$height}%22%3E%23#{$bg}%3C%2Fsvg%3E';
  @return $bg;
}

@function _buildPath($path, $parameters) {
  $icon: '%3Cpath%20fill%3D%22#{map-get($parameters, color)}%22%20stroke%3D%22#{map-get($parameters, stroke-color)}%22%20stroke-width%3D%22#{map-get($parameters, stroke-width)}%22%20style%3D%22#{map-get($parameters, css)}%22%20d%3D%22#{$path}%22%20%2F%3E';
  @return $icon;
}

@function renderSVG(
  $backgroundName,
  $color,
  $stroke-color: white,
  $stroke-width: 2px,
  $width: '100%',
  $height: '100%',
  $viewboxx: 0,
  $viewboxy: 0,
  $viewboxw: 274,
  $viewboxh: 510,
  $css: '' // arbitrary css
  ){
    $parameters: (
      'color': $color,
      'stroke-color': $stroke-color,
      'stroke-width': $stroke-width,
      'css': $css
    );

    $backgrounds: (
      bishop: _buildPath('M142.875,133.254c-2.445,0.459 -9.707,1.823 -11.649,2.187c-4.049,0.795 -4.049,0.795 -4.968,-3.423c-4.487,-23.915 -12.495,-66.626 -15.751,-83.996c-0.718,-3.829 -0.718,-3.829 -5.285,0.011c-15.435,13.555 -31.879,34.306 -31.879,63.278c0,21.094 4.218,42.188 16.875,67.5c0,0 -8.438,0 -8.438,4.219c0,4.219 8.438,4.219 8.438,4.219c0,0 0,12.656 -4.219,16.875c0,0 -12.656,0 -12.656,8.437c0,8.438 12.656,8.438 12.656,8.438c-12.656,0 -25.313,0 -25.313,12.656c0,12.656 12.657,12.656 25.313,12.656c8.437,16.875 8.437,101.25 -12.656,147.657c-4.219,4.218 -12.657,4.218 -12.657,4.218c0,37.969 -54.843,46.407 -54.843,71.719c0,12.656 21.093,21.094 21.093,21.094c0,0 -25.312,4.219 -25.312,8.437l0,4.219c0,4.219 0,4.219 4.219,4.219l261.562,0c4.219,0 4.219,0 4.219,-4.219l0,-4.219c0,-4.218 -25.313,-8.437 -25.313,-8.437c0,0 21.094,-8.438 21.094,-21.094c0,-25.312 -54.844,-33.75 -54.844,-71.719c0,0 -8.437,0 -12.656,-4.218c-21.094,-46.407 -21.094,-130.782 -12.656,-147.657c12.656,0 25.312,0 25.312,-12.656c0,-12.656 -12.656,-12.656 -25.312,-12.656c0,0 12.656,0 12.656,-8.438c0,-8.437 -12.656,-8.437 -12.656,-8.437c-4.219,-4.219 -4.219,-16.875 -4.219,-16.875c0,0 8.438,0 8.438,-4.219c0,-4.219 -8.438,-4.219 -8.438,-4.219c12.656,-25.312 16.875,-46.406 16.875,-67.5c0,-46.406 -42.187,-71.718 -54.844,-80.156c12.657,-16.875 4.219,-29.531 -8.437,-29.531c-12.656,0 -21.094,12.656 -8.438,29.531c2.022,10.786 13.758,73.382 18.226,97.212c0.701,4.066 0.701,4.066 -3.537,4.887l0,0Z', $parameters),
      star: _buildPath('M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z', $parameters)
    );

    $background: _buildSVG(map-get($backgrounds, $backgroundName),
                            $width,
                            $height,
                            $viewboxx,
                            $viewboxy,
                            $viewboxw,
                            $viewboxh);
    @return url("data:image/svg+xml;charset=utf8,#{$background}");
  }

// ----
// Sass (v3.4.7)
// Compass (v1.0.1)
// ----

/// Convert angle
/// @author Chris Eppstein
/// @param {Number} $value - Value to convert
/// @param {String} $unit - Unit to convert to
/// @return {Number} Converted angle
@function convert-angle($value, $unit) {
  $convertable-units: deg grad turn rad;
  $conversion-factors: 1 (10grad/9deg) (1turn/360deg) (3.1415926rad/180deg);
  @if index($convertable-units, unit($value)) and index($convertable-units, $unit) {
    @return $value
             / nth($conversion-factors, index($convertable-units, unit($value)))
             * nth($conversion-factors, index($convertable-units, $unit));
  }

  @warn "Cannot convert `#{unit($value)}` to `#{$unit}`.";
}

/// Test if `$value` is an angle
/// @param {*} $value - Value to test
/// @return {Bool}
@function is-direction($value) {
  $is-direction: index((to top, to top right, to right top, to right, to bottom right, to right bottom, to bottom, to bottom left, to left bottom, to left, to left top, to top left), $value);
  $is-angle: type-of($value) == 'number' and index('deg' 'grad' 'turn' 'rad', unit($value));

  @return $is-direction or $is-angle;
}

/// Convert a direction to legacy syntax
/// @param {Keyword | Angle} $value - Value to convert
/// @require {function} is-direction
/// @require {function} convert-angle
@function legacy-direction($value) {
  @if is-direction($value) == false {
    @warn "Cannot convert `#{$value}` to legacy syntax because it doesn't seem to be an angle or a direction";
  }

  $conversion-map: (
    to top          : bottom,
    to top right    : bottom left,
    to right top    : left bottom,
    to right        : left,
    to bottom right : top left,
    to right bottom : left top,
    to bottom       : top,
    to bottom left  : top right,
    to left bottom  : right top,
    to left         : right,
    to left top     : right bottom,
    to top left     : bottom right
  );

  @if map-has-key($conversion-map, $value) {
    @return map-get($conversion-map, $value);
  }

  @return 90deg - convert-angle($value, 'deg');
}

/// Mixin printing a linear-gradient
/// as well as a plain color fallback
/// and the `-webkit-` prefixed declaration
/// @access public
/// @param {String | List | Angle} $direction - Linear gradient direction
/// @param {Arglist} $color-stops - List of color-stops composing the gradient
@mixin linear-gradient($direction, $color-stops...) {
  @if is-direction($direction) == false {
    $color-stops: ($direction, $color-stops);
    $direction: 180deg;
  }

  background: nth(nth($color-stops, 1), 1);
  background: -webkit-linear-gradient(legacy-direction($direction), $color-stops);
  background: linear-gradient($direction, $color-stops);
}

@mixin linear-gradient-svg(
  $shape,
  $color,
  $stroke-color: transparent,
  $stroke-width: 0,
  $repeat-scroll-placement-size: no-repeat scroll 100% / 100% auto,
  $width: 100%,
  $height: 100%,
  $viewboxx: 0,
  $viewboxy: 0,
  $viewboxw: 274,
  $viewboxh: 510,
  $css: '',
  $direction: 180deg,
  $color-stops...) {
  @if is-direction($direction) == false {
    $color-stops: ($direction, $color-stops);
    $direction: 180deg;
  }

  background: renderSVG($shape, $color) $repeat-scroll-placement-size, nth(nth($color-stops, 1), 1);
  background: renderSVG($shape, $color) $repeat-scroll-placement-size, -webkit-linear-gradient(legacy-direction($direction), $color-stops);
  background: renderSVG($shape, $color) $repeat-scroll-placement-size, linear-gradient($direction, $color-stops);
}

// Test

.wrap {
  @include linear-gradient-svg(bishop, none, black, 2, no-repeat scroll 10px 100% / 10% auto, '', '', '', '', '', '', '', 42deg, #B58234 0%, #D2B545 50%, #D7C04D 50.01%, #FFFFFF 100%);
}

Did I mention that I'm also still getting my feet wet with SCSS? The thing that bothers me the most about the above @mixin are the dozen parameters that need to be supplied in order that the final parameters can be recognized.

From what I understand, the ugly (to me, anyway) urlEncoded strings are necessary for compatibility with IE (of course).

Maybe it would be better to just send the viewbox parameters as a single string and urlEncode it within SCSS. Aside from a gulp, npm plugin, I'm not seeing a native way to do that.

\$\endgroup\$
0
\$\begingroup\$

Well one improvement, aside from adding some ///Documenation is that using the following little function:

///Functions to create svg backgrounds:

/// Replace `$search` with `$replace` in `$string`
/// @author Hugo Giraudel
/// @param {String} $string - Initial string
/// @param {String} $search - Substring to replace
/// @param {String} $replace ('') - New value
/// @return {String} - Updated string
@function str-replace($string, $search, $replace: '') {
  $index: str-index($string, $search);

  @if $index {
    @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
  }

  @return $string;
}

/// Create a urlEncoded SVG DOM element
/// @author Mike iLL
/// @param {String} $bg - SVG PATH, including parameters
/// @param {String} $width - Width of SVG DOM Element
/// @param {String} $height - Height of SVG DOM Element
/// @param {String} $viewbox - Four values, separated by spaces, compatible with svg viewbox specifications
/// @return {String} urlEncoded SVG DOM Object
@function _buildSVG($bg, $width:'100%', $height:'100%', $viewbox:'0 0 100 100') {
  $width: str-replace($width, '%', '%25');
  $height: str-replace($height, '%', '%25');
  $viewbox: str-replace($viewbox, ' ', '%20');
  $bg: '%3Csvg%20width%3D%22#{$width}%22%20height%3D%22#{$width}%22%20viewBox%3D%22#{$viewbox}%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E#{$bg}%3C%2Fsvg%3E%0A%0A';
  @return $bg;
}

I can send the viewbox values as a single parameter.

.wrap {
  @include linear-gradient-svg(bishop, none, white, 2, no-repeat scroll 10px 100% / 10% auto, '100%', '100%', '0 0 274 510', '', 42deg, #B58234 0%, #D2B545 50%, #D7C04D 50.01%, #FFFFFF 100%);
}

Apparently there are also Sass libraries out there (of course!) that provide various mixins, functions, etc. Bourbon looks pretty interesting.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.