Skip to content

Instantly share code, notes, and snippets.

@the-glima
Last active May 26, 2021 03:34
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save the-glima/a4ff613d31c46886a6fd92f0354ebe19 to your computer and use it in GitHub Desktop.
Save the-glima/a4ff613d31c46886a6fd92f0354ebe19 to your computer and use it in GitHub Desktop.
[SCSS] Managing and Logging z-index #website

Managing and logging z-indexes

Let's say that you want to use a z-index value in a project (specially a big one) but you are not sure if there's something else using the same z-index value or a higher one, it could cover up your new cool thing, so what you do?

Easy, just use 9999 and consider this job done 😎 👎🏼

But that is the little devil 😈 on your shoulder winning the battle. So let's try to listen to the angel 👼🏼 this time.

Variables - Mappings

Specify the known z-indexes, for example:

$z-indexes-map: (
  'under': -1,
  'default': 1,
  'dialog': 100,
  'alert': 200,
  'modal': (
    'base': 300,
    'header': 301,
    'close': 302
  )
) !default;

Important: this map should be at maximum of 2 level deep.

Also, let's setup the logging options:

$z-indexes-log: (
  // If key is found in the map
  'used-key': true,

  // If value is found in the map
  'used-value': true,
  
  // To warn that the value is less than others from the map
  'less-than': true,

  // If true an error will be thrown instead of warn
  'error': false
) !default;

Functions

Check each function file for more information.

get-zindex

To get and check a z-index value from a key in a z-index map.

.class {
  z-index: get-zindex('default');
  z-index: get-zindex('modal', 'header');
}

// Output
.class {
  z-index: 1;
  z-index: 301;
}

If no key is found, will warn if used-key is true. Property will be omitted:

.class {
  z-index: get-zindex('foo');
}

// "No key "foo" found in " ("under": -1, "default": 1, "dialog": 100, "alert": 200, "modal": ("base": 300, "header": 301, "close": 302)) ". Property omitted."

If is a wrong value type. Will warn an omit the property:

.class {
  z-index: get-zindex(123);
}

// Value should be string. Property omitted!

safe-zindex

To safely use a z-index value from z-index map.

If value is less than other values, will warn if less-than is true. Property is persisted:

.class {
  z-index: safe-zindex(123);
}

// Output
.class {
  z-index: 123;
}

// Warning:
// The value '123' is less than 'alert: 200'.
// The value '123' is less than 'modal.base: 300'.
// The value '123' is less than 'modal.header: 301'.
// The value '123' is less than 'modal.close: 302'.

If value is being used by an existent key it will warn if used-value is true. Property is persisted:

.class {
  z-index: safe-zindex(1); 
}

// Output
.class {
  z-index: 1;
}

// Warning:
// The z-index value of '1' is being used by the key 'default'.

If is a wrong value type. Will warn an omit the property:

.class {
  z-index: safe-zindex('301');
}

// Warning:
// Property omitted value should be a number 

Mixin

append-custom-properties

To append all items of a map into :root as CSS Custom Properties. In this case, let's use z-indexes-map map. You can also pass a prefix for the custom properties or leave it empty.

@include append-custom-properties($prefix: 'z-index', $map: $z-indexes-map)

// Output
:root {
  --z-index-under: -1;
  --z-index-default: 1;
  --z-index-dialog: 100;
  --z-index-alert: 200;
  --z-index-modal-base: 300;
  --z-index-modal-header: 301;
  --z-index-modal-close: 302;
}
// Mixin: append-custom-properties
// A mixin to append all items of a map to :root custom properties
// @param $prefix: string - the prefix to be the variable name, default empty
// @param $map: map - a map list
@mixin append-custom-properties($prefix: '', $map) {
@if (type-of($prefix) != string) {
@warn 'Prefix should be a string.';
} @else if (type-of($map) != 'map') {
@warn 'Value should be a map.';
} @else {
$prepend: '';
@if $prefix == '' {
$prepend: '--';
} @else {
$prepend: --#{$prefix}-;
}
@at-root :root {
@each $key, $value in $map {
@if (type-of($value) == 'map') {
@each $nested-key, $nested-value in $value {
#{$prepend}#{$key}-#{$nested-key}: #{$nested-value};
}
} @else {
#{$prepend}#{$key}: #{$value};
}
}
}
}
}
// Function: get-zindex
// A function to check the usage of an already z-index value
// https://gist.github.com/the-glima/a4ff613d31c46886a6fd92f0354ebe19
// @param $key: string - they key to look for in a z-indexes-map
// @param $type: string - they variant of the key, default null
// @param $map: map - a custom map list
// @param $log-map: map - list of log flags to warn or thrown an error
// @return number | null
@function get-zindex(
$key,
$type: null,
$map: $z-indexes-map,
$log-map: $z-indexes-log
) {
$log-used-key: map-get($log-map, 'used-key');
$log-error: map-get($log-map, 'error');
@if (type-of($key) != string) {
@warn 'Value should be string. Property omitted!';
@return null;
}
$found-key: map-get($map, $key);
@if ($log-used-key) and ($found-key == null) {
@return warning(
'No key '#{$key}' found in '$z-indexes-map'. Property omitted.',
$log-error
);
}
@if type-of($found-key) == 'map' {
@if $log-used-key and not map-has-key($found-key, $type) {
@warn 'Second #{$found-key}';
$warning: warning(
'No type '#{$type}' found for key '#{$key}' in '$z-indexes-map'. Property omitted.',
$log-error
);
@return null;
}
@return get-zindex($key: $type, $map: $found-key, $log-map: $log-map);
}
@return $found-key;
}
// Function warning:
// A helper function that handles @error/@warn messages
// @param $message: string - a message to be logged
// @param $warn-error: boolean - toggle @error/@warn
// @return null
@function warning($message, $warn-error) {
@if $warn-error {
@error $message;
} @else {
@warn $message;
}
@return null;
}
// Function: map-get-key-by-value
// A function to look for the key of a value
// @param $value: string - a value to look for the key
// @param $map: map - a map list
// @return string | @error
@function map-get-key($index, $map) {
@if $index {
$pair: nth($map, $index);
$key: nth($pair, 1);
@return $key;
}
@return null;
}
// Function: safe-zindex
// A function to check the usage of an already z-index value
// https://gist.github.com/the-glima/a4ff613d31c46886a6fd92f0354ebe19
// @param $value: number - the value of a z-index to look for in z-indexes-map
// @param $map: map - a custom z-indexes-map map list
// @param $log-map: map - list of log flags to warn or thrown an error
// @param $parent: string - To append parent's map key when logging. This should not be used, default 'null'.
// @return number | null
@function safe-zindex(
$value,
$map: $z-indexes-map,
$log-map: $z-indexes-log,
$parent: null
) {
$log-error: map-get($log-map, 'error');
$log-used-value: map-get($log-map, 'used-value');
$log-less-than: map-get($log-map, 'less-than');
@if (type-of($value) != number) {
@warn 'Value should be number. Property omitted!';
@return null;
}
$values: map-values($map);
$index: index($values, $value);
$parentSeparator: if($parent, '#{$parent}.', '');
@each $val in $values {
$valIndex: index($values, $val);
$valKey: map-get-key($valIndex, $map);
@if $index {
$key: map-get-key($index, $map);
@if $log-used-value {
$warning: warning(
"The z-index value of '#{$value}' is being used by the key '#{$parentSeparator}#{$key}'.",
$log-error
);
}
@return $value;
}
@if $log-less-than {
@if (type-of($val) == 'number' and $valKey and ($value < $val)) {
@warn "The value '#{$value}' is less than '#{$parentSeparator}#{$valKey}: #{$val}'."
}
}
@if (type-of($val) == 'map') {
@return safe-zindex($value: $value, $map: $val, $log-map: $log-map, $parent: $valKey);
}
}
@return $value;
}
// A map containing all z-index layers
// In case of having duplication of the same value
// the first occurrence will be used (top to bottom)
$z-indexes-map: (
'under': -1,
'default': 1,
'dialog': 100,
'alert': 200,
'modal': (
'base': 300,
'header': 301,
'close': 302,
)
) !default;
// To toggle warn or error messages
$z-indexes-log: (
'used-key': true,
'used-value': true,
'less-than': true,
'error': false
) !default;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment