Skip to content

Commit f6694b7

Browse files
MartijnCuppensmdo
authored andcommitted
Use escape-svg() function (#29077)
* Use escape-svg() function * Update theming.md
1 parent 28dfa54 commit f6694b7

File tree

9 files changed

+51
-31
lines changed

9 files changed

+51
-31
lines changed

scss/_breadcrumb.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
display: inline-block; // Suppress underlining of the separator in modern browsers
1818
padding-right: $breadcrumb-item-padding-x;
1919
color: $breadcrumb-divider-color;
20-
content: $breadcrumb-divider;
20+
content: escape-svg($breadcrumb-divider);
2121
}
2222
}
2323

scss/_carousel.scss

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,10 +131,10 @@
131131
background: no-repeat 50% / 100% 100%;
132132
}
133133
.carousel-control-prev-icon {
134-
background-image: $carousel-control-prev-icon-bg;
134+
background-image: escape-svg($carousel-control-prev-icon-bg);
135135
}
136136
.carousel-control-next-icon {
137-
background-image: $carousel-control-next-icon-bg;
137+
background-image: escape-svg($carousel-control-next-icon-bg);
138138
}
139139

140140

scss/_functions.scss

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,17 @@
7171
@return $string;
7272
}
7373

74+
// See https://codepen.io/kevinweber/pen/dXWoRw
75+
@function escape-svg($string) {
76+
@if str-index($string, "data:image/svg+xml") {
77+
@each $char, $encoded in $escaped-characters {
78+
$string: str-replace($string, $char, $encoded);
79+
}
80+
}
81+
82+
@return $string;
83+
}
84+
7485
// Color contrast
7586
@function color-yiq($color, $dark: $yiq-text-dark, $light: $yiq-text-light) {
7687
$r: red($color);

scss/_navbar.scss

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@
229229
}
230230

231231
.navbar-toggler-icon {
232-
background-image: $navbar-light-toggler-icon-bg;
232+
background-image: escape-svg($navbar-light-toggler-icon-bg);
233233
}
234234

235235
.navbar-text {
@@ -282,7 +282,7 @@
282282
}
283283

284284
.navbar-toggler-icon {
285-
background-image: $navbar-dark-toggler-icon-bg;
285+
background-image: escape-svg($navbar-dark-toggler-icon-bg);
286286
}
287287

288288
.navbar-text {

scss/_variables.scss

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,12 @@ $yiq-contrasted-threshold: 150 !default;
101101
$yiq-text-dark: $gray-900 !default;
102102
$yiq-text-light: $white !default;
103103

104+
// Characters which are escaped by the escape-svg function
105+
$escaped-characters: (
106+
("<","%3c"),
107+
(">","%3e"),
108+
("#","%23"),
109+
) !default;
104110

105111
// Options
106112
//
@@ -531,32 +537,32 @@ $form-check-input-checked-border-color: $form-check-input-checked-bg-color !de
531537
$form-check-input-checked-bg-repeat: no-repeat !default;
532538
$form-check-input-checked-bg-position: center center !default;
533539
$form-check-input-checked-bg-size: 1em !default;
534-
$form-check-input-checked-bg-image: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath stroke='#{$form-check-input-checked-color}' stroke-width='3' d='M4 8.5L6.5 11l6-6' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3e%3c/svg%3e"), "#", "%23") !default;
535-
$form-check-radio-checked-bg-image: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='#{$form-check-input-checked-color}'/%3e%3c/svg%3e"), "#", "%23") !default;
540+
$form-check-input-checked-bg-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path stroke='#{$form-check-input-checked-color}' stroke-width='3' d='M4 8.5L6.5 11l6-6' fill='none' stroke-linecap='round' stroke-linejoin='round'/></svg>") !default;
541+
$form-check-radio-checked-bg-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'><circle r='3' fill='#{$form-check-input-checked-color}'/></svg>") !default;
536542

537543
$form-check-input-indeterminate-color: $component-active-color !default;
538544
$form-check-input-indeterminate-bg-color: $component-active-bg !default;
539545
$form-check-input-indeterminate-border-color: $form-check-input-indeterminate-bg-color !default;
540546
$form-check-input-indeterminate-bg-repeat: no-repeat !default;
541547
$form-check-input-indeterminate-bg-position: center center !default;
542548
$form-check-input-indeterminate-bg-size: 1em !default;
543-
$form-check-input-indeterminate-bg-image: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath d='M5 8h6' stroke='#{$form-check-input-indeterminate-color}' stroke-width='3' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3e%3c/svg%3e"), "#", "%23") !default;
549+
$form-check-input-indeterminate-bg-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M5 8h6' stroke='#{$form-check-input-indeterminate-color}' stroke-width='3' fill='none' stroke-linecap='round' stroke-linejoin='round'/></svg>") !default;
544550

545551
$form-switch-color: rgba(0, 0, 0, .25) !default;
546552
$form-switch-width: 2em !default;
547553
$form-switch-height: $form-check-input-width !default;
548554
$form-switch-padding-left: $form-switch-width + .5em !default;
549-
$form-switch-bg-image: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='#{$form-switch-color}'/%3e%3c/svg%3e"), "#", "%23") !default;
555+
$form-switch-bg-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'><circle r='3' fill='#{$form-switch-color}'/></svg>") !default;
550556
$form-switch-border-radius: $form-switch-width !default;
551557
$form-switch-transition: .2s ease-in-out !default;
552558
$form-switch-transition-property: background-position, background-color !default;
553559

554560
$form-switch-focus-color: hsla(211, 100%, 75%, 1) !default;
555-
$form-switch-focus-bg-image: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='#{$form-switch-focus-color}'/%3e%3c/svg%3e"), "#", "%23") !default;
561+
$form-switch-focus-bg-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'><circle r='3' fill='#{$form-switch-focus-color}'/></svg>") !default;
556562

557563
$form-switch-checked-color: $component-active-color !default;
558-
$form-switch-checked-bg-image: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='#{$form-switch-checked-color}'/%3e%3c/svg%3e"), "#", "%23") !default;
559-
$form-switch-checked-bg-position: right center !default;
564+
$form-switch-checked-bg-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'><circle r='3' fill='#{$form-switch-checked-color}'/></svg>") !default;
565+
$form-switch-checked-bg-position: right center !default;
560566

561567
$form-text-margin-top: .25rem !default;
562568

@@ -586,9 +592,9 @@ $form-select-bg: $input-bg !default;
586592
$form-select-disabled-bg: $gray-200 !default;
587593
$form-select-bg-size: 16px 12px !default; // In pixels because image dimensions
588594
$form-select-indicator-color: $gray-800 !default;
589-
$form-select-indicator: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath stroke='#{$form-select-indicator-color}' stroke-width='2px' d='M2 5l6 6 6-6' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3e%3c/svg%3e"), "#", "%23") !default;
595+
$form-select-indicator: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path stroke='#{$form-select-indicator-color}' stroke-width='2px' d='M2 5l6 6 6-6' fill='none' stroke-linecap='round' stroke-linejoin='round'/></svg>") !default;
590596

591-
$form-select-background: $form-select-indicator no-repeat right $form-select-padding-x center / $form-select-bg-size !default; // Used so we can have multiple background elements (e.g., arrow and feedback icon)
597+
$form-select-background: no-repeat right $form-select-padding-x center / $form-select-bg-size !default; // Used so we can have multiple background elements (e.g., arrow and feedback icon)
592598

593599
$form-select-feedback-icon-padding-right: calc((1em + #{2 * $form-select-padding-y}) * 3 / 4 + #{$form-select-padding-x + $form-select-indicator-padding}) !default;
594600
$form-select-feedback-icon-position: center right ($form-select-padding-x + $form-select-indicator-padding) !default;
@@ -659,9 +665,9 @@ $form-feedback-valid-color: theme-color("success") !default;
659665
$form-feedback-invalid-color: theme-color("danger") !default;
660666

661667
$form-feedback-icon-valid-color: $form-feedback-valid-color !default;
662-
$form-feedback-icon-valid: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='#{$form-feedback-icon-valid-color}' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e"), "#", "%23") !default;
668+
$form-feedback-icon-valid: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'><path fill='#{$form-feedback-icon-valid-color}' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/></svg>") !default;
663669
$form-feedback-icon-invalid-color: $form-feedback-invalid-color !default;
664-
$form-feedback-icon-invalid: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' stroke='#{$form-feedback-icon-invalid-color}' fill='none'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath d='M5.8 3.6h.4L6 6.5z' stroke-linejoin='round'/%3e%3ccircle cx='6' cy='8.2' r='.1'/%3e%3c/svg%3e"), "#", "%23") !default;
670+
$form-feedback-icon-invalid: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' stroke='#{$form-feedback-icon-invalid-color}' fill='none'><circle cx='6' cy='6' r='4.5'/><path d='M5.8 3.6h.4L6 6.5z' stroke-linejoin='round'/><circle cx='6' cy='8.2' r='.1'/></svg>") !default;
665671

666672
$form-validation-states: () !default;
667673
// stylelint-disable-next-line scss/dollar-variable-default
@@ -737,14 +743,14 @@ $navbar-dark-color: rgba($white, .5) !default;
737743
$navbar-dark-hover-color: rgba($white, .75) !default;
738744
$navbar-dark-active-color: $white !default;
739745
$navbar-dark-disabled-color: rgba($white, .25) !default;
740-
$navbar-dark-toggler-icon-bg: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='#{$navbar-dark-color}' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"), "#", "%23") !default;
746+
$navbar-dark-toggler-icon-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'><path stroke='#{$navbar-dark-color}' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/></svg>") !default;
741747
$navbar-dark-toggler-border-color: rgba($white, .1) !default;
742748

743749
$navbar-light-color: rgba($black, .5) !default;
744750
$navbar-light-hover-color: rgba($black, .7) !default;
745751
$navbar-light-active-color: rgba($black, .9) !default;
746752
$navbar-light-disabled-color: rgba($black, .3) !default;
747-
$navbar-light-toggler-icon-bg: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='#{$navbar-light-color}' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"), "#", "%23") !default;
753+
$navbar-light-toggler-icon-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'><path stroke='#{$navbar-light-color}' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/></svg>") !default;
748754
$navbar-light-toggler-border-color: rgba($black, .1) !default;
749755

750756
$navbar-light-brand-color: $navbar-light-active-color !default;
@@ -1066,8 +1072,8 @@ $carousel-caption-color: $white !default;
10661072

10671073
$carousel-control-icon-width: 20px !default;
10681074

1069-
$carousel-control-prev-icon-bg: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='#{$carousel-control-color}' viewBox='0 0 8 8'%3e%3cpath d='M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3e%3c/svg%3e"), "#", "%23") !default;
1070-
$carousel-control-next-icon-bg: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='#{$carousel-control-color}' viewBox='0 0 8 8'%3e%3cpath d='M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3e%3c/svg%3e"), "#", "%23") !default;
1075+
$carousel-control-prev-icon-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' fill='#{$carousel-control-color}' viewBox='0 0 8 8'><path d='M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/></svg>") !default;
1076+
$carousel-control-next-icon-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' fill='#{$carousel-control-color}' viewBox='0 0 8 8'><path d='M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/></svg>") !default;
10711077

10721078
$carousel-transition-duration: .6s !default;
10731079
$carousel-transition: transform $carousel-transition-duration ease-in-out !default; // Define transform transition first if using multiple transitions (e.g., `transform 2s ease, opacity .5s ease-out`)

scss/forms/_form-check.scss

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,17 +46,17 @@
4646
border-color: $form-check-input-checked-border-color;
4747

4848
&[type="checkbox"] {
49-
background-image: $form-check-input-checked-bg-image;
49+
background-image: escape-svg($form-check-input-checked-bg-image);
5050
}
5151

5252
&[type="radio"] {
53-
background-image: $form-check-radio-checked-bg-image;
53+
background-image: escape-svg($form-check-radio-checked-bg-image);
5454
}
5555
}
5656

5757
&[type="checkbox"]:indeterminate {
5858
background-color: $form-check-input-indeterminate-bg-color;
59-
background-image: $form-check-input-indeterminate-bg-image;
59+
background-image: escape-svg($form-check-input-indeterminate-bg-image);
6060
background-repeat: $form-check-input-indeterminate-bg-repeat;
6161
background-position: $form-check-input-indeterminate-bg-position;
6262
background-size: $form-check-input-indeterminate-bg-size;
@@ -90,7 +90,7 @@
9090
.form-check-input {
9191
width: $form-switch-width;
9292
margin-left: $form-switch-padding-left * -1;
93-
background-image: $form-switch-bg-image;
93+
background-image: escape-svg($form-switch-bg-image);
9494
background-repeat: no-repeat;
9595
background-position: left center;
9696
background-size: calc(#{$form-switch-height} - 2px); // Get a 1px separation
@@ -100,11 +100,11 @@
100100
// transition-property: $form-switch-transition-property;
101101

102102
&:focus {
103-
background-image: $form-switch-focus-bg-image;
103+
background-image: escape-svg($form-switch-focus-bg-image);
104104
}
105105

106106
&:checked {
107-
background-image: $form-switch-checked-bg-image;
107+
background-image: escape-svg($form-switch-checked-bg-image);
108108
background-position: $form-switch-checked-bg-position;
109109
}
110110
}

scss/forms/_form-select.scss

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@
1414
line-height: $form-select-line-height;
1515
color: $form-select-color;
1616
vertical-align: middle;
17-
background: $form-select-background;
18-
background-color: $form-select-bg;
17+
background: $form-select-bg escape-svg($form-select-indicator) $form-select-background;
1918
border: $form-select-border-width solid $form-select-border-color;
2019
@include border-radius($form-select-border-radius, 0);
2120
@include box-shadow($form-select-box-shadow);

scss/mixins/_forms.scss

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@
6969

7070
@if $enable-validation-icons {
7171
padding-right: $input-height-inner;
72-
background-image: $icon;
72+
background-image: escape-svg($icon);
7373
background-repeat: no-repeat;
7474
background-position: right $input-height-inner-quarter center;
7575
background-size: $input-height-inner-half $input-height-inner-half;
@@ -103,7 +103,7 @@
103103

104104
@if $enable-validation-icons {
105105
padding-right: $form-select-feedback-icon-padding-right;
106-
background: $form-select-background, $icon $form-select-bg no-repeat $form-select-feedback-icon-position / $form-select-feedback-icon-size;
106+
background: escape-svg($form-select-indicator) $form-select-background, escape-svg($icon) $form-select-bg no-repeat $form-select-feedback-icon-position / $form-select-feedback-icon-size;
107107
}
108108

109109
&:focus {

site/content/docs/4.3/getting-started/theming.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ Additional functions could be added in the future or your own custom Sass to cre
195195

196196
### Color contrast
197197

198-
One additional function we include in Bootstrap is the color contrast function, `color-yiq`. It utilizes the [YIQ color space](https://en.wikipedia.org/wiki/YIQ) to automatically return a light (`#fff`) or dark (`#111`) contrast color based on the specified base color. This function is especially useful for mixins or loops where you're generating multiple classes.
198+
An additional function we include in Bootstrap is the color contrast function, `color-yiq`. It utilizes the [YIQ color space](https://en.wikipedia.org/wiki/YIQ) to automatically return a light (`#fff`) or dark (`#111`) contrast color based on the specified base color. This function is especially useful for mixins or loops where you're generating multiple classes.
199199

200200
For example, to generate color swatches from our `$theme-colors` map:
201201

@@ -223,6 +223,10 @@ You can also specify a base color with our color map functions:
223223
}
224224
{{< /highlight >}}
225225

226+
## Escape SVG
227+
228+
We use the `escape-svg` function to escape the `<`, `>` and `#` characters for SVG background images. These characters need to be escaped to properly render the background images in IE.
229+
226230
## Sass options
227231

228232
Customize Bootstrap 4 with our built-in custom variables file and easily toggle global CSS preferences with new `$enable-*` Sass variables. Override a variable's value and recompile with `npm run test` as needed.

0 commit comments

Comments
 (0)