jcu*_*bic 7 javascript css css-variables
我有JS库,我有这个问题:我正在使用等宽字体创建用于计算字符大小的临时元素.现在我正在复制风格,但我需要原始的所有样式,包括css变量.我不想克隆元素,因为里面有我不需要的元素.此外,元素可能具有用户设置的id,不确定当存在两个具有相同id的元素时这将如何表现,因此将每个样式复制到新的临时元素会更好(我认为).
我有基于这些的代码:
我的代码看起来像这样:
function is_valid_style_property(key, value) {
//checking that the property is not int index ( happens on some browser
return typeof value === 'string' && value.length && value !== parseInt(value);
}
function copy_computed_style(from, to) {
var computed_style_object = false;
computed_style_object = from.currentStyle || document.defaultView.getComputedStyle(from, null);
if (!computed_style_object) {
return;
}
Object.keys(computed_style_object).forEach(function(key) {
var value = computed_style_object.getPropertyValue(key);
if (key.match(/^--/)) {
console.log({key, value}); // this is never executed
}
if (is_valid_style_property(key, value)) {
to.style.setProperty(key, value);
}
});
}
Run Code Online (Sandbox Code Playgroud)
问题是getComputedStyle,不要返回css变量.有没有其他解决方案来获取应用于元素的CSS变量列表?
我需要CSS变量,因为我有css应用于临时项目内的元素,它基于css变量.克隆节点是将CSS变量从一个元素复制到另一个元素的唯一方法吗?
编辑:
这不是重复的,因为css变量也可以不仅在每个类的样式表中内联设置.我的元素可以通过非常不同的css选择器添加样式,这是我无法知道的.
基于这个答案/sf/answers/2657081101/,我创建了一个依赖的代码getMatchedCSSRules,以便检索所有CSS,然后提取CSS自定义属性。由于自定义属性是继承的,我们需要收集元素内定义的属性和任何父元素上定义的属性。
if (typeof window.getMatchedCSSRules !== 'function') {
var ELEMENT_RE = /[\w-]+/g,
ID_RE = /#[\w-]+/g,
CLASS_RE = /\.[\w-]+/g,
ATTR_RE = /\[[^\]]+\]/g,
// :not() pseudo-class does not add to specificity, but its content does as if it was outside it
PSEUDO_CLASSES_RE = /\:(?!not)[\w-]+(\(.*\))?/g,
PSEUDO_ELEMENTS_RE = /\:\:?(after|before|first-letter|first-line|selection)/g;
// convert an array-like object to array
function toArray(list) {
return [].slice.call(list);
}
// handles extraction of `cssRules` as an `Array` from a stylesheet or something that behaves the same
function getSheetRules(stylesheet) {
var sheet_media = stylesheet.media && stylesheet.media.mediaText;
// if this sheet is disabled skip it
if ( stylesheet.disabled ) return [];
// if this sheet's media is specified and doesn't match the viewport then skip it
if ( sheet_media && sheet_media.length && ! window.matchMedia(sheet_media).matches ) return [];
// get the style rules of this sheet
return toArray(stylesheet.cssRules);
}
function _find(string, re) {
var matches = string.match(re);
return matches ? matches.length : 0;
}
// calculates the specificity of a given `selector`
function calculateScore(selector) {
var score = [0,0,0],
parts = selector.split(' '),
part, match;
//TODO: clean the ':not' part since the last ELEMENT_RE will pick it up
while (part = parts.shift(), typeof part == 'string') {
// find all pseudo-elements
match = _find(part, PSEUDO_ELEMENTS_RE);
score[2] += match;
// and remove them
match && (part = part.replace(PSEUDO_ELEMENTS_RE, ''));
// find all pseudo-classes
match = _find(part, PSEUDO_CLASSES_RE);
score[1] += match;
// and remove them
match && (part = part.replace(PSEUDO_CLASSES_RE, ''));
// find all attributes
match = _find(part, ATTR_RE);
score[1] += match;
// and remove them
match && (part = part.replace(ATTR_RE, ''));
// find all IDs
match = _find(part, ID_RE);
score[0] += match;
// and remove them
match && (part = part.replace(ID_RE, ''));
// find all classes
match = _find(part, CLASS_RE);
score[1] += match;
// and remove them
match && (part = part.replace(CLASS_RE, ''));
// find all elements
score[2] += _find(part, ELEMENT_RE);
}
return parseInt(score.join(''), 10);
}
// returns the heights possible specificity score an element can get from a give rule's selectorText
function getSpecificityScore(element, selector_text) {
var selectors = selector_text.split(','),
selector, score, result = 0;
while (selector = selectors.shift()) {
if (matchesSelector(element, selector)) {
score = calculateScore(selector);
result = score > result ? score : result;
}
}
return result;
}
function sortBySpecificity(element, rules) {
// comparing function that sorts CSSStyleRules according to specificity of their `selectorText`
function compareSpecificity (a, b) {
return getSpecificityScore(element, b.selectorText) - getSpecificityScore(element, a.selectorText);
}
return rules.sort(compareSpecificity);
}
// Find correct matchesSelector impl
function matchesSelector(el, selector) {
var matcher = el.matchesSelector || el.mozMatchesSelector ||
el.webkitMatchesSelector || el.oMatchesSelector || el.msMatchesSelector;
return matcher.call(el, selector);
}
//TODO: not supporting 2nd argument for selecting pseudo elements
//TODO: not supporting 3rd argument for checking author style sheets only
window.getMatchedCSSRules = function (element /*, pseudo, author_only*/) {
var style_sheets, sheet, sheet_media,
rules, rule,
result = [];
// get stylesheets and convert to a regular Array
style_sheets = toArray(window.document.styleSheets);
// assuming the browser hands us stylesheets in order of appearance
// we iterate them from the beginning to follow proper cascade order
while (sheet = style_sheets.shift()) {
// get the style rules of this sheet
rules = getSheetRules(sheet);
// loop the rules in order of appearance
while (rule = rules.shift()) {
// if this is an @import rule
if (rule.styleSheet) {
// insert the imported stylesheet's rules at the beginning of this stylesheet's rules
rules = getSheetRules(rule.styleSheet).concat(rules);
// and skip this rule
continue;
}
// if there's no stylesheet attribute BUT there IS a media attribute it's a media rule
else if (rule.media) {
// insert the contained rules of this media rule to the beginning of this stylesheet's rules
rules = getSheetRules(rule).concat(rules);
// and skip it
continue
}
// check if this element matches this rule's selector
if (matchesSelector(element, rule.selectorText)) {
// push the rule to the results set
result.push(rule);
}
}
}
// sort according to specificity
return sortBySpecificity(element, result);
};
}
var element = document.querySelector(".box");
/*Get element style*/
var obj = window.getMatchedCSSRules(element)[0];
var all_css = obj.parentStyleSheet.cssRules;
for(var i=0;i < all_css.length;i++) {
var rules = all_css[i].cssText.substring(all_css[i].cssText.indexOf("{")+1,all_css[i].cssText.indexOf("}"));
rules = rules.split(";");
for(var j=0;j<rules.length;j++) {
if(rules[j].trim().startsWith("--")) {
console.log(rules[j]);
}
}
}
/*get inline style*/
var rules = element.getAttribute("style").trim().split(";");
for(var j=0;j<rules.length;j++) {
if(rules[j].trim().startsWith("--")) {
console.log(rules[j]);
}
}Run Code Online (Sandbox Code Playgroud)
:root {
--b: 20px;
}
.box {
background: red;
height: 100px;
--c: blue;
border: 1px solid var(--c);
}
.element {
--e:30px;
padding:var(--e);
}Run Code Online (Sandbox Code Playgroud)
<div class="box element" style="color:blue;--d:10ch;border-radius:20px;">
</div>Run Code Online (Sandbox Code Playgroud)
这是代码1的相关部分:
var element = document.querySelector(".box");
/*Get external styles*/
var obj = window.getMatchedCSSRules(element)[0];
var all_css = obj.parentStyleSheet.cssRules;
for(var i=0;i < all_css.length;i++) {
var rules = all_css[i].cssText.substring(all_css[i].cssText.indexOf("{")+1,all_css[i].cssText.indexOf("}"));
rules = rules.split(";");
for(var j=0;j<rules.length;j++) {
if(rules[j].trim().startsWith("--")) {
console.log(rules[j]);
}
}
}
/*Get inline styles*/
var rules = element.getAttribute("style").trim().split(";");
for(var j=0;j<rules.length;j++) {
if(rules[j].trim().startsWith("--")) {
console.log(rules[j]);
}
}
Run Code Online (Sandbox Code Playgroud)
如您所见,这将打印所需的值。您可以轻松调整代码以将值存储在数组或对象中。
1:此代码未优化,因为在某些情况下它可能会收集不需要的 CSS。会继续编辑。