Design patterns for writing multiple themes in Stylus/Sass?
Asked Answered
S

2

5

I'm writing a stylesheet for a web site where I need to support multiple skins/themes. For example, one theme might be black-on-white with red as the primary color, and another theme might be white-on-black with maroon as the primary color.

Almost all of the CSS from one theme translates over to the other theme, except for things like foreground and background color.

As an illustrative example, say we have a div. The size and position of that div is fixed between themes, but the color might change. We could separate this into three different CSS files like so:

/* main.css */
#box {
    position: absolute;
    top: 50px;
    left: 50px;
    width: 200px;
    height: 200px;
}

/* theme1.css */
#box {
    backround-color: red;
}

/* theme2.css */
#box {
    background-color: maroon
}

Then the end user would load main.css plus one of the theme stylesheets. Another design would be to put a class on the body element, and use selectors to apply the right colors, all in one CSS file. For example,

#box {
    position: absolute;
    top: 50px;
    left: 50px;
    width: 200px;
    height: 200px;
}

body.theme1 #box {
    backround-color: red;
}

body.theme2 #box {
    background-color: maroon
}

The advantage of the second option is that there are fewer HTTP requests. The advantage of the first option is that the user needs to load less data from the server. This is especially important when there are many different themes, and (as in my use case) when inlined background images significantly increase the weight of the CSS files.

So my question is, how can I leverage the power of CSS pre-processors like SASS or Stylus to create multiple CSS theme files?

I envision something like this maybe:

@theme(theme1) {
    $primaryColor: red;
}
@theme(theme2) {
    $primaryColor: maroon;
}

#box {
    position: absolute;
    top: 50px;
    left: 50px;
    width: 200px;
    height: 200px;

    background-color: $primaryColor;
}

which would in turn generate the three CSS files listed above in the first example.

Any ideas? Does something like this already exist?

Sequence answered 4/7, 2015 at 22:39 Comment(2)
Are you using Sass or Stylus? They are not the same thing: pick one or the other. Have you tried anything?Crocket
I'm currently using Stylus in my project, so a Stylus solution is preferred. It's early enough though that if something like this existed in SASS instead, I can make the switch.Sequence
S
5

Here's how I ended up doing this. Make three Stylus files: main.styl, theme1.styl, and theme2.styl. Then edit their content as shown below:

// theme1.styl
primaryColor = red
@require("main.styl")

// theme2.styl
primaryColor = maroon
@require("main.styl")

// main.styl
#box {
    top: 50px
    left: 50px
    width: 200px
    height: 200px
    background-color: primaryColor
}

Then what you end up with is a theme1.css and a theme2.css that contain all of the definitions for the application with their respective theming. (You won't need to use main.css any more.)

Sequence answered 5/7, 2015 at 9:35 Comment(3)
One point of consideration I'd point out with this solution however is that this will not effectively leverage browser caching since theme files will all be different. If main.styl is output and then e.g. the theme1.styl is included after the .css generated by the main file then at least the browser can cache the common css in main and make use of this regardless of the specific theme selected.Moldy
I figure that switching themes isn't something users will normally do as part of the web site; it's more of a one-time thing when you make your account. Caching then should not be affected.Sequence
Totally agree with you there, just not entirely clear what the use case was that the OP intended regarding themes so I thought best to add that in.Moldy
M
1

I have more experience with Sass so my answer will be largely focused on that. As for Stylus I do not know enough to comment.

In my opinion your first option is the most suitable. Firstly it's relatively easy to dynamically include the second 'theme specific' .css file and also like you mentioned it keeps the styles lean if you're going to end up with a lot of themes since you have the base stylesheet and then one theme specific stylesheet.

It's also more easily scalable than your second option since you can create another theme and only add the new .css file to your server/app, whereas with the second option you have to reupload the whole file. Not too much of an issue but maintaining that Sass file will probably end up quite tedious if you have a lot of themes, even if you split them into partials and then @import 'themes/theme-red' or something similar into the main Sass stylesheet before you compile.

Unfortunately Sass does not have a lot of options available serverside compilation, where you could dynamically generate the styles based on a selected theme. A compiler called phpSass does exist but it appears to be largely defunct now and I'm not sure how good it would be. LESS is more widely used for dynamic compilation since there are more options for both serverside and clientside compilation if you were inclined to consider it.

Moldy answered 4/7, 2015 at 22:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.