-
Notifications
You must be signed in to change notification settings - Fork 24
Document height-based CQ use case #63
Comments
Pinging #60. @keithjgrant, assigning to you for the initial draft. |
Correction: don't use (If the layout is defined using |
I’m having a tough time really nailing this down. Every time I come up with a scenario, it’s clearly contrived, and I can think of a better layout that would make more sense. Here’s kind of what I’ve got, maybe bouncing some ideas around might help... Page layout using flexbox and The flex container has a Contents inside the banner and main are laid out using grid or flex or whatever. The banner's contents are the colored boxes; the main consists of the three gray boxes beneath. Then, assume the contents in the main area become longer. This means it will take up more of the screen height, leaving less for the banner. In this case, we would like the banner to lay out differently, so it requires less space: |
This is my current permutation. My devil’s advocate objection right now is this: Why is the I could force the wrapping flex container to a height of 100vh (rather than a min-height)… but that’s really not a great practice. |
@keithjgrant, I think this is a stellar start. A couple quick questions from me:
|
I’m not entirely convinced height-based CQ’s are necessary, or at least not as necessary as width-based ones. This has been a sort of thought experiment for me to figure out how I would use them, but I’m jumping through hoops to generate a plausible scenario. I’m beginning to suspect I wouldn’t ever use them, personally. |
Now that I said that, I realized I do have a real-world app where I want to constrain the height. https://sidecar.us is built primarily to work on mobile as a PWA. I’ve worked to keep the home screen at 100vh tall. Currently, it can overflow, if content gets too long, but I’m not too happy about it. Maybe I’ll noodle on that as a different starting point. |
I think focusing on a real-world example could be a really great starting point! The way I think of it, we’re trying to demonstrate an existing need here; we don’t have to be responsible for inventing new ones, if that makes sense? Possibly related: I thought @eeeps had a marvelously insightful comment in Slack, about the distinction between features and use cases:
(Only sharing it here if it’s helpful to you. Please disregard if it isn’t!) |
I think what I’m finding when it comes to height is not so much that I want to query the height of the container so much as I want to be able detect overflow and take steps to shrink things down in attempt to prevent it. Would that still fall in the scope of what we’re doing here? |
@keithjgrant Hmm! I’m not sure. My gut read says that, yes, it’s probably out of scope. This feels like a more general property status query, which is highly rad, but mayyyyybe not what we’re after? But—but!—I don’t want to preemptively axe a possibly stellar use case. I’d say keep working at it, if you think it has merit? In other words, if you think there’s a common pattern or problem here that container queries might be able to solve, let’s get it written up! |
Just popping by to say that @keithjgrant it’s super-cool to get to read you thinking concretely though a possible use case and finding out that you didn't really want what you thought you wanted. That's the Use-Cases-first system at work! (; When you say “overflow” – do you mean overflow within a DOM element or overflow of the viewport? If the viewport, that would be an awesome media query! Not a container query though. If you want to be able to query DOM nodes though... hm. If we come up with a general way to query facts about elements (in the same way that media queries let you query all sorts of disprate things about a browsing context), this sounds totes-in-scope to me – with two big caveats:
|
I do think there's a use case for a How about something like this as a use-case for This example isn't very pretty, but it works: <div id=sidebar>
<div class=widget>
<h2>Widget Title</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>
<button>Click Me</button>
</div>
<div class=widget>
<h2>Widget Title</h2>
<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>
<button>Click Me</button>
</div>
</div>
<style>
* {
box-sizing: border-box;
}
#sidebar {
width: 300px;
border: 1px solid;
padding: 1em;
}
.widget {
border: 1px solid;
padding: 1em;
}
.widget + .widget {
margin-top: 1em;
}
button {
display: block;
width: 100%;
font-size: 20pt;
padding: 2em;
}
@element .widget p and (min-height: 300px) {
:self ~ button {
font-size: 14pt;
padding: 1em;
}
}
</style>
<script src=http://elementqueries.com/EQCSS.js></script> And on a related note, about overflow and visibility, I've made a few helper plugins for doing things like this as well if you want to see what they might look like, or how they differ from the element query plugins I've written. Is that element partly or fully visible in the viewport?// Viewport Visibility
function viewport(selector, option, rule) {
let styles = ''
let count = 0
const features = {
partly: (tag, rule) => {
const top = tag.offsetTop - innerHeight
const bottom = top + tag.offsetHeight
return (scrollY < tag.offsetTop + tag.offsetHeight)
&& (top < scrollY)
&& (bottom < scrollY + tag.offsetHeight)
? rule
: ''
},
fully: (tag, rule) => {
const top = tag.offsetTop - innerHeight
const bottom = top + tag.offsetHeight
return (scrollY < tag.offsetTop)
&& (top < scrollY)
&& (bottom < scrollY)
? rule
: ''
}
}
document.querySelectorAll(selector).forEach(tag => {
const attr = selector.replace(/\W/g, '')
const evaluated = features[option](tag, rule)
tag.setAttribute(`data-viewport-${attr}`, count)
styles += `[data-viewport-${attr}="${count}"] { ${evaluated} }\n`
count++
})
return styles
} Demo: http://staticresource.com/viewport.html Is that element in sight or out of sight vertically within an overflowed parent?// Visible Vertically Within Parent
function inSight(selector, rule) {
let styles = ''
let count = 0
document.querySelectorAll(selector).forEach(tag => {
const attr = selector.replace(/\W/g, '')
let underTop = tag.offsetTop + tag.offsetHeight >= tag.parentElement.scrollTop
let aboveBottom = tag.offsetTop < tag.parentElement.scrollTop + tag.parentElement.offsetHeight
if (underTop && aboveBottom) {
styles += `[data-insight-${attr}="${count}"] { ${rule} }\n`
tag.setAttribute(`data-insight-${attr}`, count)
count++
} else {
tag.setAttribute(`data-insight-${attr}`, '')
}
})
return styles
} // Out of Sight Vertically in Parent
function outOfSight(selector, rule) {
let styles = ''
let count = 0
document.querySelectorAll(selector).forEach(tag => {
const attr = selector.replace(/\W/g, '')
let aboveTop = tag.offsetTop + tag.offsetHeight < tag.parentElement.scrollTop
let underBottom = tag.offsetTop > tag.parentElement.scrollTop + tag.parentElement.offsetHeight
if (aboveTop || underBottom) {
styles += `[data-outofsight-${attr}="${count}"] { ${rule} }\n`
tag.setAttribute(`data-outofsight-${attr}`, count)
count++
} else {
tag.setAttribute(`data-outofsight-${attr}`, '')
}
})
return styles
} Is that element horizontally overflowed on the left and/or right side?// Horizontal Overflow
function overflow(selector, option, stylesheet) {
let styles = ''
let count = 0
const features = {
left: tag => 0 < tag.scrollLeft,
right: tag => (tag.scrollLeft + tag.offsetWidth) !== tag.scrollWidth
}
Array.from(document.querySelectorAll(selector)).forEach(tag => {
const attr = (selector+option).replace(/\W/g, '')
if (features[option](tag)) {
styles += stylesheet.replace(/:self|\$this/g, `[data-overflow-${attr}="${count}"]`)
tag.setAttribute(`data-overflow-${attr}`, count)
count++
} else {
tag.setAttribute(`data-overflow-${attr}`, '')
}
})
return styles
} |
@keithjgrant and @tomhodgins — I think both of your examples focus on querying boxes whose height is being determined by their contents. In other words, they are intrinsically sized. The container queries use cases that seem to come up when people talk about “width” queries are all about elements whose width is entirely dependent on their context. Which is to say, they are extrinsically-sized. You can, of course, have an element whose “height” is extrinsically-sized. Think, for instance, of a height-constrained, left-to-right-scrolling image carousel. That height might be fluid and dependent on context, just as the widths of components that we normally talk about are - in this case, I think “height” queries make all the sense in the world. But the examples in this thread are of the other thing: querying elements based on their intrinsic size. Which seems like a whole other kettle of fish... Container queries help break circularity w/r/t extrinsically-sized boxes because they limit the ways in which a boxe's contents (children) can affect the thing-queried (container size). When dealing with intrincally-sized boxes, you’d... almost need the opposite constraint? You could only query children and apply styles on containers!? ...aaand it looks like once again, I have strayed far afield from use cases, and jumped ahead to the how-could-this-work talk. Doh. Back to buisness... @keithjgrant , it seems as if you explored the use cases for intrinsic-size queries a bit, and found what you actually wanted was an is-this-overflowing-query? @tomhodgins – that button example looks like it could be the start of something promising. Have you actually used this sort of query anywhere, or wanted to, or seen it used? |
@eeeps beat me to my main point, but here's my 2p: In most scenarios, and by popular convention, we choose width as the limiting factor, opting to allow vertical scrolling if content > screen height. However, it's perfectly possible, though unconventional to choose height as the limiting factor, opting to allow horizontal scrolling if content > screen width. Example: Vasilis presents a horizontal layout in his talks (18:48) and a live example I've also mocked up a similar kind of thing. Where there's enough height, I want 2 rows, where there isn't, only 1. No doubt this example could be greatly improved if need be. |
@eeeps that sounds like a fair summary. Technically, I guess the overflowing query is a little bit both intrinsic and extrensic: does the intrinsic size exceed some extrinsic constraint. I basically want to short-circuit any circularity. If element X overflows, I want to take mitigating steps to prevent it. I would most likely shrink the content, hopefully making the overflow query evaluate to false; but of course I wouldn’t want it to then revert back to the initial layout. I don’t want it to evaluate circularly. In this case, if there’s any circularity, I want it to be disregarded and for my query to take effect. I’m not sure whether that is the same behaviour we want in a width-based query or not. |
An interesting, possibly-related use case, re: intrinsic size queries: marcj/css-element-queries#223 (comment) @7iomka wanted to make the intrinsic size of some text depend on... the text's intrinsic size. Which introduced an infinite loop. I get the use case (shrink the text rather than have it linebreak); dunno if container queries are the hammer for that nail. |
Oh, hm! So personally, text sizing and weight are two of the biggest things I’d use container queries for. (Just for example, if an image+title pattern appears in both, say, a main content well and in a sidebar, I’d expect the title to be more prominent in the former.) That said, I’d think about that as something under the domain of container queries—here’s the space available for this module, let’s adjust the internals accordingly—rather than querying the property itself. If that makes sense? [sips coffee] |
Off topic? |
@beep makes total sense. And yep! I'm not trying to say that adjusting text styles is problematic. Rather, I'm just (weirdly?) excited to find a real-life example of someone trying to do something related to @keithjgrant’s use case – adjusting the style of some content so that it doesn’t overflow (well, line break within) a container. Can you use a tool like container queries to mitigate overflows/line breaks? I don't know yet! But I was interested to see somebody trying and failing in real life. As you suggest, as long as the query target can't be influenced by the style target, there's no problem. @andykirk, as I see it, the thread’s a place for @keithjgrant to hash out a use case. In my head, that use case started as “height-based queries” and has developed into something along the lines of overflow queries or intrinsic size queries. But I may very well be wandering off on my own, there. At the very least, given your + @beep’s responses, I should have been more explicit about how I thought the linked example tied back to Keith’s use-case-in-progress. |
@eeeps don’t mind me. I was just pointing it out in case... |
Re: detecting overflow – I can't wait to see the video, but from what I can gather from just the slides, the IntersectionObserver section of Greg Whitworth’s CSS Day talk container queries, here, is surely relevant: https://noti.st/gregwhitworth/UDul7E/over-the-moon-for-container-queries Stepping back – @keithjgrant , given your explorations and all of the discussion they spurred, where are you at with all of this? Seems like we forked off into a few different sub-discussions about how various concepts related to your original exploration could work... but may not really any closer to a use case. Is there enough here for you (or anyone else!) to turn into a PR? If not I’ll go ahead and close the issue. |
Following this discussion, document a use case with a height-based CQ. A banner with min-height specified in
vh
units, with three child elements.If the banner element is beneath a certain height, the three elements should appear inline. If it is above a certain height, they can stack various ways.
The text was updated successfully, but these errors were encountered: