Click here to Skip to main content
15,867,568 members
Articles / Programming Languages / C#

Color Scheme Selector

Rate me:
Please Sign up or sign in to vote.
4.87/5 (50 votes)
24 Jun 2015CPOL11 min read 43.8K   1.2K   39   19
“The colors of the world are changing day by day!” - Les Misérables

Introduction

This article is not about code (there will be code later, but the important part is the explanation). I will try to shed light on another aspect of software development - design… Not software design, but UI/UX design. I will not seize the whole subject of UI/UX (like size and position and shape and so) but only the subject of choosing colors for your web site…

Note: If you ask, why web sites and not desktop (native) applications, here my answer… When you create an application for desktop (native) you do not play with colors, but use the color theme the OS provides - what the end-user picked, and that because you want to give him/her the comfort of being home.

When you are working with a big company, you will never touch this subject, a designer will give you the exact UI/UX parameters including colors. But! In small companies and in cases you work alone it is important to know how to choose colors that will play together in harmony…

Image 1

 Image 2

Both sites are full of colors, but the proper choice and pairing of them makes all the difference!

Background

My big brother is a professional graphics designer, who designs books (page-layout and cover) in several languages. He done several thousand designs over the years and his opinion is that the “beauty is in the eye of the beholder”. In years, when I worked with him, he taught me lot of his little secrets, but it became obvious that while I’m able to supervise the pagination (mostly done by computers today), I don't have the slightest ability to work with colors.

At that point my dear brother revealed that there are mathematical methods of choosing colors, and those methods are used even by designers… I will explain those methods, but before that a little introduction to different color models used around…

Color Models

Color models are mathematical abstractions of real life color into tuples of mostly 3 or 4 values.

RGB model

The human retina (eye) contains three types of cones (sensors), that can sense (see) different wavelengths, namely long (Red), medium (Green) and short (Blue). This structure - that was known way before the age of electronic devices - used as the base for the RGB  color model, which creates colors by adding the three components, just like the human eye. This model used in all the screen devices we know today - all your PC, tablet and smart-phone screens. And the reason that you are already familiar with it is, that all major (and most minor) language/framework supports this color model…

However the RGB model does not work in a way human understand color. For instance the color named Magenta built of R:255, G:0, B:255. By adding more green one should expect to see a more greenish color, however adding more and more green the color became more and more white-like…

Image 3
Magenta color strip in RGB model is a bit strange.
Red and blue are fixed on 255, green runs  from 0 to 255 (left to right)

 

Image 4

RGB model represented as a cube.
(Based on work from SharkD - Wikimedia Commons)

HSV model

This color model was created in the 1970s, specifically for the needs of computer graphics. The model still uses 3 components in an additive way, but rearranges the RGB color space in a way human can understand much better. It also resembles the classical color-wheel used by artists, which also makes it easier to choose color with this model.

The basic element is Hue, which runs around a color-wheel where 0 degree is red and 360 is red again. Saturation defines the purity of the color where 0 is the purest and 100 describes a color so saturated that it turns dim - white. Value defines the brightness of the color where 0 defines black (lack of light) and 100 defines the lightest shade of the current color (hue).

This model is very easy to understand, as by changing one component you see what you have expected and not an undefined change of colors...For these reasons this is the color model used almost exclusively in all graphics programs and by all designers…

Image 5

Green color strip in HSV model behaves in way human can understand it easily. 
Hue fixed on 120, value fixed on 100, saturation runs  from 100 to 0 (left to right)

Image 6

HSV model represented as a cylinder.
(Based on work from SharkD - Wikimedia Commons)

Alpha channel

Alpha channel is introduced to computer graphics in the second half of 1980s. The alpha channel represents the transparency of a color, where 100% is a fully opaque color and 0% is a fully transparent color. This A element can be applied to both color models we discussed here…

Note: In the color sets to follow I do not use alpha channel, it is here only for completeness...

Choosing the set of colors

The basic idea is to use less color. If you look around, you will see that most well designed sites are use very few colors (HP for instance have 4 - including white). And even there is a need for more colors, colors are chosen with care. As we do not have (most of us at least) the talent to choose nicely fitting colors we can use one of these algorithms formed from the experience of designers…

All these formulas are based on the idea that you choose a single color and get back a set of colors that play nicely together (the color chosen is one of the set).

I will explain now how every of these formulas works, and what are the pros and cons of each one of them.

Complements

Image 7

This method creates a set of two colors, where the second color is placed on the opposite side of the color wheel. The best is to choose warm-cold color pairs (like orange-blue or magenta-green) for better contrast. In any case it is important to choose a color that is dominant over its counterpart.

Pros: This method gives high contrast between the colors in the set.

Cons: It can be hard to create a balanced color-set, especially when using desaturated color as base (desaturated colors are more grayish/whitish than normal colors).

Split Complements

Image 8

This method creates a set of three colors, where the additional two colors are adjacent to the complementary color from either side (the actual distance from the complementary color can be an important factor of the final result). Just like in the Complements method it is better to choose warm-cold pairs for better result, and keep the distance between 15 to 45 degrees...

Pros: This method gives high contrast between the colors in the set and adds more nuances over the Complements method (more colors!).

Cons: It can be hard to create a balanced color-set, especially when using desaturated color as base.

Triads

Image 9

This method creates a set with three colors equally spaced around the color wheel.

Pros: The colors in the set are very harmonious, but still have a good level of contrast.

Cons: Lower contrast than in Complements or SplitComplements.

Tetrads

 Image 10

This method creates a set with four colors equally spaced around the color wheel. In fact this is a ‘double’ Complements, with the harmony of triads.

Pros: The colors in the set are very harmonious, but have the contrast of Complements method in each pair of the colors.

Cons: Because of the larger number of colors it is much harder to balance.

Quintads

Image 11

This method creates a set of five colors equally spaced around the color wheel.

Pros: The colors in the set are very harmonious (like in Tetrads), but have lower contrast than the other sets before.

Cons: Because of the larger number of colors it is much harder to balance.

Analogous

Image 12

This method creates a set of three colors, where the additional two are adjacent to the original color (the actual distance from the original color can be an important factor of the final result). It is better to avoid warm-cold colors in the set (do not choose color on the border between warm-cold color areas), and keep the distance between 15 to 45 degrees.

Pros: It is a rich and easy to create color set.

Cons: There is not much contrast in the set.

Monochromatics

Image 13

This method creates a set of five colors, where the new colors are shades of the original color, playing  with the saturation of the color. The five colors are spaced equally over the axis of the saturation (in-out on the color wheel).

Pros: Very easy to create a well balanced and harmonious set.

Cons: Lacks any contrast of colors.

Combinations

Image 14

This method creates a set of 25 colors. The colors are created as a combination of the Quintads method and the Monochromatics method, applied in that order. The method combines the balance of Monochromatics with the contrast of Quintads.

Pros: The set is very harmonious also between main colors and also in subsets. Can be used in larger sites to separate different subjects of the site by colors.

Cons: Because of the larger number of colors it is much harder to balance.

Color Blindness

Between 2 to 8 percent of humans has one or other form of color blindness. Color blindness caused by missing or malfunctioning cones - one or more types - in the eye. People with this condition may not notice the difference between colors, switch colors or see only shades of the same color.

For these people color information alone is not enough - when designing a web site, pair color information with shape, icon and/or text to provide better user experience...

Image 15 Image 16
In the left the color wheel as one with normal vision sees it,
and in the right how one with Deuteranomaly (the most common form of color blindness) may see it...

True Blindness

Designing web-site for blind people is far beyond the scope of this article (we talk about colors - a blind person has no colors!). If you ever get  a project, where design for blind people is a request, you will have to find yourself an expert in that field (it’s an expertise even between designers).

The Code Part

I promised no code, but after all it a coding site...

In this part I will show the core of a possible implementation of the ideas we saw. The sample code I will show here is NOT the code attached to the article! The attached code is a Visual Studio extension, that enables you to create the mentioned color sets and insert the single colors into your code… The code here is a sample of that only, that shows the relevant parts for this article (how to create a color palette in WPF is not our subject :-))

RGB to HSV and Back

As mentioned before, RGB color model is supported in almost every language/framework. In .NET we have the Color class that represents a color based on RGB model, the problem is that the color sets computed around the HSV color wheel, and for that we have to be able to convert between the two models back and forth.

Of course the computations are not trade secret, and can be found on the web…

RGB to HSV

$ R'=R\div255\\ G'=G\div255\\ B'=G\div255\\~\\ C_{max}=\max(R',G',B')\\ C_{min}=\min(R',G',B')\\ \Delta=C_{max}-C_{min}\\~\\ H=\left\{\begin{matrix} 0^{\circ},&\Delta=0\\ 60^{\circ}\times\left(\frac{G'-B'}{\Delta}\mod6\right),&C_{max}=R'\\ 60^{\circ}\times\left(\frac{B'-R'}{\Delta}+2\right),&C_{max}=G'\\ 60^{\circ}\times\left(\frac{R'-G'}{\Delta}+4\right),&C_{max}=B' \end{matrix}\right.\\~\\ S=\left\{\begin{matrix} 0,&C_{max}=0\\ \frac{\Delta}{C_{max}},&C_{max}\neq0 \end{matrix}\right.\\~\\ V=C_{max} $

HSV to RGB

$ H'=H\\ S'=S\div100\\ V'=V\div100\\~\\ C=V'\times S'\\ X=C\times\left(1-\left|\left(\frac{H'}{60^{\circ}}\right)\mod2-1\right|\right)\\ m=V'-C\\~\\ \left(R',G',B'\right)=\left\{\begin{matrix} \left(C,X,0\right),&0^{\circ}\leq H'<60^{\circ}\\ \left(X,C,0\right),&60^{\circ}\leq H'<120^{\circ}\\ \left(0,C,X\right),&120^{\circ}\leq H'<180^{\circ}\\ \left(0,X,C\right),&180^{\circ}\leq H'<240^{\circ}\\ \left(X,0,C\right),&240^{\circ}\leq H'<300^{\circ}\\ \left(C,0,X\right),&300^{\circ}\leq H'<360^{\circ} \end{matrix}\right.\\~\\ R=\left(R'+m\right)\times255\\ G=\left(G'+m\right)\times255\\ B=\left(B'+m\right)\times255 $

And a possible implementation of those formulas in C#

C#
public class ColorEx
{
    public static short MaxHue = 360;
    public static short MaxSaturation = 100;

    private bool _IsRGBDirty = false;
    private bool _IsHSVDirty = false;

    public ColorEx ( )
    {
        RGB2HSV( );
    }

    public ColorEx Clone ( )
    {
        return ( new ColorEx( )
        {
            R = R,
            G = G,
            B = B
        } );
    }

    #region Properties

    private Color _Color = new Color( )
    {
        A = 255,
        R = 128,
        G = 128,
        B = 128
    };

    public Color Color
    {
        get
        {
            if ( _IsRGBDirty )
            {
                HSV2RGB( );
            }

            return ( _Color );
        }
    }

    public byte R
    {
        get
        {
            if ( _IsRGBDirty )
            {
                HSV2RGB( );
            }

            return ( _Color.R );
        }
        set
        {
            _Color.R = value;

            _IsHSVDirty = true;
        }
    }

    public byte G
    {
        get
        {
            if ( _IsRGBDirty )
            {
                HSV2RGB( );
            }

            return ( _Color.G );
        }
        set
        {
            _Color.G = value;

            _IsHSVDirty = true;
        }
    }

    public byte B
    {
        get
        {
            if ( _IsRGBDirty )
            {
                HSV2RGB( );
            }

            return ( _Color.B );
        }
        set
        {
            _Color.B = value;

            _IsHSVDirty = true;
        }
    }

    private short _H = 0;

    public short H
    {
        get
        {
            if ( _IsHSVDirty )
            {
                RGB2HSV( );
            }

            return ( _H );
        }
        set
        {
            // Hue is circular (degree)
            _H = ( short )( ( value < 0 ? 360 : 0 ) + ( value % 360 ) );

            _IsRGBDirty = true;
        }
    }

    private byte _S = 0;

    public byte S
    {
        get
        {
            if ( _IsHSVDirty )
            {
                RGB2HSV( );
            }

            return ( _S );
        }
        set
        {
            if ( value >= 0 && value <= 100 )
            {
                _S = value;

                _IsRGBDirty = true;
            }
        }
    }

    private byte _V = 0;

    public byte V
    {
        get
        {
            if ( _IsHSVDirty )
            {
                RGB2HSV( );
            }

            return ( _V );
        }
        set
        {
            if ( value >= 0 && value <= 100 )
            {
                _V = value;

                _IsRGBDirty = true;
            }
        }
    }

    #endregion

    #region Helpers

    private void RGB2HSV ( )
    {
        double nR = _Color.R / ( double )255;
        double nG = _Color.G / ( double )255;
        double nB = _Color.B / ( double )255;
        double nCmax = Math.Max( nR, Math.Max( nG, nB ) );
        double nCmin = Math.Min( nR, Math.Min( nG, nB ) );
        double nDelta = nCmax - nCmin;
        double nH = 0;
        double nS = 0;
        double nV = nCmax;

        if ( nDelta != 0 )
        {
            if ( nCmax == nR )
            {
                nH = ( ( nG - nB ) / nDelta ) % 6.0;
            }
            else if ( nCmax == nG )
            {
                nH = ( ( nB - nR ) / nDelta ) + 2.0;
            }
            else if ( nCmax == nB )
            {
                nH = ( ( nR - nG ) / nDelta ) + 4.0;
            }
        }

        nH *= 60.0;

        if ( nH < 0 )
        {
            nH += 360;
        }

        if ( nDelta != 0 )
        {
            nS = nDelta / nCmax;
        }

        nS *= ( double )100;
        nV *= ( double )100;

        _H = ( short )( nH );
        _S = ( byte )( nS );
        _V = ( byte )( nV );

        _IsHSVDirty = false;
    }

    private void HSV2RGB ( )
    {
        double nS = _S / ( double )100;
        double nV = _V / ( double )100;
        double nDelta = nV * nS;
        double nH = _H / 60.0;
        double nX = nDelta * ( 1 - Math.Abs( ( nH % 2 ) - 1 ) );
        double nM = nV - nDelta;
        double nR = 0;
        double nG = 0;
        double nB = 0;

        if ( nH >= 0 && nH < 1 )
        {
            nR = nDelta;
            nG = nX;
        }
        else if ( nH >= 1 && nH < 2 )
        {
            nR = nX;
            nG = nDelta;
        }
        else if ( nH >= 2 && nH < 3 )
        {
            nG = nDelta;
            nB = nX;
        }
        else if ( nH >= 3 && nH < 4 )
        {
            nG = nX;
            nB = nDelta;
        }
        else if ( nH >= 4 && nH < 5 )
        {
            nR = nX;
            nB = nDelta;
        }
        else
        {
            nR = nDelta;
            nB = nX;
        }

        nR += nM;
        nG += nM;
        nB += nM;

        nR *= 255;
        nG *= 255;
        nB *= 266;

        _Color.R = ( byte )( nR );
        _Color.G = ( byte )( nG );
        _Color.B = ( byte )( nB );

        _IsRGBDirty = false;
    }

    #endregion
}

This code creates a new color  class that supports both RGB and HSV and always synchronized... The most important thing you have to notice with this code is that H is circular, as it measured in degrees, so 361 is the same as 1...

Computing the color sets

Triads

All color sets - except Monochromatics - are moving the original color around the current color wheel to create the set, so first let see a sample of that...

private void Triads ( ColorEx BaseColor )
{
    ColorEx oTriad1 = BaseColor.Clone( );
    ColorEx oTriad2 = BaseColor.Clone( );

    oTriad1.H += 120;
    oTriad2.H -= 120;

    // ...
}

As triads are used to create 3 colors equally distributed around the color wheel, we are using the 120° value (\(360^{\circ}\div 3 = 120^{\circ}\)), but all the other manipulations of Hue do the same only the value computed according to the set...

Monochromatics

The only set creates its colors by manipulating the saturation of the original color...

C#
private void Monochromatics ( ColorEx BaseColor )
{
    byte nGap = 20;
    byte nS = BaseColor.S % nGap;

    ColorEx oMonochromatic0 = new ColorEx( ) { H = BaseColor.H, S = nS, V = BaseColor.V    };
    ColorEx oMonochromatic1 = new ColorEx( ) { H = BaseColor.H, S = ( byte )( nS + nGap ), V = BaseColor.V };
    ColorEx oMonochromatic2 = new ColorEx( ) { H = BaseColor.H, S = ( byte )( nS + ( 2 * nGap ) ), V = BaseColor.V };
    ColorEx oMonochromatic3 = new ColorEx( ) { H = BaseColor.H, S = ( byte )( nS + ( 3 * nGap ) ), V = BaseColor.V };
    ColorEx oMonochromatic4 = new ColorEx( ) { H = BaseColor.H, S = ( byte )( nS + ( 4 * nGap ) ), V = BaseColor.V };

    // ...
}

These are only samples of how to manipulate color values to get the sets - in the attached code you will find the exact code for creating all the color sets in this article...

Summary

If you mean to deliver quality work as  web developer, it is not enough that your code works and is written well - you also have to deliver the perfect look-and-feel for your site. And if you are alone and only start you career it can be too expensive to hire a professional designer for a small site. This article  can help you to choose the right colors...

TL;DR

So. You are convinced about the importance of colors, but still don't want to mess with the code!

You can download and install the Visual Studio extension based on this article - it's free!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Israel Israel
Born in Hungary, got my first computer at age 12 (C64 with tape and joystick). Also got a book with it about 6502 assembly, that on its back has a motto, said 'Try yourself!'. I believe this is my beginning...

Started to learn - formally - in connection to mathematics an physics, by writing basic and assembly programs demoing theorems and experiments.

After moving to Israel learned two years in college and got a software engineering degree, I still have somewhere...

Since 1997 I do development for living. I used 286 assembly, COBOL, C/C++, Magic, Pascal, Visual Basic, C#, JavaScript, HTML, CSS, PHP, ASP, ASP.NET, C# and some more buzzes.

Since 2005 I have to find spare time after kids go bed, which means can't sleep to much, but much happier this way...

Free tools I've created for you...



Comments and Discussions

 
QuestionIs anyone out there? Pin
dezrtluver26-Mar-22 10:59
dezrtluver26-Mar-22 10:59 
AnswerRe: Is anyone out there? Pin
dezrtluver26-Mar-22 12:16
dezrtluver26-Mar-22 12:16 
Generalgreat! Pin
Southmountain14-Mar-20 10:54
Southmountain14-Mar-20 10:54 
GeneralMy vote of 5 Pin
User 1106097914-Apr-17 3:28
User 1106097914-Apr-17 3:28 
GeneralRe: My vote of 5 Pin
Kornfeld Eliyahu Peter17-Apr-17 20:43
professionalKornfeld Eliyahu Peter17-Apr-17 20:43 
GeneralRe: My vote of 5 Pin
User 1106097918-Apr-17 20:36
User 1106097918-Apr-17 20:36 
GeneralMy vote of 5 Pin
wmjordan22-Jan-17 14:41
professionalwmjordan22-Jan-17 14:41 
GeneralRe: My vote of 5 Pin
Kornfeld Eliyahu Peter22-Jan-17 19:48
professionalKornfeld Eliyahu Peter22-Jan-17 19:48 
GeneralMy vote of 5 Pin
BillWoodruff23-Jul-16 18:53
professionalBillWoodruff23-Jul-16 18:53 
GeneralRe: My vote of 5 Pin
Kornfeld Eliyahu Peter23-Jul-16 20:56
professionalKornfeld Eliyahu Peter23-Jul-16 20:56 
Question5 - Try it live Pin
Rage9-Sep-15 6:01
professionalRage9-Sep-15 6:01 
AnswerRe: 5 - Try it live Pin
Kornfeld Eliyahu Peter9-Sep-15 7:23
professionalKornfeld Eliyahu Peter9-Sep-15 7:23 
GeneralMy vote of 5 Pin
Graham Cottle26-Aug-15 23:24
professionalGraham Cottle26-Aug-15 23:24 
Brilliant. Wish I had this a few years ago. I found something on the web very similar and started a Silverlight clone for some of the work, but got bogged down in it with generating and picking from a colour wheel and eventually gave up. This might just kick me back into action.
GeneralRe: My vote of 5 Pin
Kornfeld Eliyahu Peter27-Aug-15 7:28
professionalKornfeld Eliyahu Peter27-Aug-15 7:28 
QuestionGreat article Pin
Mike Hankey25-Jun-15 7:29
mveMike Hankey25-Jun-15 7:29 
AnswerRe: Great article Pin
Kornfeld Eliyahu Peter25-Jun-15 7:54
professionalKornfeld Eliyahu Peter25-Jun-15 7:54 
AnswerRe: Great article Pin
Liju Sankar17-Jul-15 5:44
professionalLiju Sankar17-Jul-15 5:44 
AnswerRe: Great article Pin
Kornfeld Eliyahu Peter18-Jul-15 20:20
professionalKornfeld Eliyahu Peter18-Jul-15 20:20 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.