Inline style
Before our in-depth knowledge of the complex, to come back to care about some of the basics. For example, you can modify it .style
to edit a given attribute HTMLElement
of the inline style.
const el = document.createElement('div') el.style.backgroundColor = 'red' // 或者 el.style.cssText = 'background-color: red' // 或者 el.setAttribute('style', 'background-color: red')
Directly .style
set style properties on an object will need to use as camel named attribute key instead 短横线命名
. If you need to set more inline style attributes, by setting the .style.cssText
property to set a more efficient way.
Remember, after cssText set to the original css style is cleared up, so we requested a bunch of dead styles.
If this is too cumbersome inline style set, you can also consider .style
to Object.assign()
be used together to set a plurality of style properties.
// ... Object.assign(el.style, { backgroundColor: "red", margin: "25px" })
These "basics" much more than we imagined. .style
Object implements the CSSStyleDeclaration
interface.
This shows it with some interesting properties and methods, including the use of just .cssText
, further comprising .length
(set number of attributes), as well as .item()
, .getPropertyValue()
and .setPropertyValue()
methods like:
// ... const propertiesCount = el.style.length for(let i = 0; i < propertiesCount; i++) { const name = el.style.item(i) // 'background-color' const value = el.style.getPropertyValue(name) // 're' const priority = el.style.getPropertyPriority(name) // 'important' if(priority === 'important') { el.style.removeProperty() } }
There is a small trick - during traversal .item()
method by index alternate form of syntax.
// ... el.style.item(0) === el.style[0]; // true
CSS class
Next, look at the structure --CSS higher class, having the form of a string and retrieving settings are .classname
.
// ... el.className = "class-one class-two"; el.setAttribute("class", "class-one class-two");
Another method is to set the string class set class
attributes (the same as the search). However, as the use of .style.cssText
property, the set .className
will include our requirements given element in the string of all classes, including the changed and unchanged classes.
Of course, you can use some simple string manipulation to get the job done, there is a relatively new is the use of .classList
property that, IE9 does not support it, and IE10 and IE11 are only partially supported it.
classlist
Properties achieved DOMTokenList
, there is a lot of useful methods. For example .add()
, , .remove()
.toggle () and .replace()
allow the current to change our CSS class set, while others, for example .item()
, .entries()
or .foreach()
can be simplified traversal of the index set.
// ... const classNames = ["class-one", "class-two", "class-three"]; classNames.forEach(className => { if(!el.classList.contains(className)) { el.classList.add(className); } });
Stylesheets
All along, Web Api Another StyleSheetList
interface, which by the document.styleSheets
realization of property. document.styleSheets
Read-only property, a return of StyleSheet
objects of StyleSheetList
each of StyleSheet
the objects are in a document linked or embedded style sheet.
for(styleSheet of document.styleSheets){ console.log(styleSheet); }
We know by the print result, each cycle is CSSStyleSheet printing objects, each object is CSSStyleSheet consists of the following attributes:
CSS Style Sheet object methods:
With StyleSheetList
all the content, we come CSS StyleSheet
itself. Here it is a bit mean, CSS StyleSheet
extends the StyleSheet
interface, and only this read-only attribute, such as .ownerNode
, .href
, .title
or .type
, most of them given to the local style sheets directly from the statement. Recall that the standard HTML code to load an external CSS file, we will understand the meaning of this sentence is valid:
<head> <link rel="stylesheet" type="text/css" href="style.css" title="Styles"> </head>
Now, we know HTML document can contain multiple style sheets, all of these stylesheets can contain different rules, may contain even more style sheets (when using @import
the time). CSSStyleSheet
There are two ways: 、.insertrule()
and .deleterule()
to add and delete Css rules.
// ... const ruleIndex = styleSheet.insertRule("div {background-color: red}"); styleSheet.deleteRule(ruleIndex);
.insertRule(rule,index)
: This function can be cssRules
inserted into a specified rule set in the rule, the parameter rule
is a string denoted rule, the parameter index
is a value of rule string inserted. deleteRule(index)
: This function can delete the specified index of compliance rules, parameters index
specified index rules. CSSStyleSheet
Also has its own two properties: .ownerRule
and .cssRule
. Although .ownerRule
the @import
correlation, but more interesting is that .cssRules
. Simply put, it is CSSRuleList
to CSSRule
be used the aforementioned .insertrule()
and .deleterule()
to modify its methods. Remember that some browsers may block our access to external CSSSt from different sources (domain) y
leSheet the .cssRules
property.
So what is CSSRuleList
?
CSSRuleList
It is an array object contains an ordered CSSRule
collection of objects. Each CSSRule
can be rules.item(index)
in the form of access, or rules[index]
. Here rules
is an implementation of the CSSRuleList
interface object, index
is based on 0
the beginning of the sequence and CSS
the sequence stylesheet is consistent. It is the number of style objects by rules.length
expression.
For CSSStyleRule objects:
Each stylesheet CSSStyleSheet
object can contain a number of CSSStyleRule
objects, i.e. css style rules, as follows:
<style type="text/css">
h1{color:red}
div{color:green}
</style>
在上面的代码中style
标签是一个CSSStyleSheet
样式表对象,这个样式表对象包含两个CSSStyleRule
对象,也就是两个css样式规则。CSSStyleRule
对象具有下列属性:
1.type
:返回0-6
的数字,表示规则的类型,类型列表如下:
0:CSSRule.UNKNOWN_RULE。
1:CSSRule.STYLE_RULE (定义一个CSSStyleRule对象)。
2:CSSRule.CHARSET_RULE (定义一个CSSCharsetRule对象,用于设定当前样式表的字符集,默认与当前网页相同)。
3:CSSRule.IMPORT_RULE (定义一个CSSImportRule对象,就是用@import引入其他的样式表)
4:CSSRule.MEDIA_RULE (定义一个CSSMediaRule对象,用于设定此样式是用于显示器,打印机还是投影机等等)。
5:CSSRule.FONT_FACE_RULE (定义一个CSSFontFaceRule对象,CSS3的@font-face)。
6:CSSRule.PAGE_RULE (定义一个CSSPageRule对象)。
2.cssText
:返回一个字符串,表示的是当前规则的内容,例如:
div{color:green}
3.parentStyleSheet
:返回所在的CSSStyleRule
对象。
4.parentRule
:如果规则位于另一规则中,该属性引用另一个CSSRule对象。
5.selectorText
:返回此规则的选择器,如上面的div就是选择器。
6.style
:返回一个CSSStyleDeclaration
对象。
// ... const ruleIndex = styleSheet.insertRule("div {background-color: red}"); const rule = styleSheet.cssRules.item(ruleIndex); rule.selectorText; // "div" rule.style.backgroundColor; // "red"
实现
现在,咱们对 CSS 相关的 JS Api有了足够的了解,可以创建咱们自己的、小型的、基于运行时的CSS-in-JS
实现。咱们的想法是创建一个函数,它传递一个简单的样式配置对象,生成一个新创建的CSS类的哈希名称供以后使用。
实现流程很简单,咱们需要一个能够访问某种样式表的函数,并且只需使用.insertrule()
方法和样式配置就可以运行了。先从样式表部分开始:
function createClassName(style) { // ... let styleSheet; for (let i = 0; i < document.styleSheets.length; i++) { if (document.styleSheets[i].CSSInJS) { styleSheet = document.styleSheets[i]; break; } } if (!styleSheet) { const style = document.createElement("style"); document.head.appendChild(style); styleSheet = style.sheet; styleSheet.CSSInJS = true; } // ... }
如果你使用的是ESM或任何其他类型的JS模块系统,则可以在函数外部安全地创建样式表实例,而不必担心其他人对其进行访问。 但是,为了演示例,咱们将stylesheet
上的.CSSInJS
属性设置为标志的形式,通过标志来判断是否要使用它。
现在,如果如果还需要创建一个新的样式表怎么办? 最好的选择是创建一个新的<style/>
标记,并将其附加到HTML文档的<head/>
上。 这会自动将新样式表添加到document.styleSheets
列表,并允许咱们通过<style/>
标记的.sheet
属性对其进行访问,是不是很机智?
function createRandomName() { const code = Math.random().toString(36).substring(7); return `css-${code}`; } function phraseStyle(style) { const keys = Object.keys(style); const keyValue = keys.map(key => { const kebabCaseKey = key.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(); const value = `${style[key]}${typeof style[key] === "number" ? "px" : ""}`; return `${kebabCaseKey}:${value};`; }); return `{${keyValue.join("")}}`; }
除了上面的小窍门之外。 自然,咱们首先需要一种为CSS类生成新的随机名称的方法。
然后,将样式对象正确地表达为可行的CSS字符串的形式。 这包括驼峰命名和短横线全名之间的转换,以及可选的像素单位(px)转换的处理。
function createClassName(style) { const className = createRandomName(); let styleSheet; // ... styleSheet.insertRule(`.${className}${phraseStyle(style)}`); return className; }
完整代码如下:
HTML
<div id="el"></div>
JS
function createRandomName() { const code = Math.random().toString(36).substring(7); return `css-${code}`; } function phraseStyle(style) { const keys = Object.keys(style); const keyValue = keys.map(key => { const kebabCaseKey = key.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(); const value = `${style[key]}${typeof style[key] === "number" ? "px" : ""}`; return `${kebabCaseKey}:${value};`; }); return `{${keyValue.join("")}}`; } function createClassName(style) { const className = createRandomName(); let styleSheet; for (let i = 0; i < document.styleSheets.length; i++) { if (document.styleSheets[i].CSSInJS) { styleSheet = document.styleSheets[i]; break; } } if (!styleSheet) { const style = document.createElement("style"); document.head.appendChild(style); styleSheet = style.sheet; styleSheet.CSSInJS = true; } styleSheet.insertRule(`.${className}${phraseStyle(style)}`); return className; } const el = document.getElementById("el"); const redRect = createClassName({ width: 100, height: 100, backgroundColor: "red" }); el.classList.add(redRect);
运行效果:
总结
正如本文咱们所看到的,使用 JS 操作CSS 是一件非常有趣的事,咱们可以挖掘很多好用的 API,上面的例子只是冰山一角,在CSS API(或者更确切地说是API)中还有更多方法,它们正等着被揭开神秘面纱。