Login

CSS Preprocessor

Author:
jokull
Posted:
October 1, 2007
Language:
Python
Version:
.96
Score:
2 (after 2 ratings)

Here is a Django view that turns code like this:

@variables { $varcolor: #333; }
body { color: $varcolor; padding: 20px; }
.space { padding: 10px; }
.small { font-size: 10px; }
#banana(.space, .small) { margin-bottom: 10px; }

And turns it into something like this:

body { color: #333; padding: 20px; }
#banana { padding: 10px; font-size: 10px; margin-bottom: 10px; }
.small { font-size: 10px; }
.space { padding: 10px; }

Notice the variables declaration at the top. The other feature is extending - here #banana extends .space and .small.

The url.py entry might look something like this:

(r'^css/(?P<css>(\w|-)+)\.css$','csspp.csspp'),

Here referencing csspp.py in your path (root directory of your site probably). The code also looks for a CSS_DIR setting in your settings file. You will probably want to point straight to your media/css/ directory.

Known problems

  • There is now way of extending selectors that are already extending something else. In the example code there is now way to extend #banana since it is already extending .small and .space.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
from django.http import HttpResponse, Http404
from django.conf import settings

def csspp(request, css):
	
	try:
		f = open("%s/%s.css" % (settings.CSS_DIR, css))
		css = f.read().strip("\n").strip()
		f.close()
	except:
		raise Http404
	
	css_dict = {}

	for line in [line.strip() for line in css.split("}") if line.find("{") > 0]:
		selector = line.split("{")[0].strip()
		line = line.split("{")[1].strip()
		rules = {}
		rule_list = [rule.strip() for rule in line.split(";") if rule.find(":") > 0]
		for rule in rule_list:
			prop = rule.split(":")[0].strip()
			value = rule.split(":")[1].strip()
			if value.startswith("$"):
				value = css_dict["@variables"][value]
			rules[prop] = value
		css_dict[selector] = rules

	for selector in [selector for selector in css_dict if selector.endswith(")") and selector.find("(") > 0]:
		old_selector = selector
		selector = selector.split("(")[0]
		css_dict[selector] = css_dict[old_selector]
		for extend in old_selector.split("(")[1].split(")")[0].split(","):
			try:
				if css_dict[extend]:
					for rule in css_dict[extend]:
						css_dict[selector][rule] = css_dict[extend][rule]
			except:
				pass
		del css_dict[old_selector]
	
	try:
		del css_dict["@variables"]
	except:
		pass

	css = ""

	for selector in css_dict:
		css += selector+" { "
		for rule in css_dict[selector]:
			css += "%s: %s; " % (rule, css_dict[selector][rule])
		css += "} \n"

	return HttpResponse(css, mimetype="text/css; charset=utf-8")

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 11 months, 2 weeks ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months, 3 weeks ago
  3. Serializer factory with Django Rest Framework by julio 1 year, 6 months ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 7 months ago
  5. Help text hyperlinks by sa2812 1 year, 7 months ago

Comments

derivin (on October 1, 2007):

How is this better than using django templates and the

{% with #ffffff as color %} {{ color }} {% endwith %}

statements? why create a new template system when we have one?

#

jokull (on October 1, 2007):

Whatever floats your boat. My way keeps the syntax very close to what CSS looks like anyway. I like that. Django templates are very awesome but here they stray far away from the compact syntax of CSS.

#

jokull (on October 2, 2007):

One would probably want to implement some caching of the generated styles.

#

Please login first before commenting.