| 1 | // vendor.scss v1.0 | @ajlkn | MIT licensed */ |
| 2 | |
| 3 | // Vars. |
| 4 | |
| 5 | /// Vendor prefixes. |
| 6 | /// @var {list} |
| 7 | $vendor-prefixes: ( |
| 8 | '-moz-', |
| 9 | '-webkit-', |
| 10 | '-ms-', |
| 11 | '' |
| 12 | ); |
| 13 | |
| 14 | /// Properties that should be vendorized. |
| 15 | /// Data via caniuse.com, github.com/postcss/autoprefixer, and developer.mozilla.org |
| 16 | /// @var {list} |
| 17 | $vendor-properties: ( |
| 18 | |
| 19 | // Animation. |
| 20 | 'animation', |
| 21 | 'animation-delay', |
| 22 | 'animation-direction', |
| 23 | 'animation-duration', |
| 24 | 'animation-fill-mode', |
| 25 | 'animation-iteration-count', |
| 26 | 'animation-name', |
| 27 | 'animation-play-state', |
| 28 | 'animation-timing-function', |
| 29 | |
| 30 | // Appearance. |
| 31 | 'appearance', |
| 32 | |
| 33 | // Backdrop filter. |
| 34 | 'backdrop-filter', |
| 35 | |
| 36 | // Background image options. |
| 37 | 'background-clip', |
| 38 | 'background-origin', |
| 39 | 'background-size', |
| 40 | |
| 41 | // Box sizing. |
| 42 | 'box-sizing', |
| 43 | |
| 44 | // Clip path. |
| 45 | 'clip-path', |
| 46 | |
| 47 | // Filter effects. |
| 48 | 'filter', |
| 49 | |
| 50 | // Flexbox. |
| 51 | 'align-content', |
| 52 | 'align-items', |
| 53 | 'align-self', |
| 54 | 'flex', |
| 55 | 'flex-basis', |
| 56 | 'flex-direction', |
| 57 | 'flex-flow', |
| 58 | 'flex-grow', |
| 59 | 'flex-shrink', |
| 60 | 'flex-wrap', |
| 61 | 'justify-content', |
| 62 | 'order', |
| 63 | |
| 64 | // Font feature. |
| 65 | 'font-feature-settings', |
| 66 | 'font-language-override', |
| 67 | 'font-variant-ligatures', |
| 68 | |
| 69 | // Font kerning. |
| 70 | 'font-kerning', |
| 71 | |
| 72 | // Fragmented borders and backgrounds. |
| 73 | 'box-decoration-break', |
| 74 | |
| 75 | // Grid layout. |
| 76 | 'grid-column', |
| 77 | 'grid-column-align', |
| 78 | 'grid-column-end', |
| 79 | 'grid-column-start', |
| 80 | 'grid-row', |
| 81 | 'grid-row-align', |
| 82 | 'grid-row-end', |
| 83 | 'grid-row-start', |
| 84 | 'grid-template-columns', |
| 85 | 'grid-template-rows', |
| 86 | |
| 87 | // Hyphens. |
| 88 | 'hyphens', |
| 89 | 'word-break', |
| 90 | |
| 91 | // Masks. |
| 92 | 'mask', |
| 93 | 'mask-border', |
| 94 | 'mask-border-outset', |
| 95 | 'mask-border-repeat', |
| 96 | 'mask-border-slice', |
| 97 | 'mask-border-source', |
| 98 | 'mask-border-width', |
| 99 | 'mask-clip', |
| 100 | 'mask-composite', |
| 101 | 'mask-image', |
| 102 | 'mask-origin', |
| 103 | 'mask-position', |
| 104 | 'mask-repeat', |
| 105 | 'mask-size', |
| 106 | |
| 107 | // Multicolumn. |
| 108 | 'break-after', |
| 109 | 'break-before', |
| 110 | 'break-inside', |
| 111 | 'column-count', |
| 112 | 'column-fill', |
| 113 | 'column-gap', |
| 114 | 'column-rule', |
| 115 | 'column-rule-color', |
| 116 | 'column-rule-style', |
| 117 | 'column-rule-width', |
| 118 | 'column-span', |
| 119 | 'column-width', |
| 120 | 'columns', |
| 121 | |
| 122 | // Object fit. |
| 123 | 'object-fit', |
| 124 | 'object-position', |
| 125 | |
| 126 | // Regions. |
| 127 | 'flow-from', |
| 128 | 'flow-into', |
| 129 | 'region-fragment', |
| 130 | |
| 131 | // Scroll snap points. |
| 132 | 'scroll-snap-coordinate', |
| 133 | 'scroll-snap-destination', |
| 134 | 'scroll-snap-points-x', |
| 135 | 'scroll-snap-points-y', |
| 136 | 'scroll-snap-type', |
| 137 | |
| 138 | // Shapes. |
| 139 | 'shape-image-threshold', |
| 140 | 'shape-margin', |
| 141 | 'shape-outside', |
| 142 | |
| 143 | // Tab size. |
| 144 | 'tab-size', |
| 145 | |
| 146 | // Text align last. |
| 147 | 'text-align-last', |
| 148 | |
| 149 | // Text decoration. |
| 150 | 'text-decoration-color', |
| 151 | 'text-decoration-line', |
| 152 | 'text-decoration-skip', |
| 153 | 'text-decoration-style', |
| 154 | |
| 155 | // Text emphasis. |
| 156 | 'text-emphasis', |
| 157 | 'text-emphasis-color', |
| 158 | 'text-emphasis-position', |
| 159 | 'text-emphasis-style', |
| 160 | |
| 161 | // Text size adjust. |
| 162 | 'text-size-adjust', |
| 163 | |
| 164 | // Text spacing. |
| 165 | 'text-spacing', |
| 166 | |
| 167 | // Transform. |
| 168 | 'transform', |
| 169 | 'transform-origin', |
| 170 | |
| 171 | // Transform 3D. |
| 172 | 'backface-visibility', |
| 173 | 'perspective', |
| 174 | 'perspective-origin', |
| 175 | 'transform-style', |
| 176 | |
| 177 | // Transition. |
| 178 | 'transition', |
| 179 | 'transition-delay', |
| 180 | 'transition-duration', |
| 181 | 'transition-property', |
| 182 | 'transition-timing-function', |
| 183 | |
| 184 | // Unicode bidi. |
| 185 | 'unicode-bidi', |
| 186 | |
| 187 | // User select. |
| 188 | 'user-select', |
| 189 | |
| 190 | // Writing mode. |
| 191 | 'writing-mode', |
| 192 | |
| 193 | ); |
| 194 | |
| 195 | /// Values that should be vendorized. |
| 196 | /// Data via caniuse.com, github.com/postcss/autoprefixer, and developer.mozilla.org |
| 197 | /// @var {list} |
| 198 | $vendor-values: ( |
| 199 | |
| 200 | // Cross fade. |
| 201 | 'cross-fade', |
| 202 | |
| 203 | // Element function. |
| 204 | 'element', |
| 205 | |
| 206 | // Filter function. |
| 207 | 'filter', |
| 208 | |
| 209 | // Flexbox. |
| 210 | 'flex', |
| 211 | 'inline-flex', |
| 212 | |
| 213 | // Grab cursors. |
| 214 | 'grab', |
| 215 | 'grabbing', |
| 216 | |
| 217 | // Gradients. |
| 218 | 'linear-gradient', |
| 219 | 'repeating-linear-gradient', |
| 220 | 'radial-gradient', |
| 221 | 'repeating-radial-gradient', |
| 222 | |
| 223 | // Grid layout. |
| 224 | 'grid', |
| 225 | 'inline-grid', |
| 226 | |
| 227 | // Image set. |
| 228 | 'image-set', |
| 229 | |
| 230 | // Intrinsic width. |
| 231 | 'max-content', |
| 232 | 'min-content', |
| 233 | 'fit-content', |
| 234 | 'fill', |
| 235 | 'fill-available', |
| 236 | 'stretch', |
| 237 | |
| 238 | // Sticky position. |
| 239 | 'sticky', |
| 240 | |
| 241 | // Transform. |
| 242 | 'transform', |
| 243 | |
| 244 | // Zoom cursors. |
| 245 | 'zoom-in', |
| 246 | 'zoom-out', |
| 247 | |
| 248 | ); |
| 249 | |
| 250 | // Functions. |
| 251 | |
| 252 | /// Removes a specific item from a list. |
| 253 | /// @author Hugo Giraudel |
| 254 | /// @param {list} $list List. |
| 255 | /// @param {integer} $index Index. |
| 256 | /// @return {list} Updated list. |
| 257 | @function remove-nth($list, $index) { |
| 258 | |
| 259 | $result: null; |
| 260 | |
| 261 | @if type-of($index) != number { |
| 262 | @warn "$index: #{quote($index)} is not a number for `remove-nth`."; |
| 263 | } |
| 264 | @else if $index == 0 { |
| 265 | @warn "List index 0 must be a non-zero integer for `remove-nth`."; |
| 266 | } |
| 267 | @else if abs($index) > length($list) { |
| 268 | @warn "List index is #{$index} but list is only #{length($list)} item long for `remove-nth`."; |
| 269 | } |
| 270 | @else { |
| 271 | |
| 272 | $result: (); |
| 273 | $index: if($index < 0, length($list) + $index + 1, $index); |
| 274 | |
| 275 | @for $i from 1 through length($list) { |
| 276 | |
| 277 | @if $i != $index { |
| 278 | $result: append($result, nth($list, $i)); |
| 279 | } |
| 280 | |
| 281 | } |
| 282 | |
| 283 | } |
| 284 | |
| 285 | @return $result; |
| 286 | |
| 287 | } |
| 288 | |
| 289 | /// Replaces a substring within another string. |
| 290 | /// @author Hugo Giraudel |
| 291 | /// @param {string} $string String. |
| 292 | /// @param {string} $search Substring. |
| 293 | /// @param {string} $replace Replacement. |
| 294 | /// @return {string} Updated string. |
| 295 | @function str-replace($string, $search, $replace: '') { |
| 296 | |
| 297 | $index: str-index($string, $search); |
| 298 | |
| 299 | @if $index { |
| 300 | @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace); |
| 301 | } |
| 302 | |
| 303 | @return $string; |
| 304 | |
| 305 | } |
| 306 | |
| 307 | /// Replaces a substring within each string in a list. |
| 308 | /// @param {list} $strings List of strings. |
| 309 | /// @param {string} $search Substring. |
| 310 | /// @param {string} $replace Replacement. |
| 311 | /// @return {list} Updated list of strings. |
| 312 | @function str-replace-all($strings, $search, $replace: '') { |
| 313 | |
| 314 | @each $string in $strings { |
| 315 | $strings: set-nth($strings, index($strings, $string), str-replace($string, $search, $replace)); |
| 316 | } |
| 317 | |
| 318 | @return $strings; |
| 319 | |
| 320 | } |
| 321 | |
| 322 | // Mixins. |
| 323 | |
| 324 | /// Wraps @content in vendorized keyframe blocks. |
| 325 | /// @param {string} $name Name. |
| 326 | @mixin keyframes($name) { |
| 327 | |
| 328 | @-moz-keyframes #{$name} { @content; } |
| 329 | @-webkit-keyframes #{$name} { @content; } |
| 330 | @-ms-keyframes #{$name} { @content; } |
| 331 | @keyframes #{$name} { @content; } |
| 332 | |
| 333 | } |
| 334 | |
| 335 | /// Vendorizes a declaration's property and/or value(s). |
| 336 | /// @param {string} $property Property. |
| 337 | /// @param {mixed} $value String/list of value(s). |
| 338 | @mixin vendor($property, $value) { |
| 339 | |
| 340 | // Determine if property should expand. |
| 341 | $expandProperty: index($vendor-properties, $property); |
| 342 | |
| 343 | // Determine if value should expand (and if so, add '-prefix-' placeholder). |
| 344 | $expandValue: false; |
| 345 | |
| 346 | @each $x in $value { |
| 347 | @each $y in $vendor-values { |
| 348 | @if $y == str-slice($x, 1, str-length($y)) { |
| 349 | |
| 350 | $value: set-nth($value, index($value, $x), '-prefix-' + $x); |
| 351 | $expandValue: true; |
| 352 | |
| 353 | } |
| 354 | } |
| 355 | } |
| 356 | |
| 357 | // Expand property? |
| 358 | @if $expandProperty { |
| 359 | @each $vendor in $vendor-prefixes { |
| 360 | #{$vendor}#{$property}: #{str-replace-all($value, '-prefix-', $vendor)}; |
| 361 | } |
| 362 | } |
| 363 | |
| 364 | // Expand just the value? |
| 365 | @elseif $expandValue { |
| 366 | @each $vendor in $vendor-prefixes { |
| 367 | #{$property}: #{str-replace-all($value, '-prefix-', $vendor)}; |
| 368 | } |
| 369 | } |
| 370 | |
| 371 | // Neither? Treat them as a normal declaration. |
| 372 | @else { |
| 373 | #{$property}: #{$value}; |
| 374 | } |
| 375 | |
| 376 | } |