Design patterns for writing multiple themes in Sty

2019-06-26 09:30发布

问题:

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?

回答1:

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.)



回答2:

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.