Reading through this thread I was inspired by a number of different possibilities for how text could be manipulated with a CSS-like syntax!
Currently CSS can:
- Set a pseudo-element’s
content
with text from an HTML attribute()
- Set a pseudo-element’s
content
with a text string from CSS
And CSS cannot:
- Set an element’s
innerHTML
with text from an HTML attribute
- Set an element’s
innerHTML
with a text string from CSS
- Target an element based on a search of the text it contains.
For those last three I have experimented with element queries and the possibility of evaluating JavaScript inside CSS (from the context of the scoped element) and here are some demos of those three ideas CSS currently cannot do:
Text from attribute as innerHTML
<h2>Text from attribute as innerHTML</h2>
<div id=text data-text="This is <strong>HTML</strong> text."></div>
<style>
@element '#text' {
eval('innerHTML = getAttribute("data-text")');
}
</style>
<script src=http://elementqueries.com/EQCSS.js></script>
This example grabs the text content from the HTML attribute data-text
on the scoped element #text
and sets it as the innerHTML
of the scoped element (itself).
I’ve used a similar technique in the past to supply responsive truncated text excerpts of longer passages: http://codepen.io/tomhodgins/pen/KgKggX
@element '[data-truncate]' {
$this:before {
content: 'eval("getAttribute('data-truncate').substring(0,scrollWidth/3)")…';
}
}
Text from CSS as innerHTML
<h2>Text from CSS as innerHTML</h2>
<div id=from-CSS></div>
<style>
@element '#from-CSS' {
eval('innerHTML = "This is <strong>HTML</strong> text."')
}
</style>
<script src=http://elementqueries.com/EQCSS.js></script>
This example does a similar thing as the last example, except the text content is fully supplied from within the stylesheet. This would make it really easy to add responsive content, or to swap out content by language, etc.
Element Selected by its Text Content
<h2>Element Selected by its Text Content</h2>
<div>This element is highlighted because it contains the word: Rubber</div>
<style>
@element 'div' {
eval('(/rubber/i).test(innerHTML) ? "$this" : ""') {
background: yellow;
}
}
</style>
<script src=http://elementqueries.com/EQCSS.js></script>
This one is really cool! I was wondering if there was a way you could target an element with a style based on its own text content. Now a few notes about this, you want to scope the element the closest to the content you’re searching. Since tags can contain other tags, if there’s any tag inside your HTML
element and you write the rule for @element 'html' {}
it will come back true. Likewise if you scoped the *
wildcard selector, this rule would be true for every parent element containing an element that contained the test you were searching.
My first attempt at doing this was formatted with indexOf()
like this:
@element 'div' {
eval('innerHTML.indexOf("Rubber") !== -1 ? "$this" : ""') {
background: yellow;
}
}
But the downside to innerHTML.indexOf("Rubber") !== -1
was that I had to enter an exact string Rubber
, and I would have to write a separate selector if I wanted to target rubber
or rUbBeR
. So instead I formatted the string I’m searching as a Regular Expression so I can use flags like i
for a case insensitive search, and using test()
to see if that regular expression matches anything in the innerHTML
. If the result of the test is true
, then the selector used will output $this
(which inside of the scoped style, refers to div
in this case) otherwise if it’s false, no selector text is output and our rule of { background: yellow }
applies to zero elements on the page.
Here’s a Codepen demo of all 5 ideas on the same page: http://codepen.io/tomhodgins/pen/ggYzmY?editors=1000
Just some fuel for the fire