Skip to content

Instantly share code, notes, and snippets.

@tomhodgins
Last active January 22, 2020 05:15
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/eb3a0992d769462932c47ba85b56d156 to your computer and use it in GitHub Desktop.
Save tomhodgins/eb3a0992d769462932c47ba85b56d156 to your computer and use it in GitHub Desktop.

Easy Element Query Workflow for 2020

  1. Your HTML in index.html
  2. Your CSS in input.css
  3. Run CSS through process-css-demo via build.sh (or node)
  4. Serve JS-supported styles
  5. ???
  6. Profit!

Notes:

  • For this demo I added a scroll listener some elements that sends a reprocess event to window when you scroll
#!/bin/sh
echo "Processing style.css"
# Use process-css-demo from npm without installing via npx
npx process-css-demo input.css -b > output.js
echo "Processing complete!"
<!DOCTYPE html>
<meta charset=utf-8>
<meta name=viewport content="width=device-width, initial-scale=1">
<title>deqaf demo</title>
<script defer src=output.js></script>
<script type=module>
document.querySelectorAll('[class*="-scroll-"]').forEach(tag =>
tag.addEventListener('scroll', event =>
window.dispatchEvent(new CustomEvent('reprocess'))
)
)
</script>
<h1>Element Query Test</h1>
<h2>Width Queries</h2>
<h3 id=min-width>min-width</h3>
<div class=minwidth data-drag=horizontal>class="minwidth"</div>
<h3 id=max-with>max-width</h3>
<div class=maxwidth data-drag=horizontal>class="maxwidth"</div>
<h2>Height Queries</h2>
<h3 id=min-height>min-height</h3>
<div class=minheight data-drag=vertical>class="minheight"</div>
<h3 id=max-height>max-height</h3>
<div class=maxheight data-drag=vertical>class="maxheight"</div>
<h2>Quantity Queries</h2>
<h3 id=min-characters>min-characters on block elements</h3>
<p>(Use keyboard)</p>
<div class=mincharacters contenteditable>class="mincharacters"</div>
<h3>min-characters on form inputs</h3>
<p>(Use keyboard)</p>
<input type=text class=mincharacters-input value='class="mincharacters-input"'>
<textarea class=mincharacters-textarea>class="mincharacters-textarea"</textarea>
<h3 id=characters>characters on block elements</h3>
<p>(Use keyboard)</p>
<div class=characters contenteditable>class="characters"</div>
<h3>characters on form inputs</h3>
<p>(Use keyboard)</p>
<input type=text class=characters-input value='class="characters-input"'>
<textarea class=characters-textarea>class="characters-textarea"</textarea>
<h3 id=max-characters>max-characters on block elements</h3>
<p>(Use keyboard)</p>
<div class=maxcharacters contenteditable>class="maxcharacters"</div>
<h3>max-characters on form inputs</h3>
<p>(Use keyboard)</p>
<input type=text class=maxcharacters-input value='class="maxcharacters-input"'>
<textarea class=maxcharacters-textarea>class="maxcharacters-textarea"</textarea>
<h3 id=min-children>min-children</h3>
<button data-button=semiflat onclick="var img=document.createElement('img');img.src='https://staticresource.s3.amazonaws.com/user.png';document.querySelector('.minchildren').appendChild(img)">Add Child</button>
<div class=minchildren>
<img src=https://staticresource.s3.amazonaws.com/user.png style=width:50px>
</div>
<h3 id=children>children</h3>
<button data-button=semiflat onclick="var img=document.createElement('img');img.src='https://staticresource.s3.amazonaws.com/user.png';document.querySelector('.children').appendChild(img)">Add Child</button>
<div class=children>
<img src=https://staticresource.s3.amazonaws.com/user.png style=width:50px>
</div>
<h3 id=max-children>max-children</h3>
<button data-button=semiflat onclick="var img=document.createElement('img');img.src='https://staticresource.s3.amazonaws.com/user.png';document.querySelector('.maxchildren').appendChild(img)">Add Child</button>
<div class=maxchildren>
<img src=https://staticresource.s3.amazonaws.com/user.png style=width:50px>
</div>
<h2>Scroll queries</h2>
<h3 id=min-scroll-y>min-scroll-y</h3>
<div class=min-scroll-y>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</div>
<h3 id=max-scroll-y>max-scroll-y</h3>
<div class=max-scroll-y>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</div>
<h3 id=min-scroll-x>min-scroll-x</h3>
<div class=min-scroll-x>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</div>
<h3 id=max-scroll-x>max-scroll-x</h3>
<div class=max-scroll-x>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</div>
<h2>Aspect queries</h2>
<h3 id=orientation>orientation</h3>
<div class=orientation style="width: 100px; height: 100px;">100 &times; 100</div>
<div class=orientation style="width: 100px; height: 200px;">100 &times; 200</div>
<div class=orientation style="width: 200px; height: 100px;">200 &times; 100</div>
<h3 id=min-aspect-ratio>min-aspect-ratio</h3>
<div class=minaspectratio data-drag=both>class="minaspectratio"</div>
<h3 id=max-aspect-ratio>max-aspect-ratio</h3>
<div class=maxaspectratio data-drag=both>class="maxaspectratio"</div>
body style {
display: block;
width: 100%;
padding: 1em;
margin: 1em 0 2em 0;
border-radius: 3px;
font-size: 12pt;
font-family: monospace;
word-break: break-word;
white-space: pre-wrap;
font-kerning: auto;
color: rgba(0, 0, 0, .7);
background: transparent;
border: 1px solid rgba(0, 0, 0, .3);
}
* {
box-sizing: border-box;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-kerning: auto;
}
body {
margin: 1em;
font-family: sans-serif;
}
[data-button] {
display: block;
margin: 1em 0;
}
div {
display: inline-block;
border-radius: .2em;
padding: 1.5em;
color: #555;
font-size: 12pt;
line-height: 1.4;
background: #eee;
border: 4px solid #ccc;
}
input,
textarea {
display: block;
min-width: 250px;
border-radius: .2em;
margin: 1em;
padding: .5em;
color: #555;
font-size: 12pt;
background: white;
border: 4px solid #ccc;
}
section {
height: 300px;
display: inline-block;
border: 4px dotted lightskyblue;
padding: 1em;
}
img {
max-width: 50px;
box-shadow: rgba(0, 0, 0, .1) 0 .2em .5em;
}
img + img {
margin-left: 1em;
}
p {
font-size: 10pt;
color: #555;
}
[class*=-scroll-x] {
overflow-x: scroll;
}
[class*=-scroll-x] p {
width: 200%;
}
[class*=-scroll-y] {
height: 100px;
overflow-y: scroll;
}
[data-drag] {
overflow: auto;
}
[data-drag=horizontal] {
resize: horizontal;
}
[data-drag=vertical] {
resize: vertical;
}
[data-drag=both] {
resize: both;
}
/* Min-width */
@--element .minwidth and (min-width: 300) {
:--self {
border-color: limegreen;
background: greenyellow;
}
}
/* Max-width */
@--element .maxwidth and (max-width: 300) {
:--self {
border-color: limegreen;
background: greenyellow;
}
}
/* Min-height */
@--element .minheight and (min-height: 200) {
:--self {
border-color: limegreen;
background: greenyellow;
}
}
/* Max-height */
@--element .maxheight and (max-height: 200) {
:--self {
border-color: limegreen;
background: greenyellow;
}
}
/* Min-characters on block elements */
@--element .mincharacters and (min-characters: 35) {
:--self {
border-color: limegreen;
background: greenyellow;
}
}
/* Min-characters on input */
@--element .mincharacters-input and (min-characters: 35) {
:--self {
border-color: limegreen;
background: greenyellow;
}
}
/* Min-characters on textarea */
@--element .mincharacters-textarea and (min-characters: 35) {
:--self {
border-color: limegreen;
background: greenyellow;
}
}
/* Characters on block elements */
@--element .characters and (characters: 5) {
:--self {
border-color: limegreen;
background: greenyellow;
}
}
/* Characters on input */
@--element .characters-input and (characters: 5) {
:--self {
border-color: limegreen;
background: greenyellow;
}
}
/* Characters on textarea */
@--element .characters-textarea and (characters: 5) {
:--self {
border-color: limegreen;
background: greenyellow;
}
}
/* Max-characters */
@--element .maxcharacters and (max-characters: 35) {
:--self {
border-color: limegreen;
background: greenyellow;
}
}
/* Max-characters on input */
@--element .maxcharacters-input and (max-characters: 35) {
:--self {
border-color: limegreen;
background: greenyellow;
}
}
/* Max-characters on textarea */
@--element .maxcharacters-textarea and (max-characters: 35) {
:--self {
border-color: limegreen;
background: greenyellow;
}
}
/* Min-children */
@--element .minchildren and (min-children: 5) {
:--self {
border-color: limegreen;
background: greenyellow;
}
}
/* Children */
@--element .children and (children: 5) {
:--self {
border-color: limegreen;
background: greenyellow;
}
}
/* Max-children */
@--element .maxchildren and (max-children: 5) {
:--self {
border-color: limegreen;
background: greenyellow;
}
}
/* Min-scroll-y */
@--element .min-scroll-y and (min-scroll-y: 50) {
:--self {
border-color: limegreen;
background: greenyellow;
}
}
/* Max-scroll-y */
@--element .max-scroll-y and (max-scroll-y: 50) {
:--self {
border-color: limegreen;
background: greenyellow;
}
}
/* Min-scroll-x */
@--element .min-scroll-x and (min-scroll-x: 50) {
:--self {
border-color: limegreen;
background: greenyellow;
}
}
/* Max-scroll-x */
@--element .max-scroll-x and (max-scroll-x: 50) {
:--self {
border-color: limegreen;
background: greenyellow;
}
}
/* Square Orientation */
@--element .orientation and (orientation: 'square') {
:--self {
border-color: darkorchid;
background: orchid;
}
}
/* Portrait Orientation */
@--element .orientation and (orientation: 'portrait') {
:--self {
border-color: teal;
background: darkturquoise;
}
}
/* Landscape Orientation */
@--element .orientation and (orientation: 'landscape') {
:--self {
border-color: limegreen;
background: greenyellow;
}
}
/* Min-aspect ratio */
@--element .minaspectratio and (min-aspect-ratio: 1.777) {
:--self {
border-color: limegreen;
background: greenyellow;
}
}
/* Max-aspect-ratio */
@--element .maxaspectratio and (max-aspect-ratio: 1.777) {
:--self {
border-color: limegreen;
background: greenyellow;
}
}
((jsincss, elementQueryAtRule) => {
document.documentElement.appendChild(
document.createElement('style')
).textContent = `body style {
display: block;
width: 100%;
padding: 1em;
margin: 1em 0 2em 0;
border-radius: 3px;
font-size: 12pt;
font-family: monospace;
word-break: break-word;
white-space: pre-wrap;
font-kerning: auto;
color: rgba(0, 0, 0, 0.7);
background: transparent;
border: 1px solid rgba(0, 0, 0, 0.3);
}
* {
box-sizing: border-box;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-kerning: auto;
}
body {
margin: 1em;
font-family: sans-serif;
}
[data-button] {
display: block;
margin: 1em 0;
}
div {
display: inline-block;
border-radius: 0.2em;
padding: 1.5em;
color: #555;
font-size: 12pt;
line-height: 1.4;
background: #eee;
border: 4px solid #ccc;
}
input,
textarea {
display: block;
min-width: 250px;
border-radius: 0.2em;
margin: 1em;
padding: 0.5em;
color: #555;
font-size: 12pt;
background: white;
border: 4px solid #ccc;
}
section {
height: 300px;
display: inline-block;
border: 4px dotted lightskyblue;
padding: 1em;
}
img {
max-width: 50px;
box-shadow: rgba(0, 0, 0, 0.1) 0 0.2em 0.5em;
}
img + img {
margin-left: 1em;
}
p {
font-size: 10pt;
color: #555;
}
[class*='-scroll-x'] {
overflow-x: scroll;
}
[class*='-scroll-x'] p {
width: 200%;
}
[class*='-scroll-y'] {
height: 100px;
overflow-y: scroll;
}
[data-drag] {
overflow: auto;
}
[data-drag='horizontal'] {
resize: horizontal;
}
[data-drag='vertical'] {
resize: vertical;
}
[data-drag='both'] {
resize: both;
}
`;
jsincss(event =>
[
elementQueryAtRule(
'.minwidth',
{ minWidth: 300 },
`[--self] { border-color: limegreen;background: greenyellow }`
),
elementQueryAtRule(
'.maxwidth',
{ maxWidth: 300 },
`[--self] { border-color: limegreen;background: greenyellow }`
),
elementQueryAtRule(
'.minheight',
{ minHeight: 200 },
`[--self] { border-color: limegreen;background: greenyellow }`
),
elementQueryAtRule(
'.maxheight',
{ maxHeight: 200 },
`[--self] { border-color: limegreen;background: greenyellow }`
),
elementQueryAtRule(
'.mincharacters',
{ minCharacters: 35 },
`[--self] { border-color: limegreen;background: greenyellow }`
),
elementQueryAtRule(
'.mincharacters-input',
{ minCharacters: 35 },
`[--self] { border-color: limegreen;background: greenyellow }`
),
elementQueryAtRule(
'.mincharacters-textarea',
{ minCharacters: 35 },
`[--self] { border-color: limegreen;background: greenyellow }`
),
elementQueryAtRule(
'.characters',
{ characters: 5 },
`[--self] { border-color: limegreen;background: greenyellow }`
),
elementQueryAtRule(
'.characters-input',
{ characters: 5 },
`[--self] { border-color: limegreen;background: greenyellow }`
),
elementQueryAtRule(
'.characters-textarea',
{ characters: 5 },
`[--self] { border-color: limegreen;background: greenyellow }`
),
elementQueryAtRule(
'.maxcharacters',
{ maxCharacters: 35 },
`[--self] { border-color: limegreen;background: greenyellow }`
),
elementQueryAtRule(
'.maxcharacters-input',
{ maxCharacters: 35 },
`[--self] { border-color: limegreen;background: greenyellow }`
),
elementQueryAtRule(
'.maxcharacters-textarea',
{ maxCharacters: 35 },
`[--self] { border-color: limegreen;background: greenyellow }`
),
elementQueryAtRule(
'.minchildren',
{ minChildren: 5 },
`[--self] { border-color: limegreen;background: greenyellow }`
),
elementQueryAtRule(
'.children',
{ children: 5 },
`[--self] { border-color: limegreen;background: greenyellow }`
),
elementQueryAtRule(
'.maxchildren',
{ maxChildren: 5 },
`[--self] { border-color: limegreen;background: greenyellow }`
),
elementQueryAtRule(
'.min-scroll-y',
{ minScrollY: 50 },
`[--self] { border-color: limegreen;background: greenyellow }`
),
elementQueryAtRule(
'.max-scroll-y',
{ maxScrollY: 50 },
`[--self] { border-color: limegreen;background: greenyellow }`
),
elementQueryAtRule(
'.min-scroll-x',
{ minScrollX: 50 },
`[--self] { border-color: limegreen;background: greenyellow }`
),
elementQueryAtRule(
'.max-scroll-x',
{ maxScrollX: 50 },
`[--self] { border-color: limegreen;background: greenyellow }`
),
elementQueryAtRule(
'.orientation',
{ orientation: 'square' },
`[--self] { border-color: darkorchid;background: orchid }`
),
elementQueryAtRule(
'.orientation',
{ orientation: 'portrait' },
`[--self] { border-color: teal;background: darkturquoise }`
),
elementQueryAtRule(
'.orientation',
{ orientation: 'landscape' },
`[--self] { border-color: limegreen;background: greenyellow }`
),
elementQueryAtRule(
'.minaspectratio',
{ minAspectRatio: 1.777 },
`[--self] { border-color: limegreen;background: greenyellow }`
),
elementQueryAtRule(
'.maxaspectratio',
{ maxAspectRatio: 1.777 },
`[--self] { border-color: limegreen;background: greenyellow }`
),
].join('\n')
);
window.dispatchEvent(new CustomEvent('reprocess'));
})(
function(
stylesheet = event => '',
selector = window,
events = ['load', 'resize', 'input', 'click', 'reprocess']
) {
function registerEvent(target, event, id, stylesheet) {
return target.addEventListener(event, e =>
populateStylesheet(id, stylesheet, e)
);
}
function populateStylesheet(id, stylesheet, e) {
let tag = document.querySelector(`#jsincss-${id}`);
if (!tag) {
tag = document.createElement('style');
tag.id = `jsincss-${id}`;
document.head.appendChild(tag);
}
const currentStyles = tag.textContent;
const generatedStyles = stylesheet(e);
if (!currentStyles || generatedStyles !== currentStyles) {
return (tag.textContent = generatedStyles);
}
}
let id = Date.now() + Math.floor(Math.random() * 100);
if (selector === window) {
return events.forEach(event =>
registerEvent(window, event, id, stylesheet)
);
} else {
return document
.querySelectorAll(selector)
.forEach(tag =>
events.forEach(event => registerEvent(tag, event, id, stylesheet))
);
}
},
(selector, conditions, stylesheet) => {
const attr = (
selector +
Object.keys(conditions) +
Object.values(conditions)
).replace(/\W/g, '');
const features = {
minWidth: (el, number) => number <= el.offsetWidth,
maxWidth: (el, number) => number >= el.offsetWidth,
minHeight: (el, number) => number <= el.offsetHeight,
maxHeight: (el, number) => number >= el.offsetHeight,
minChildren: (el, number) => number <= el.children.length,
children: (el, number) => number === el.children.length,
maxChildren: (el, number) => number >= el.children.length,
minCharacters: (el, number) =>
number <= (el.value ? el.value.length : el.textContent.length),
characters: (el, number) =>
number === (el.value ? el.value.length : el.textContent.length),
maxCharacters: (el, number) =>
number >= (el.value ? el.value.length : el.textContent.length),
minScrollX: (el, number) => number <= el.scrollLeft,
maxScrollX: (el, number) => number >= el.scrollLeft,
minScrollY: (el, number) => number <= el.scrollTop,
maxScrollY: (el, number) => number >= el.scrollTop,
minAspectRatio: (el, number) =>
number <= el.offsetWidth / el.offsetHeight,
maxAspectRatio: (el, number) =>
number >= el.offsetWidth / el.offsetHeight,
orientation: (el, string) =>
({
portrait: el => el.offsetWidth < el.offsetHeight,
square: el => el.offsetWidth === el.offsetHeight,
landscape: el => el.offsetHeight < el.offsetWidth,
}[string](el)),
};
const result = Array.from(document.querySelectorAll(selector)).reduce(
(output, tag, count) => {
if (
Object.entries(conditions).every(test =>
features[test[0]](tag, test[1])
)
) {
output.add.push({ tag: tag, count: count });
output.styles.push(
stylesheet.replace(
/:self|\$this|\[--self\]/g,
`[data-element-${attr}="${count}"]`
)
);
} else {
output.remove.push(tag);
}
return output;
},
{ add: [], remove: [], styles: [] }
);
result.add.forEach(tag =>
tag.tag.setAttribute(`data-element-${attr}`, tag.count)
);
result.remove.forEach(tag => tag.setAttribute(`data-element-${attr}`, ''));
return result.styles.join('\n');
}
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment