In the web application development, it's usual to face the need to make the user able to customize the layout and appearance of a web site based on his own color preferences. A simple way to accomplish this feature is through the adoption of different, customizable, Cascading Style Sheet (CSS) files associated to each user: in this way, the user can manipulate or upload his own CSS file in order to see the web pages rendered based on the particular chosen color scheme.
In this scenario [scenario 1], you may need to mantain multiple CSS files, all similar in the structure but different in the choices made in terms of colors used; and this kind of maintenance can become hard and tedious as the number of CSS grows. For example, if you need to add or modify a class in your "master" CSS, you will have to update all the customized CSS files in the same way, editing each of them to operate the addition/modification of the same CSS class, but preserving the user's color choice.
Mantaining multiple CSS files becomes tedious also when you have the same color palette used in a lot of different CSS files, you decide to change one or more colors of the palette and you need to update all the existing CSS files substituting just the changed color(s) in each style sheet [scenario 2].
Believe me: when you are in such situations, you're dreaming of a tool capable to make your life easier. Now CSSeditor can help you to avoid this repetitive mantaining task.
CSSeditor is based on a very simple idea: to have a CSS file that acts as a "master" (or, if you prefer, as a template) for the automatic generation of another CSS file, that is different from the template only in the color scheme (or palette) used. So, you can look at a CSS file generated by CSSeditor as a "sum" of a CSS template "plus" an applied color palette.
With this idea in mind, it's simple to imagine a solution for both the situations previously depicted:
- for the first one, [scenario 1], you can regenerate the user's custom CSS files by applying different user's color palettes (extracted by their own original CSS files) to a new, modified CSS template;
- for the second one, [scenario 2], you can recreate the different CSS files by applying the new, modified color palette to each original CSS file (used as a template).
Basically, the only "problem" about this automatic CSS generation consists in isolating the customizable color elements of the CSS template. Once they are isolated, their substitution with a new set of colors is just a matter of find&replace.
To differentiate the customizable colors from the other colors contained in the CSS template, I decided to adopt a sort of "tagging convention", using the standard CSS comment facility. In this tagging convention, each individual customizable color is delimited by a starting color comment tag and by an ending color comment tag. So, for example, if I want to make customizable the border and the background colors of a particular CSS class, I'll modify the class definition from:
border:solid 1 #4D7FA9;
background-color: /*sC01*/ #4D7FA9 /*eC01*/;
border:solid 1 /*sC02*/ #4D7FFF /*eC02*/;
/*sCxx*/ stands for "start of color xx" and
/*eCxx*/ stands for "end of color xx". With customizable colors tagged this way, it's simple to code a tool capable of extracting a table of the used colors and of generating a new CSS file with that set of colors substituted with another set of colors (that is, with a color palette changed).
How CSSeditor works
CSSeditor is a simple Windows Forms VB.NET application that allows you to:
- open an input CSS "template" file (that we'll call "base CSS" from now on), containing colors tagged as described before;
- extract from that base CSS the palette of used colors (the "base palette" from now on);
- edit (or open from a previously saved file) a new color palette (the "new palette"), where each color from the base palette (which in turn comes from the base CSS) is twined with a new color;
- preview, in a browser window, the effects of the new palette applied to the base CSS on some sample HTML static pages;
- generate and save a new CSS file that is the combination of the base CSS with the new palette.
The CSS file generation, based on the new palette, can also be done in a "batch" fashion; in fact:
- you can select a set of CSS files that will be processed to extract different color palettes to be used for the generation of multiple versions of the base CSS with different color schemes applied [scenario 1], or
- you can select a set of CSS files that will be automatically recreated applying a given color palette [scenario 2].
To load an input "base CSS" file, use the "open" button in the upper-left area of the CSSeditor's user interface (the default CSS directory is
bin\CSS). When you load a CSS file to be used as a "base CSS", CSSeditor extracts the tagged colors in it and shows them in the "Base" column of the color palette (in the lower-left area of the form).
At this point, you can edit the color palette by clicking on cells from the "New" column of the palette and by entering an RGB color in the classic CSS hexadecimal notation (
#RRGGBB). If you're not so comfortable with hex digits you can always double-click the grey row selector of a color row: CSSeditor will show you the system "pick-a-color" dialog box. You can also load a previously saved palette, using the corresponding "open" button, in the lower-left area of the screen (the default palette directory is
bin\Palettes). Keep in mind that, by the CSSeditor point of view, a "color palette" is just a text file containing tagged colors, so any tagged CSS file can be used as a color palette.
With the base CSS loaded and the color palette modified, you can preview the final result by simply choosing an HTML sample file from the upper-right combobox and by clicking on the camera button. Listed HTML sample files are taken from the directory
bin\TrialPages; to prepare HTML sample files for your style sheets, you only need to save some of your pages (static or generated HTML) in that directory and modify their CSS reference as follows:
<link href="Generated.css" rel="stylesheet" type="text/css">
In fact, CSSeditor will generate (by the loaded base CSS and the new palette) a new CSS named
Generated.css, just before opening in the browser frame the HTML file you chose.
If the preview is OK, you can save the generated CSS in a different location, using the "save" button.
As stated at the beginning of this article, CSSeditor can speed up the generation of more CSS files. For the situations depicted above as [scenario 1] and [scenario 2], you can use respectively the "Batch CSS generation" and the "Batch apply Palette" facilities of CSSeditor. The first one allows you to regenerate multiple style sheets derived by the same base CSS but preserving their own color palettes; the second one allows you to apply the same new color palette to multiple style sheets.
Points of interest
All the work CSSeditor does, resides in a sort of smart find&replace, implemented using the
RegEx class from the
System.Text.RegularExpressions namespace. So, the code of this utility is not difficult.
Also the HTML preview was simple to implement, through a WebBrowser Control included in the form via COM Interop.
An interesting point may be in the way I implemented the color palette user interface: I used a standard
DataGrid with a customized
DataGridTextBoxColumn, that is a derived class in which the
Paint method is overridden to have each cell colored according with his own color value:
Public Class DataGridColoredTextBoxColumn
Public Sub New()
Protected Overloads Overrides Sub Paint(...)
Dim o As Object
Dim col As Color
o = Me.GetColumnValueAtRow(source, rowNum)
If (Not (o) Is Nothing) Then
Dim c As String = CType(o, String)
col = HexToColor(c)
backBrush = New SolidBrush(col)
foreBrush = New SolidBrush(col)
MyBase.Paint(g, bounds, source, rowNum, backBrush, foreBrush,
Private Function HexToColor(ByVal c As String) As Color
Dim r, g, b As Integer
r = Int32.Parse(c.Substring(1, 2), NumberStyles.HexNumber)
g = Int32.Parse(c.Substring(3, 2), NumberStyles.HexNumber)
b = Int32.Parse(c.Substring(5, 2), NumberStyles.HexNumber)
Return Color.FromArgb(r, g, b)
CSSeditor could never have matured without the suggestions of my friend and colleague Teo Mietto.