<h1>CSS highlight API</h1>
<pre class="editor" id="code" lang="css">ul{
min-height: 0;
}
.sub {
display: grid;
grid-template-rows: 0fr;
transition: 0.3s;
overflow: hidden;
}
:checked ~ .sub {
grid-template-rows: 1fr;
}
.txt{
animation: color .001s .5 linear forwards;
}
@keyframes color {
from {
color: var(--c1)
}
to{
color: var(--c2)
}
}</pre>
html,
body {
margin: 0;
height: 100%;
}
body {
padding: 20px;
}
.editor {
color: #383a42;
background: #fafafa;
white-space: pre-wrap;
user-modify: read-write-plaintext-only;
font-size: 20px;
padding: 1em 0.5em;
min-height: 300px;
outline-width: 4px;
outline-color: cornflowerblue;
}
::highlight(built_in) {
color: #c18401;
}
::highlight(comment) {
color: #a0a1a7;
font-style: italic;
}
::highlight(number),
::highlight(selector-class) {
color: #986801;
}
::highlight(attr) {
color: #986801;
}
::highlight(string) {
color: #50a14f;
}
::highlight(selector-pseudo) {
color: #986801;
}
::highlight(attribute) {
color: #50a14f;
}
::highlight(keyword) {
color: #a626a4;
}
const highlights = function (pre) {
pre.normalize();
const words = hljs.highlight(pre.textContent, {
language: pre.getAttribute("lang"),
})._emitter.rootNode.children;
console.log(words);
CSS.highlights.clear();
// const el = pre.firstChild
const nodes = pre.firstChild;
const text = nodes.textContent;
const highlightMap = {};
let startPos = 0;
words
.filter((el) => el.scope)
.forEach((el) => {
const str = el.children[0];
const scope = el.scope;
const index = text.indexOf(str, startPos);
if (index < 0) {
return;
}
const item = {
start: index,
scope: scope,
end: index + str.length,
str: str,
};
if (highlightMap[scope]) {
highlightMap[scope].push(item);
} else {
highlightMap[scope] = [item];
}
startPos = index + str.length;
});
console.log(highlightMap);
Object.entries(highlightMap).forEach(function ([k, v]) {
const ranges = v.map(({ start, end }) => {
const range = new Range();
range.setStart(nodes, start);
range.setEnd(nodes, end);
return range;
});
const highlight = new Highlight(ranges.flat());
CSS.highlights.set(k, highlight);
});
};
highlights(code);
code.addEventListener("input", function () {
highlights(this);
});
This Pen doesn't use any external CSS resources.