使用Django和CSS变量的用户生成的主题

100 阅读2分钟

考虑一个 "白标 "应用程序,CMS管理员可以定制他们面向公众的仪表板的设计。开发人员的任务是将用户填入的少量数值保存到数据库中。颜色、字体,也许还有一两张背景图片,现在需要覆盖整个系统中的几十个CSS属性。

Django Compressor在历史上对这种类型的任务很有帮助。工作流程是这样的。

  1. 建立一个SASS文件/Django模板混合体,看起来像这样。
$brand-color: {{ user.brand_color }};
$link-color: {{ user.link_color }};
$font-family: {{ user.font_family }};
  1. 将该文件导入Django Compressor,并使用这些变量而不是默认值建立一个新的完整的应用CSS副本。

  2. 如果新的CSS文件存在的话,在基本应用文件下面注入一个链接,让CSS级联正确覆盖一切。

这在2020年是次优的,有几个原因。它创造了不必要的重复代码。它在服务器上增加了一个潜在的故障点。使用现代的CSS,有办法让浏览器做所有的重活。

进入CSS变量

如果用户主题不需要支持Internet Explorer,那么CSS变量就非常适合这项任务。(如果IE是强制性的,css-vars-ponyfill可能会帮助你完成这项工作。)通过CSS变量,可以使用级联覆盖变量,所以我们可以完全避免使用预处理器。我们也可以用一种相当外科手术的方式来做这种改变,而不需要完全重构你的样式表,使之脱离 SASS 或 LESS。请注意,这并不是我开始一个新项目的方式。相反,我会把 CSS 变量作为一等公民来对待。这只是一个安全的方法来对老的代码库进行改变。

更新基础SCSS文件

首先,我们将更新基本的SCSS文件,以使用CSS变量,并回退到原来的值。原始的_variables.scss 文件看起来是这样的。

$heading-color: #222 !default;
$link-color: #33C !default;
$font-family: Lato, sans-serif !default;

为了保留这些默认值并在以后用CSS变量覆盖它们,我们需要注入CSS变量语法。

$heading-color: var(--heading-color, #222);
$link-color: var(--link-color, #33C);
$font-family: var(--font-family, "Lato, sans-serif");

如果没有定义CSS变量,将使用原来的值。在做了这些修改之后,现在是时候交叉手指,希望CSS能够编译了。

它可能不会。

如果SCSS源在整个项目中使用颜色函数,就会出现错误。例如,SASS将不知道如何处理mix($black, $heading-color, 20%) ,因为$heading-color 不再解析为可计算的颜色值。这些将需要手动重构。根据SCSS中颜色的结构,解决方案有很大不同。这可以通过巧妙地使用RGBA梯度叠加来解决,也可以通过CSS变量的方式来解决颜色问题,或者在_variables.scss 中制作更多的变量来整合这项工作,把所有的颜色计算放在一个地方。不幸的是,SASS的颜色函数仍然比试图在CSS中完成这项工作要优雅得多,所以每个解决方案都有取舍。

更新Django模板

现在SASS已经准备好了,基本的CSS文件可以用现代的纯前端工具来编译,而CSS变量将只用于主题覆盖。Django模板可以是一个编译成CSS文件的模板文件(出于页面缓存的原因,这将是最好的),或者是仪表盘HTML模板中内联的<style> 标签。

{% block append_head %}
<style>
:root {
    {% if user.heading_color %} 
    --heading-color: {{ user.heading_color }}; 
    {% endif %}
    {% if user.link_color %} 
    --link-color: {{ user.link_color }}; 
    {% endif %}
    {% if user.font_family %} 
    --font-family: {{ user.font_family }};
    {% endif %}
}
</style>
{% endblock append_head %}

结束它,或者继续前进

这是一个开始使用CSS自定义属性的小例子。它是一项强大的技术,有很好的浏览器支持,在林肯环形山,它已经改变了游戏规则。所以,如果它还没有成为你的常规工具带的一部分,现在是时候给它一个机会了。