[英]How to generate CSS variable values to a new stylesheet
I'm working on a project in which a user can select colors from a color input and create their own theme dynamically using CSS variables.我正在开发一个项目,在该项目中,用户可以从颜色输入中选择颜色并使用 CSS 变量动态创建自己的主题。 I'd like the user to be able to download the entire CSS file with the values they selected.我希望用户能够使用他们选择的值下载整个 CSS 文件。
My issue : The CSS file downloaded doesn't display the actual color values, but shows the variable name.我的问题:下载的 CSS 文件不显示实际颜色值,但显示变量名称。
NOT WANTED
pre[class*="language-"] {
background: var(--block-background);
}
instead of代替
WANTED OUTPUT
pre[class*="language-"] {
background: #0D2831;
}
I know I can get CSS property values by doing the following.我知道我可以通过执行以下操作来获取 CSS 属性值。
const styles = getComputedStyle(document.documentElement)
const value = String(styles.getPropertyValue('--block-background')).trim()
I figured that I would create a function that loops through all my CSS variables and grabs the corresponding property values and then adds them to a new stylesheet for the user to download, but I got lost along the way.我想我会创建一个函数来循环遍历我所有的 CSS 变量并获取相应的属性值,然后将它们添加到一个新的样式表中供用户下载,但我在此过程中迷路了。 I currently have two CSS files, a main.css
and a prism.css
.我目前有两个 CSS 文件,一个main.css
和一个prism.css
。 The main.css
file holds the page styling and all CSS variables within the root. main.css
文件包含页面样式和根目录中的所有 CSS 变量。 The prism.css
file contains the theme in which I want the user to be able to download. prism.css
文件包含我希望用户能够下载的主题。
I'm trying to find a way to create a new stylesheet that contains everything within the prism.css
file but has the actual color hex code instead of the CSS variable name as a value to the given CSS property.我试图找到一种方法来创建一个新样式表,该样式表包含prism.css
文件中的所有内容,但具有实际的颜色十六进制代码而不是 CSS 变量名称作为给定 CSS 属性的值。
Index.js索引.js
import { colors } from './colorHelper'
const inputs = [].slice.call(document.querySelectorAll('input[type="color"]'));
const handleThemeUpdate = (colors) => {
const root = document.querySelector(':root');
const keys = Object.keys(colors);
keys.forEach(key => {
root.style.setProperty(key, colors[key]);
});
}
inputs.forEach((input) => {
input.addEventListener('change', (e) => {
e.preventDefault()
const cssPropName = `--${e.target.id}`;
document.styleSheets[2].cssRules[3].style.setProperty(cssPropName, e.target.value)
handleThemeUpdate({
[cssPropName]: e.target.value
});
console.log(`${cssPropName} is now ${e.target.value}`)
});
});
const cssRules = document.styleSheets[2].cssRules;
for (var i = 0; i < cssRules.length; i++) {
// Finds css variable names
const regexp = /(?:var\(--)[a-zA-z\-]*(?:\))/
let cssVariables = cssRules[i].cssText.matchAll(regexp)
cssVariables = Array.from(cssVariables).join()
console.log(cssVariables)
}
colorHelper.js颜色助手.js
const colorSelect = {
'Line Highlights': {
'highlight-background': '#F7EBC6',
'highlight-accent': '#F7D87C'
},
'Inline Code': {
'inline-code-color': '#DB4C69',
'inline-code-background': '#F9F2F4'
},
'Code Blocks': {
'block-background': '#0D2831',
'base-color': '#5C6E74',
'selected-color': '#b3d4fc'
},
'Tokens': {
'comment-color': '#93A1A1',
'punctuation-color': '#999999',
'property-color': '#990055',
'selector-color': '#669900',
'operator-color': '#a67f59',
'operator-background': '#FFFFFF',
'variable-color': '#ee9900',
'function-color': '#DD4A68',
'keyword-color': '#0077aa'
}
}
const colorNames = []
const colors = {}
Object.keys(colorSelect).map(key => {
const group = colorSelect[key]
Object.keys(group).map(color => {
colorNames.push(color)
colors[color] = group[color]
})
})
export { colorSelect, colorNames, colors }
prism.css棱镜.css
pre[class*="language-"],
code[class*="language-"] {
color: var(--base-color);
font-size: 13px;
text-shadow: none;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
direction: ltr;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::selection,
code[class*="language-"]::selection,
pre[class*="language-"]::mozselection,
code[class*="language-"]::mozselection {
text-shadow: none;
background: var(--selected-color);
}
@media print {
pre[class*="language-"],
code[class*="language-"] {
text-shadow: none;
}
}
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
background: var(--block-background);
}
:not(pre) > code[class*="language-"] {
padding: .1em .3em;
border-radius: .3em;
color: var(--inline-code-color);
background: var(--inline-code-background);
}
/* Tokens */
.namespace {
opacity: .7;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: var(--comment-color);
}
.token.punctuation {
color: var(--punctuation-color);
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: var(--property-color);
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: var(--selector-color);
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: var(--operator-color);
background: var(--operator-background);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: var(--keyword-color);
}
.token.function {
color: var(--function-color);
}
.token.regex,
.token.important,
.token.variable {
color: var(--variable-color);
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
/* Line highlighting */
pre[data-line] {
position: relative;
}
pre[class*="language-"] > code[class*="language-"] {
position: relative;
z-index: 1;
}
.line-highlight {
position: absolute;
left: 0;
right: 0;
padding: inherit 0;
margin-top: 1em;
background: var(--highlight-background);
box-shadow: inset 5px 0 0 var(--highlight-accent);
z-index: 0;
pointer-events: none;
line-height: inherit;
white-space: pre;
}
I have three stylesheets.我有三个样式表。
style.css
holds the CSS variables in the root style.css
将 CSS 变量保存在根目录中
normalize.css
prism.css
contains the styles for syntax highlighting. prism.css
包含语法高亮的样式。 This is the stylesheet I would like the user to download, but I would like to provide them with the actual hex values for each variable and not the variable name for the CSS property.这是我希望用户下载的样式表,但我希望为他们提供每个变量的实际十六进制值,而不是 CSS 属性的变量名称。
Stylesheet order in my HTML我的 HTML 中的样式表顺序
<link rel="stylesheet" type="text/css" href="./style.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.css"
integrity="sha256-WAgYcAck1C1/zEl5sBl5cfyhxtLgKGdpI3oKyJffVRI=" crossorigin="anonymous" />
<link href="./themes/prism.css" rel="stylesheet" />
EDIT编辑
I attempted to loop through the stylesheet and grab the CSS variable names, but some of them returned as an empty string.我试图遍历样式表并获取 CSS 变量名称,但其中一些作为空字符串返回。
This is what I did这就是我所做的
const cssRules = document.styleSheets[2].cssRules;
for (var i = 0; i < cssRules.length; i++) {
const regexp = /(?:var\(--)[a-zA-z\-]*(?:\))/
let cssVariables = cssRules[i].cssText.matchAll(regexp)
cssVariables = Array.from(cssVariables)
console.log(cssVariables)
}
This was the result in the console这是控制台中的结果
var(--base-color)
var(--selected-color)
<empty string>
var(--block-background)
var(--inline-code-color)
<empty string>
var(--comment-color)
var(--punctuation-color)
var(--property-color)
var(--selector-color)
var(--operator-color)
var(--keyword-color)
var(--function-color)
var(--variable-color)
<empty string>
var(--highlight-background)
I then attempted to chain .replace()
after the trim()
but that didn't seem to work either.然后我尝试在trim()
.replace()
之后链接.replace()
,但这似乎也不起作用。
You can download the file as text then find and replace the variables.您可以将文件下载为文本,然后查找并替换变量。
For example:例如:
var s = `pre[class*="language-"] { background: var(--block-background); }` const variables = {"block-background":"#0D2831"}; Object.keys(variables).forEach(key => { s = s.replace("var(--"+key+")", variables[key]); }); console.log(s);
You are getting empty strings from css rules that do not have var(--something)
in them.您从其中没有var(--something)
css 规则中获取空字符串。 Like喜欢
@media print { pre[class*="language-"], code[class*="language-"] { text-shadow: none; } }
which gives you the first empty string.这给你第一个空字符串。
You are missing var(--operator-background)
because matchAll()
actually doesn't do what you expect.您缺少var(--operator-background)
因为matchAll()
实际上并没有按照您的预期执行。 It does它确实
returns an iterator of all results matching a string against a regular expression返回与正则表达式匹配字符串的所有结果的迭代器
but the regular expression you have yields only one result.但是您拥有的正则表达式只会产生一个结果。 So you need to add g
flag to it所以你需要给它添加g
标志
/(?:var\\(--)[a-zA-z\\-]*(?:\\))/g
mozselection
... Hmm... Not sure, but shouldn't it be -moz-selection
? mozselection
......嗯......不确定,但不应该是-moz-selection
吗?
The full loop for replacements can look like this:替换的完整循环如下所示:
const updated_rules = []; for (var i = 0; i < cssRules.length; i++) { const regexp = /(?:var\\(--)[a-zA-z\\-]*(?:\\))/g; let updated_rule = cssRules[i].cssText; let cssVariables = updated_rule.matchAll(regexp); cssVariables = Array.from(cssVariables).flat(); for (const v of cssVariables) { updated_rule = updated_rule.replace(v, colors[v.slice(6, -1)]); } updated_rules.push(updated_rule); } console.log(updated_rules);
It's an ugly code, and should be refactored, but...这是一个丑陋的代码,应该重构,但是......
Why would you access css through document.styleSheets
anyway?你为什么要通过document.styleSheets
访问 css 呢? It's harder than just replacing strings in a css-file and for one thing, I'm not sure if you whould be able to access ::-moz-selection
rule on Chrome, and in turn ::-webkit-selection
on Firefox这比仅替换 css 文件中的字符串更难,一方面,我不确定您是否能够在 Chrome 上访问::-moz-selection
规则,然后在 Firefox 上访问::-webkit-selection
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.