Search code examples
sassbackground-colorscss-mixins

SASS - Complement function on a variable from another scope


I have two separate SASS files among many, on a ReactJS repository, such as _main.sass and _partials.sass. They are combined using @use on a separate file named index.css.

The SASS package as a dependency is just sass via npm.

_main.sass and all of its variables can be accessed by _partials.sass, thanks to @use "./main" as *.

I have the following code on _main.sass which detects OS preference for dark mode:

@media (prefers-color-scheme: light)
    body
        background-color: $white
        color: $black

@media (prefers-color-scheme: dark)
    body
        background-color: $dark
        color: $light

All of these color variables are defined and they're working well.

But the problem is that I need to use complement() function on the background-color which is currently active, in _partials.sass.

The main issue seems to me that when I assign a variable e.g. $accent on both ends of the media queries, the variable does not get picked up by the remote file. I could not wrap my head around to do it in such way, since I'm only a beginner at coding SASS.

Unfortunately, I need the plain CSS @media query implementations for automatically detecting the preference. But any suggestion is appreciated in case it is impossible to keep it like that and achieve what I wanted.

Thank you!


Solution

  • I've found the solution myself.

    So, I was trying to make a light/dark theme compliant SASS implementation.

    What complement function does is that it rotates the color in the input for 180deg on the RGB hue. I needed this to get corresponding inverted-like colors for each color, for better dark-mode contrast. The difference between invert and complement are listed here.

    But, I realized that I did not need that. Here is the code for my theme implementation using SASS.

    // rainbow
    $blue: #00a4ef
    $yellow: #f4b400
    $red: #db4437
    $green: #61b500
    $purple: #6e14ef
    $pink: #ff0090
    $carmine: #c6004b
    
    // monochroma 
    $white: #fff
    $light: #f5f5f5
    $lgray: #c2c2c2
    $dgray: #6e6e6e
    $ldark: #363636
    $dark: #232323
    $black: #000
    
    $themes: (light: (logo: url("../static/logo-light.svg"), bg: $white, card-bg: $light, text: $black, link: $red, hover: $pink, active: $carmine, border: $lgray, button: $yellow), dark: (logo: url("../static/logo-dark.svg"), bg: $dark, card-bg: $ldark, text: $light, link: $red, hover: $pink, active: $carmine, border: $dgray, button: $purple))
    
    @mixin themeProperty($theme, $property, $color, $additionalProperties)
    @if $additionalProperties
        #{$property}: unquote(map-get($theme, $color) + " " + $additionalProperties)
    @else 
        #{$property}: unquote(map-get($theme, $color))
    
    @mixin theme($property, $color, $additionalProperties: "")
        $light: map-get($themes, light)
        $dark: map-get($themes, dark)
    
        @media (prefers-color-scheme: light)
            @include themeProperty($light, $property, $color, $additionalProperties)
    
        @media (prefers-color-scheme: dark)
            @include themeProperty($dark, $property, $color, $additionalProperties)
    

    There is a color map named "themes" which lists each color for light and dark themes for different use cases.

    Furthermore, the mixins match the exact color for exact usage for the desired theme mode, whichever is being used by the client-side (browser or OS), thanks to @media queries.

    For example, if you'd like to color a background-color using the button preset on the theme mapping, the usage is as follows:

    @include theme("background-color", button)