Last active
October 26, 2020 08:38
-
-
Save davidkpiano/dbf20a242bcccd1d789c to your computer and use it in GitHub Desktop.
Generated by SassMeister.com.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ---- | |
// Sass (v3.4.7) | |
// Compass (v1.0.1) | |
// ---- | |
/// SCSS Specificity Calculator | |
/// | |
/// Utility to calculate (and display) specificity or specificity map of any | |
/// valid simple/compound/complex selector. | |
/// @author David Khourshid | |
/// Replaces a batch of substrings (needles) in a string (haystack) | |
/// with a single replacement string. | |
/// @access private | |
/// @param {String} $haystack - string to perform search and replacement on | |
/// @param {List | String} $needles - string or list of strings to replace globally | |
/// @param {String} $replacement ('') - replacement string to replace needles | |
/// @return {String} replaced string | |
@function str-replace-batch($haystack, $needles, $replacement: '') { | |
$instances: false; | |
@if not type_of($needles) == list { $needles: ($needles); } | |
@while ($instances == false) or ($instances > 0) { | |
$instances: 0; | |
@each $needle in $needles { | |
$needle-index: str-index($haystack, $needle); | |
$instances: $instances + if($needle-index, 1, 0); | |
@if $needle-index { | |
$haystack: str-slice($haystack, 1, $needle-index - 1) + str-slice($haystack, $needle-index + str-length($needle), -1); | |
$haystack: str-insert($haystack, $replacement, $needle-index); | |
} | |
} | |
} | |
@return $haystack; | |
} | |
/// Signifies what specificity type the simple selector is. | |
/// a - IDs | |
/// b - class selectors, attribute selectors, pseudo-classes | |
/// c - type (element) selectors, pseudo-elements | |
/// @access private | |
/// @param {String} $simple-selector - a single simple selector | |
/// @return {String} specificity type of simple selector - 'a', 'b', 'c', or false | |
@function specificity-type($simple-selector) { | |
$types: ( | |
c: (':before', ':after', ':first-line', ':first-letter', ':selection'), | |
b: ('.', '[', ':'), | |
a: ('#') | |
); | |
$simple-selector: str-replace-batch($simple-selector, '::', ':'); | |
@if str-index($simple-selector, ':not(') == 1 { | |
$simple-selector: str-slice($simple-selector, 6, -2); | |
} | |
@each $type-key, $type-tokens in $types { | |
@each $token in $type-tokens { | |
@if str-index($simple-selector, $token) == 1 { | |
@return $type-key; | |
} | |
} | |
} | |
// Ignore the universal selector | |
@if str-index($simple-selector, '*') == 1 { | |
@return false; | |
} | |
// Simple selector is type selector (element) | |
@return c; | |
} | |
/// Returns the specificity value (in the specified base). | |
/// Base is set to 256 (16^2) to accurately represent historical 6-digit | |
/// hexadecimal representation of specificity in most browsers, though this | |
/// limitation has been "resolved" in some browsers (try base 65536 for those). | |
/// @access private | |
/// @param {Map} $specificity-map - map of frequency of each type (a, b, c) in complex selector | |
/// @param {Number} $base (256) - base used to calculate specificity value (default: 256) | |
/// @return {Number} specificity value of given specificity map as base 10 integer | |
@function specificity-value($specificity-map, $base: 256) { | |
$exponent-map: (a: 2, b: 1, c: 0); | |
$specificity: 0; | |
@each $specificity-type, $specificity-value in $specificity-map { | |
$specificity: $specificity + ($specificity-value * pow($base, map-get($exponent-map, $specificity-type))); | |
} | |
@return $specificity; | |
} | |
/// Returns the specificity map or value of given simple/complex/multiple selector(s). | |
/// @access public | |
/// @param {List | String} $initial-selector - selector returned by '&' | |
/// @param {Bool} $integer (false) - output specificity as integer? (default: false) | |
/// @return {Map | Number} specificity map or specificity value represented as integer | |
@function specificity($initial-selector, $integer: false) { | |
$initial-selector: str-replace-batch(#{$initial-selector}, ('+', '>', '~')); | |
$selectors: selector-parse($initial-selector); | |
$specificities-map: (); | |
@each $selector in $selectors { | |
$parts: (); | |
$selector-specificity-map: (a: 0, b: 0, c: 0); | |
@each $simple-selectors in $selector { | |
@each $simple-selector in simple-selectors($simple-selectors) { | |
$parts: append($parts, $simple-selector); | |
} | |
} | |
@each $part in $parts { | |
$specificity-type: specificity-type($part); | |
@if $specificity-type { | |
$selector-specificity-map: map-merge($selector-specificity-map, (#{$specificity-type}: map-get($selector-specificity-map, $specificity-type) + 1)); | |
} | |
} | |
$specificities-map: map-merge($specificities-map, (specificity-value($selector-specificity-map): $selector-specificity-map)); | |
} | |
$specificity-value: max(map-keys($specificities-map)...); | |
$specificity-map: map-values(map-get($specificities-map, $specificity-value)); | |
@return if($integer, $specificity-value, $specificity-map); | |
} | |
/// Outputs specificity in your CSS as (invalid) properties. | |
/// Please, don't use this mixin in production. | |
/// @access public | |
/// @output specificity (map as string), specificity-value (specificity value as integer) | |
@mixin specificity() { | |
specificity: specificity(&); | |
specificity-value: specificity(&, true); | |
} | |
* { @include specificity; } | |
li { @include specificity; } | |
li:first-line { @include specificity; } | |
ul li { @include specificity; } | |
ul ol+li { @include specificity; } | |
h1 + *[rel=up] { @include specificity; } | |
ul ol li.red { @include specificity; } | |
li.red.level { @include specificity; } | |
p { @include specificity; } | |
div p { @include specificity; } | |
.sith { @include specificity; } | |
div p.sith { @include specificity; } | |
#sith { @include specificity; } | |
body #darkside .sith p { @include specificity; } | |
* { @include specificity; } | |
LI { @include specificity; } | |
UL LI { @include specificity; } | |
UL OL+LI { @include specificity; } | |
H1 + *[REL=up] { @include specificity; } | |
UL OL LI.red { @include specificity; } | |
LI.red.level { @include specificity; } | |
#x34y { @include specificity; } | |
#s12:not(FOO) { @include specificity; } | |
/* The highest specificity is the one that's displayed */ | |
#super_high_specificity, .sorta[low="specificity"] { | |
@include specificity; | |
} | |
/* It even works with nested selectors! */ | |
.first { | |
.second[disabled]:hover { | |
.third > #fourth ~ div ul > li:first-child + li.active { | |
@include specificity; | |
} | |
} | |
} | |
/* Here's why in some browsers, 256 classes can override a single ID! */ | |
.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h | |
.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h | |
.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h | |
.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h | |
.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h | |
.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h | |
.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h | |
.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h | |
.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h | |
.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h | |
.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h | |
.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h | |
.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h | |
.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h | |
.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h | |
.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h | |
{ @include specificity; } | |
#h { @include specificity; } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
* { | |
specificity: 0, 0, 0; | |
specificity-value: 0; | |
} | |
li { | |
specificity: 0, 0, 1; | |
specificity-value: 1; | |
} | |
li:first-line { | |
specificity: 0, 0, 2; | |
specificity-value: 2; | |
} | |
ul li { | |
specificity: 0, 0, 2; | |
specificity-value: 2; | |
} | |
ul ol + li { | |
specificity: 0, 0, 3; | |
specificity-value: 3; | |
} | |
h1 + *[rel=up] { | |
specificity: 0, 1, 1; | |
specificity-value: 257; | |
} | |
ul ol li.red { | |
specificity: 0, 1, 3; | |
specificity-value: 259; | |
} | |
li.red.level { | |
specificity: 0, 2, 1; | |
specificity-value: 513; | |
} | |
p { | |
specificity: 0, 0, 1; | |
specificity-value: 1; | |
} | |
div p { | |
specificity: 0, 0, 2; | |
specificity-value: 2; | |
} | |
.sith { | |
specificity: 0, 1, 0; | |
specificity-value: 256; | |
} | |
div p.sith { | |
specificity: 0, 1, 2; | |
specificity-value: 258; | |
} | |
#sith { | |
specificity: 1, 0, 0; | |
specificity-value: 65536; | |
} | |
body #darkside .sith p { | |
specificity: 1, 1, 2; | |
specificity-value: 65794; | |
} | |
* { | |
specificity: 0, 0, 0; | |
specificity-value: 0; | |
} | |
LI { | |
specificity: 0, 0, 1; | |
specificity-value: 1; | |
} | |
UL LI { | |
specificity: 0, 0, 2; | |
specificity-value: 2; | |
} | |
UL OL + LI { | |
specificity: 0, 0, 3; | |
specificity-value: 3; | |
} | |
H1 + *[REL=up] { | |
specificity: 0, 1, 1; | |
specificity-value: 257; | |
} | |
UL OL LI.red { | |
specificity: 0, 1, 3; | |
specificity-value: 259; | |
} | |
LI.red.level { | |
specificity: 0, 2, 1; | |
specificity-value: 513; | |
} | |
#x34y { | |
specificity: 1, 0, 0; | |
specificity-value: 65536; | |
} | |
#s12:not(FOO) { | |
specificity: 1, 0, 1; | |
specificity-value: 65537; | |
} | |
/* The highest specificity is the one that's displayed */ | |
#super_high_specificity, .sorta[low="specificity"] { | |
specificity: 1, 0, 0; | |
specificity-value: 65536; | |
} | |
/* It even works with nested selectors! */ | |
.first .second[disabled]:hover .third > #fourth ~ div ul > li:first-child + li.active { | |
specificity: 1, 7, 4; | |
specificity-value: 67332; | |
} | |
/* Here's why in some browsers, 256 classes can override a single ID! */ | |
.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h | |
.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h | |
.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h | |
.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h | |
.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h | |
.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h | |
.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h | |
.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h | |
.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h | |
.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h | |
.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h | |
.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h | |
.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h | |
.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h | |
.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h | |
.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h.h { | |
specificity: 0, 256, 0; | |
specificity-value: 65536; | |
} | |
#h { | |
specificity: 1, 0, 0; | |
specificity-value: 65536; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment