通过模板和占位符动态生成css

时间:2017-01-05 18:48:32

标签: javascript html css sass

我想在运行时动态生成css

最初我使用过sass并定义了一些变量并使用了这些变量。但是必须首先从scss生成css。 Sass让我可以灵活地使用变量和函数,但我仍然无法通过javascript在运行时更改它们。

一种方法是通过javascript更改内联样式,但这种方法并不完全灵活。

 document.getElementById("myDiv").style.color = "red"; 

我不想在上面做,也不想通过javascript附加任何<style>属性。

我想使用javascript但不能用于修改每个样式属性。我希望使用css和javascript实现scss效果,但在运行时即动态。

E.g。假设我从 ajax调用获得了color信息,现在我想根据立即收到的color更改网站的整个主题,而无需重新启动或重新部署我的应用程序。

e.g

在scss中完成

.myClass {
           background:$color;
           // Update color value dynamically at run-time
}

甚至是可能还是我在错误的方向思考!

4 个答案:

答案 0 :(得分:1)

扩展链接的&#34;可能的副本中提供的信息&#34;问题,您可以轻松设置&#34;默认&#34;页面CSS文件中的样式集,然后根据AJAX调用的响应创建包含任何覆盖的内联<style>元素。只要元素/ class / id定义在两个位置(即CSS文件和内联样式部分)中相同,特异性将导致内联定义覆盖CSS。

因此,使用您的示例,您的静态CSS文件将包含:

.myClass {
    background: #FFFFFF;
}

。 。 。如果AJAX调用失败,则存在默认值,然后动态创建的<style>部分将包含:

.myClass {
    background: THE_AJAX_RESPONSE_VALUE;
}

。 。 。这将覆盖默认值。

更新#1:

根据您的示例JSON,这将非常简单。 。 。你将遍历JSON的每个顶级属性并创建它:

KEY_NAME {
    . . .
}

然后,在该块中,循环遍历该属性中的每个属性,并添加键和值以创建样式定义:

KEY_NAME {
    key1: value1,
    key2: value2,
    . . .
    keyN: valueN
}

更新#2:

您还可以使用StyleSheetCSSStyleSheet接口来访问现有样式表中的规则,但是,假设它使用类似于数组的结构,则意味着循环遍历所有CSS定义以找到您想要的并改变它。如何做到这一点的一个例子可以在另一个SO问题的答案中找到:Is it possible to alter a CSS stylesheet using JavaScript? (NOT the style of an object, but the stylesheet itself)

在这两种方法之间,创建一个重要的<style>部分似乎更容易。

答案 1 :(得分:1)

由于JSON同时具有元素名称和相关样式,因此刷新页面样式表(vs内联元素样式)可能是最快的,因为它使用innerHTML并且只需要单个DOM查找。

您需要循环使用JSON来创建CSS兼容字符串,然后将其转储到onpage样式元素中。您可以通过将现有innerHTML与新CSS字符串连接来附加CSS。为简单起见,我在样式表中添加了一个ID,但您也可以在需要时生成样式元素。

&#13;
&#13;
var StringifiedAjaxStyleObject = "h1 {background-color: #ecc; color: #633}";
var styleSheet = document.getElementById("style-update");

// some additional fake test style returns...
var testStyle1 = "h1 {background-color: #ccc; color: #333}";
var testStyle2 = "h1 {background-color: #667; color: #bbc}";
var testStyle3 = "h1 {background-color: #fee; color: #b00}";

// some fake ajax returns...
window.setTimeout(function() {
  styleSheet.innerHTML = StringifiedAjaxStyleObject;
}, 1000);
window.setTimeout(function() {
  styleSheet.innerHTML = testStyle1;
}, 2000);
window.setTimeout(function() {
  styleSheet.innerHTML = testStyle2;
}, 3000);
window.setTimeout(function() {
  styleSheet.innerHTML = testStyle3;
}, 4000);
&#13;
/* base styles ... */
h1 {
  padding: 5px;
  background-color: #eef;
  color: #007
}
&#13;
<!-- empty stylesheet -->
<style id="style-update" type="text/css" rel="stylesheet"></style>

<h1>Hi, mom</h1>
<button>Update Styles<button>
&#13;
&#13;
&#13;

修改

这是一个基于评论中JSON对象的更真实的版本。通过按钮触发它。

&#13;
&#13;
var styleSheet = document.getElementById("style-update");
var btn = document.querySelector('button');

btn.addEventListener("click", updateStyles);

function updateStyles() {
  var StringifiedAjaxStyleObject
    , newCSS
    , ajaxReturn
  ;

  // ...your ajax method to get the new styles...
  // on success...
  ajaxReturn = {
    ".base": {
      "background-color": "#b83605",
      "border-color": "#543927",
      "color": "gray",
      "text-shadow": "0 -1px 0 rgba(0, 0, 0, 0.15)"
    },
    ".overlay": {
      "background": "rgba(76, 65, 80, 0.2)",
      "color" : "#ddd"
    }
  };
  
  // Convert the object to a string
  newCSS = cssStringFromJson(ajaxReturn);

  // Update the stylesheet
  styleSheet.innerHTML = newCSS;
}


function cssStringFromJson(cssJSON) {
  var styleStr = "",
    i, j;

  for (i in cssJSON) {
    styleStr += i + " {\n"
    for (j in cssJSON[i]) {
      styleStr += "\t" + j + ": " + cssJSON[i][j] + ";\n"
    }
    styleStr += "}\n"
  }

  return styleStr;
}
&#13;
/* base styles ... */
.base {
  border: 1px solid #ccf;
  background-color: #eef;
  color: #000;
  padding: 15px;
}

.overlay {
  padding: 5px 15px;
  background: rgba(96, 95, 180, 0.2);
}

body {
  font-family: sans-serif;
}

button {
  margin-top: 1em;
  font-size: 1em;
}
&#13;
<!-- empty stylesheet -->
<style id="style-update" type="text/css" rel="stylesheet"></style>

<div class="base">
  <p>.base</p>
  <div class="overlay">
    <p>.overlay</p>
  </div>
</div>

<button>Update Styles</button>
&#13;
&#13;
&#13;

答案 2 :(得分:1)

玩弄这个和CSS变量。我正在添加第二个答案,因为它与我的第一个答案的方法非常不同,它更符合你原来的问题(用JS更新CSS变量)。

但是......不要这样做。 :) IE中的浏览器支持&lt;边缘不存在,它几乎肯定比更新页面上的<style>元素要慢,尽管我还没有测试过它。这个jsperf测试各种样式更新方法。它不包含innerHTML单个style元素(可能是最快的),但您可以看到以下CSS DOM方法比其他方法慢。

// get the stylesheet
// array position depends on how many style sheets you're loading.     
// adjust as needed.
var sheet = document.styleSheets[0];


// simplest method: insertRule()
// setTimeout only for demo so you can see the change
window.setTimeout(function(){
  // @media all {} is a trick to insert more than one 
  // selector and/or properties at once. Otherwise it's:
  // sheet.insertRule(":root", "--header-color: green"); ...repeat...
  sheet.insertRule("@media all { :root { --header-color: green; --main-color: orange;  } }", 1);
}, 1200);



// SAFER method via addCSSRule. 
// button and getAjaxStyles are just placeholders, obviously
var btn = document.querySelector('button');
btn.addEventListener("click", getAjaxStyles);

function getAjaxStyles() {
  // success callback... break apart the json and update the CSS variables
  addCSSRule(sheet, ":root", "--header-color: orange");
  addCSSRule(sheet, ":root", "--main-color: blue");
  addCSSRule(sheet, ":root", "--alt-color: red");
  addCSSRule(sheet, ":root", "--borderColorA: lavender");
  
  // or go with a single big string. definitely faster:
  // addCSSRule(sheet, ":root", "--alt-color: red; --borderColorA: #0ff; ")
}

// Credit for addCSSRule() goes to Diego Flórez in a comment on 
// https://davidwalsh.name/add-rules-stylesheets
var addCSSRule = function(sheet, selector, rules) {
  //Backward searching of the selector matching cssRules
  var index = sheet.cssRules.length - 1;
  for (var i = index; i > 0; i--) {
    var current_style = sheet.cssRules[i];
    if (current_style.selectorText === selector) {
      //Append the new rules to the current content of the cssRule;
      rules = current_style.style.cssText + rules;
      sheet.deleteRule(i);
      index = i;
    }
  }
  if (sheet.insertRule) {
    sheet.insertRule(selector + "{" + rules + "}", index);
  } else {
    sheet.addRule(selector, rules, index);
  }
  return sheet.cssRules[index].cssText;
}
/* Set initial CSS variables */
:root {
  --header-color: #333;
  --main-color: #888;
  --alt-color: #bbb;
  --borderColorA: #ccc;
}
h1 {
  color: var(--header-color);
}
p {
  border-bottom: 1px solid var(--borderColorA);
  color: var(--main-color);
}
p+p {
  color: var(--alt-color);
}
<h1>header</h1>
<p>paragraph 1</p>
<p>paragraph 2</p>
<button>Update CSS Variables</button>

答案 3 :(得分:0)

您可以尝试角度模板。 它会打破你以前的sass,但它会在以后解决。