Skip to content

Instantly share code, notes, and snippets.

@tomhodgins
Last active December 8, 2017 15:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tomhodgins/94fc1dc73ec0fc9d3dfc6722192924a8 to your computer and use it in GitHub Desktop.
Save tomhodgins/94fc1dc73ec0fc9d3dfc6722192924a8 to your computer and use it in GitHub Desktop.
Server-side Element Queries on Static HTML
/*
These element queries have nothing to do with width, but extend the power of CSS selector - as long as they don't need to be used with interactive content. This means they aren't suitable for:
- interaction-based pseudo-classes like :hover, :focus, :active, etc
- queries on interactive content, like inside form elements
- dynamic HTML that will in structure after the page loads
- scroll position or dimensions
Where it might be useful:
- select by text content length
- select by regex search of text content
- select by string search of text content
- select direct parents of a CSS selector
- select ancestors of a CSS selector
- select previous sibling of a CSS selector
- select first instance of CSS selector in DOM
*/
/* Character count in text content */
${containerQuery('.headline h2', el => el.textContent.length > 10, `
$this {
font-size: 80%;
background: lime;
}
`)}
/* String match in text content */
${containerQuery('.string li', el => (el.textContent).indexOf('laughter') !== -1, `
$this {
background: hotpink;
}
`)}
/* Regex match in text content */
${containerQuery('.regex li', el => /laughter/.test(el.textContent), `
$this {
background: orange;
}
`)}
/* Parent Selector */
${containerQuery('.parent > ul', el => el.querySelector('.target') && el.querySelector('.target').parentNode === el, `
$this {
background: purple;
}
`)}
/* Ancestor Selector */
${containerQuery('.ancestor .goal', el => el.querySelector('.target'), `
$this {
border: 5px solid yellow;
}
`)}
/* Previous Sibling Selector */
${containerQuery('.previous *', el => el.nextElementSibling && el.nextElementSibling.classList.contains('target'), `
$this {
background: teal;
}
`)}
/* First of Selector in Document */
${containerQuery('.first span', el => el === document.querySelector('.first span'), `
$this {
background: hotpink;
}
`)}
<!DOCTYPE html>
<meta charset=utf-8>
<meta name=viewport content="width=device-width, initial-scale=1">
<title>Element Query Explorations</title>
<h1>Element Query Explorations for static (non-dynamic) HTML</h1>
<h2>Character count in text content</h2>
<section class=headline>
<h2>MMMMM</h2>
<h2>MMMMMMMMMM</h2>
<h2>MMMMMMMMMMMMMMM</h2>
<h2>MMMMMMMMMMMMMMMMMMMM</h2>
</section>
<h2>String match in text content</h2>
<section class=string>
<ul>
<li>to laugh is the best medicine</li>
<li>laughter is the best medicine</li>
<li>slaughter is the best medicine</li>
</ul>
</section>
<h2>Regex match in text content</h2>
<section class=regex>
<ul>
<li>to laugh is the best medicine</li>
<li>laughter is the best medicine</li>
<li>slaughter is the best medicine</li>
</ul>
</section>
<h2>Parent Selector (like <code>:has()</code>)</h2>
<section class=parent>
<ul>
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
</ul>
<ul>
<li>item 1</li>
<li class=target>target</li>
<li>item 3</li>
</ul>
</section>
<h2>Ancestor Selector</h2>
<section class=ancestor>
<ul class=goal>
<li>item</li>
<li>item
<ul>
<li>item</li>
<li class=target>target</li>
<li>item</li>
</ul>
</li>
<li>item</li>
</ul>
<ul>
<li>item</li>
<li>item
<ul class=goal>
<li>item</li>
<li class=target>target</li>
<li>item</li>
</ul>
</li>
<li>item</li>
</ul>
</section>
<h2>Previous Sibling Selector</h2>
<section class=previous>
<ul>
<li>item</li>
<li class=target>target</li>
<li>item</li>
</ul>
</section>
<h2>First of Selector in Document</h2>
<section class=first>
<p>Lorem ipsum <span>dolor</span> sit amet, consectetur <span>adipisicing</span> elit, sed do eiusmod tempor <span>incididunt</span> ut labore et dolore magna aliqua.</p>
</section>
@media (min-width: 1px) and (max-width: 2000px) {
[data-headlineh2eleltextcontentlength10at1="0"],
[data-headlineh2eleltextcontentlength10at1="1"] {
font-size: 80%;
background: lime;
}
[data-stringlieleltextcontentindexoflaughter1at1="0"],
[data-stringlieleltextcontentindexoflaughter1at1="1"] {
background: hotpink;
}
[data-regexliellaughtertesteltextcontentat1="0"],
[data-regexliellaughtertesteltextcontentat1="1"] {
background: orange;
}
[data-parentulelelqueryselectortargetelqueryselectortargetparentnodeelat1="0"] {
background: purple;
}
[data-ancestorgoalelelqueryselectortargetat1="0"],
[data-ancestorgoalelelqueryselectortargetat1="1"] {
border: 5px solid #ff0;
}
[data-previouselelnextelementsiblingelnextelementsiblingclasslistcontainstargetat1="0"] {
background: teal;
}
[data-firstspaneleldocumentqueryselectorfirstspanat1="0"] {
background: hotpink;
}
}
@media (min-width: 2000px) {
[data-headlineh2eleltextcontentlength10at2000="0"],
[data-headlineh2eleltextcontentlength10at2000="1"] {
font-size: 80%;
background: lime;
}
[data-stringlieleltextcontentindexoflaughter1at2000="0"],
[data-stringlieleltextcontentindexoflaughter1at2000="1"] {
background: hotpink;
}
[data-regexliellaughtertesteltextcontentat2000="0"],
[data-regexliellaughtertesteltextcontentat2000="1"] {
background: orange;
}
[data-parentulelelqueryselectortargetelqueryselectortargetparentnodeelat2000="0"] {
background: purple;
}
[data-ancestorgoalelelqueryselectortargetat2000="0"],
[data-ancestorgoalelelqueryselectortargetat2000="1"] {
border: 5px solid #ff0;
}
[data-previouselelnextelementsiblingelnextelementsiblingclasslistcontainstargetat2000="0"] {
background: teal;
}
[data-firstspaneleldocumentqueryselectorfirstspanat2000="0"] {
background: hotpink;
}
}
<!DOCTYPE html><html><head><meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Element Query Explorations</title>
<link href="element-external.css" rel="stylesheet"></head><body><h1>Element Query Explorations for static (non-dynamic) HTML</h1>
<h2>Character count in text content</h2>
<section class="headline">
<h2>MMMMM</h2>
<h2>MMMMMMMMMM</h2>
<h2 data-headlineh2eleltextcontentlength10at1="0" data-headlineh2eleltextcontentlength10at2000="0">MMMMMMMMMMMMMMM</h2>
<h2 data-headlineh2eleltextcontentlength10at1="1" data-headlineh2eleltextcontentlength10at2000="1">MMMMMMMMMMMMMMMMMMMM</h2>
</section>
<h2>String match in text content</h2>
<section class="string">
<ul>
<li>to laugh is the best medicine</li>
<li data-stringlieleltextcontentindexoflaughter1at1="0" data-stringlieleltextcontentindexoflaughter1at2000="0">laughter is the best medicine</li>
<li data-stringlieleltextcontentindexoflaughter1at1="1" data-stringlieleltextcontentindexoflaughter1at2000="1">slaughter is the best medicine</li>
</ul>
</section>
<h2>Regex match in text content</h2>
<section class="regex">
<ul>
<li>to laugh is the best medicine</li>
<li data-regexliellaughtertesteltextcontentat1="0" data-regexliellaughtertesteltextcontentat2000="0">laughter is the best medicine</li>
<li data-regexliellaughtertesteltextcontentat1="1" data-regexliellaughtertesteltextcontentat2000="1">slaughter is the best medicine</li>
</ul>
</section>
<h2>Parent Selector (like <code>:has()</code>)</h2>
<section class="parent">
<ul>
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
</ul>
<ul data-parentulelelqueryselectortargetelqueryselectortargetparentnodeelat1="0" data-parentulelelqueryselectortargetelqueryselectortargetparentnodeelat2000="0">
<li>item 1</li>
<li class="target">target</li>
<li>item 3</li>
</ul>
</section>
<h2>Ancestor Selector</h2>
<section class="ancestor">
<ul class="goal" data-ancestorgoalelelqueryselectortargetat1="0" data-ancestorgoalelelqueryselectortargetat2000="0">
<li>item</li>
<li>item
<ul>
<li>item</li>
<li class="target">target</li>
<li>item</li>
</ul>
</li>
<li>item</li>
</ul>
<ul>
<li>item</li>
<li>item
<ul class="goal" data-ancestorgoalelelqueryselectortargetat1="1" data-ancestorgoalelelqueryselectortargetat2000="1">
<li>item</li>
<li class="target">target</li>
<li>item</li>
</ul>
</li>
<li>item</li>
</ul>
</section>
<h2>Previous Sibling Selector</h2>
<section class="previous">
<ul>
<li data-previouselelnextelementsiblingelnextelementsiblingclasslistcontainstargetat1="0" data-previouselelnextelementsiblingelnextelementsiblingclasslistcontainstargetat2000="0">item</li>
<li class="target">target</li>
<li>item</li>
</ul>
</section>
<h2>First of Selector in Document</h2>
<section class="first">
<p>Lorem ipsum <span data-firstspaneleldocumentqueryselectorfirstspanat1="0" data-firstspaneleldocumentqueryselectorfirstspanat2000="0">dolor</span> sit amet, consectetur <span>adipisicing</span> elit, sed do eiusmod tempor <span>incididunt</span> ut labore et dolore magna aliqua.</p>
</section></body></html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment