WICG / cq-usecases

Use cases and requirements for standardizing element queries.
Other
184 stars 24 forks source link

Need a section outlining limitations of current techniques #53

Closed eeeps closed 6 years ago

eeeps commented 6 years ago

Like this, but for Container Queries.

@andykirk, who wrote an excellent article outlining a bunch of use cases and current-workaround-techniques, has agreed to give this a go, soonish (I’ll assign him as soon as he accepts the collaborator invite).

ZeeCoder commented 6 years ago

That's great! I'll explore this area myself a little more as I prepare for my talk, so I'll leave here ideas for @andykirk .

andykirk commented 6 years ago

Thanks both.

andykirk commented 6 years ago

Hi, Apologies for the delay in this. I hope to have a draft in the next few days. Ok to post it here for comment?

ZeeCoder commented 6 years ago

Yeah, I'll get a notification then

marcoscaceres commented 6 years ago

Once we have some initial text, we should quickly translate it to "bikeshed" and start doing detailed review as a Pull Request. BikeShed's syntax is a bit of a burden of entry, so the quicker one of the folks editing the translate the incoming text, the better.

tomhodgins commented 6 years ago

I can get the text we come up with into a bikeshed document, but I might need a little help with Github PR stuff as we get going :D

marcoscaceres commented 6 years ago

Sure, no problem. Happy to provide help with the PR stuff. Key is that we have a clean commit history and make sure we track who made the contributions.

When sending the PRs, particularly for ones like this one, we need to make sure that the author of the text is captured correctly, so:

git commit --author="Andy Kirk <andys_real_email_here@somwhere.com>"
tomhodgins commented 6 years ago

@andykirk When you are ready to submit text to be added, it seems I'll need some information for proper authorship attribution ➸ how would you like me to reference you?

andykirk commented 6 years ago

Thanks Tommy.

Andy Kirk andy@andykirk.net

andykirk commented 6 years ago

Hi, Here's a start. Apologies for the delay - I've struggled with this somewhat (both with time and subject). I've taken a few liberties with the definition - it's more difficult working outside of the context of the full document - but anything here can be changed, of course. I hope this is somewhere along the right lines.


Limitations of current techniques

There is currently no native CSS mechanism available to developers that achieves the primary function of container queries, which is to employ the full capabilities of CSS to a specific element tree based on the state and properties of their container. Therefore developers must look to workarounds to achieve their goals. These workarounds and their limitations are outlined here:

The use of Media Queries can only affect CSS changes based on the state and properties of the viewport. The viewport is not a good indicator of the state and properties of a particular container within the viewport.

The use of CSS layout methods such as Flexbox and Grid, alongside CSS-based workarounds (such as the Fab Four technique) cannot employ the full capabilities of CSS on an element tree.

The use of iframes produces the closest effect to what Container Queries is intended to achieve, but their use has two significant drawbacks:

  1. Without the use of JavaScript, iframes require that the contents of the iframe are stored in a separate HTML document rather than being part of the current document. This necessitates a new document composition paradigm that's very different from the methods currently employed by developers.

  2. The contents of an iframe do not natively affect the dimensions of the iframe itself. The contents of a container that is the subject of a Container Query are still expected to be able to affect the layout of its parents in the opposite dimension of the query. For example, in the case of a Container Query that is based on a containers width, it is still expected that the container's contents affect the height of a container, subject to any overflow rules.

JavaScript-based solutions (for example EQCSS) should not be considered an adequate replacement for a native CSS solution for all the same reasons any other layout- or appearance-based declarations are the domain of CSS, not JavaScript, and the usual caveats of JavaScript availability and failure still apply.

jpamental commented 6 years ago

This is an excellent overview @andykirk !

andykirk commented 6 years ago

Thanks @jpamental

beep commented 6 years ago

@andykirk This is excellent. Thanks so much for writing this up!

Out of curiosity, have you considered mentioning any performance drawbacks of JS-driven solutions? (I know @eeeps has done a little research into this.) I’m only asking because @marcoscaceres mentioned during the kickoff call that issues impacting end users are really compelling to implementers, and speed/performance seems like it could be a good one to hone in on.

What do you think?

andykirk commented 6 years ago

Thanks @beep - no, actually I hadn't. It's not an area I'm strong in, tbh. It's a good shout though - perhaps someone with more knowledge of that are than myself can add something along those lines?

ausi commented 6 years ago

@eeeps and I did some performance research on my container query script in ausi/cq-prolyfill#39. I can try to write something (short) up that describes the minimum performance costs of a javascript solution.

beep commented 6 years ago

@ausi Marvelous, thank you! Adding you as a co-assignee.

ausi commented 6 years ago

Minimum Performance Cost of a Container Query Solution via JavaScript

On first render:

After every subsequent render that affects the matching state of at least one container query:


Or shorter: The minimum performance cost of a JavaScript solution is about 6KB more render blocking JavaScript and a reflow after every significant layout.


According to my research these should be the absolute minimum costs of any JavaScript solution (most scripts cost more performance-wise). The KB numbers are taken from the most popular scripts.

Does this help so far, or should it me more detailed?

jpamental commented 6 years ago

I think that including @ausi 's addition is good, but I think that the stronger point is that layout is the domain of CSS, not JS (which is well known, and by design). So adding the 'and JS would be bad for performance too' should be a secondary reinforcing case.

ausi commented 6 years ago

I fully agree.
Layout should not depend on JavaScript. This should be the main concern.

tomhodgins commented 6 years ago

I'm curious about these numbers:

  • About 3KB or more additional network traffic.
  • About 6KB or more (minified) JavaScript code to parse.

Is that 3kb for the gzipped plugin code? Are stylesheets included in that? And for 6kb are we saying the minimum size of a plugin for this is 6kb minified (but uncompressed)?

I just tossed my most recent stylesheet loader and element query plugin into Closure Compiler and minified it and I get <2kb uncompressed, 764 bytes gzipped, and this wasn't written with the intention of being small. Should these numbers be adjusted downward, or better explain what they cover in their estimate?

jpamental commented 6 years ago

You make a good point @tomhodgins - I think that if we are going to include a performance consideration it's probably worth not talking specific numbers, but rather focus on the fact that it does require additional request, download, and processing resources as @ausi laid out above. Best to not get specific where not needed.

ausi commented 6 years ago

Great point.

I'm curious about these numbers

They are an average size of some general purpose container query scripts. There is no real minimum for the size because we didn’t specify the use cases yet and solutions can be very different.

it's probably worth not talking specific numbers, but rather focus on the fact that it does require additional request, download, and processing resources

I think you are right, we should probably remove these numbers. My intention was to note that the required scripts are huge in many cases ☺️.

How about this:

beep commented 6 years ago

I think that if we are going to include a performance consideration it's probably worth not talking specific numbers, but rather focus on the fact that it does require additional request, download, and processing resources as @ausi laid out above. Best to not get specific where not needed.

Strong agree!

@ausi, I love your condensed list. Just me, but I think that’s the perfect level of detail for now.

marcoscaceres commented 6 years ago

What's the impact per element to which the JS is then applied (and what's a typical number of element to which CQ would be applied)? Does the browser then need to recalculate styles once or for each?

tomhodgins commented 6 years ago

This is where the separation between ' virtual stylesheets' and 'events' makes a difference.

In some plugins, all element queries are treated as a separate stylesheet, and all stylesheets are reprocessed upon each event (commonly load, resize, input, and click on the window object) In this instance, all styles get refreshed and trigger repaints any time any event that triggers a reprocess is fired. EQCSS works like this.

Other stylesheet loaders register specific queries to events on specific elements in the document (either through browser events, or observers like Resize Observer or Mutation Observer). In this case, only those stylesheets tied to specific events on specific elements in the document would be repopulated. ReproCSS is like this.

Lastly, it's possible to load event-driven virtual stylesheets on global events, or element-specific events, but only to repopulate the stylesheets if they are different than the current styles, which also saves repaints. My latest jsincss plugin works like this, so it should be a little better than one that updates that the same styles verbatim just because an event was triggered.

As for the number of elements affected by each element query - often it's one (the same being queried), sometimes it's a handful (the element plus some children), but rarely is it more than 5 different selectors in one query.

EDIT: ^ those numbers are for selectors, not # of elements matching those selectors in the document. Often 1 selector matches 1 element in the document, but it can be multiple. That's why 'style scoping' or 'selector scoping' is important, so you don't have to use ID's or unique class names to target a matching element :D

ausi commented 6 years ago

What's the impact per element to which the JS is then applied?

An optimized CQ script should not have a significant impact per element. And for determining the minimum performance cost we should assume an optimal JS implementation I think.

(and what's a typical number of element to which CQ would be applied)

This can be anything from one single element up to thousands of elements.

Does the browser then need to recalculate styles once or for each?

This also depends on the actual JS implementation. But in the optimal case one recalc/reflow should be enough (even for thousands of elements). More recalcs/reflows might be needed if the CQ elements are nested, but this strongly depends on the actual use case.

This is where the separation between ' virtual stylesheets' and 'events' makes a difference.

Many CQ scripts don’t use “virtual stylesheets” at all, they just switch classes on and off (or custom attributes). In the case of “virtual stylesheets” CSS parsing would have to be added to the performance cost. But for the minimum cost this is not relevant I think.

tomhodgins commented 6 years ago

Iframes as Mini-Viewports

Iframes allow you to 'modularize' some HTML by embedding it in an HTML document as another HTML document. This lets you use media queries for 'modular' styles in a way similar to writing container queries.

There is at least one plugin that uses iframes to contain self-responsive 'modules' as part of a larger site layout.

Pros

Cons

Element Queries are not Syntactic Sugar for Media Queries

The most-used feature of media queries is the ability to set width-based breakpoints based on the browser's viewport. Most container queries are also based on an elements width. In non-dynamic layouts, where the width of 'modules' in the layout ultimately end up tied (even indirectly) to the viewport's width, it may be possible to predict or pre-render container queries and express the same styles as media queries.

There is at least one plugin that can convert container queries to media queries.

Pros

Cons

This is from the element query test file for Qompile, where a comment explains what kinds of element querying functionality (beyond element width) this feature might be suitable for: https://github.com/tomhodgins/qompile/blob/master/test/src/element.jic#L3&L18

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

Note: for an extreme example of the impracticality of this technique for 'lossless' conversion, consider that this HTML:

<div>Hello</div>

And this stylesheet:

${containerQuery('div', el => el.offsetWidth <= 500, `
 :self {
   background: lime;
 }
`)}

When rendered in a 'lossless' way at every width between 0px wide and 1000px wide, turned into 66kb of rendered HTML & CSS: http://staticresource.com/compiled-demo.html

Note: For normal use-cases of this technique and a few examples of how the 'lossy' conversion from container queries to media queries might work, check out the Qompile examples: https://github.com/tomhodgins/qompile#examples

marcoscaceres commented 6 years ago

This is starting to take shape, so it would be good to start moving some of the above into a couple of pull requests (otherwise, we risk this becoming a mega thread).

andykirk commented 6 years ago

Hi, Just my opinion, but what @tomhodgins wrote above, though good, is quite verbose and to me it doesn’t look like it actually adds much in the way of new information to what I originally wrote. I’m not suggesting that what I wrote should be used as-is, but I based the length and level of detail on the responsive images equivalent that @eeeps linked to in the first post.

It would seem to me that we should be as concise as possible in order to make reading the doc as painless as as possible, and thus improve the chances of it being read and understood.

Just my 2p.

marcoscaceres commented 6 years ago

Let's find a balance between the two. @andykirk let's use yours as the base of the pull request, and then @tomhodgins et. al can layer any additional information on top, if necessary... we can then chop chop chop words as needed.  

beep commented 6 years ago

Sounds great to me, @marcoscaceres.

@andykirk (and/or @ausi), feel free to open a PR to tackle this! We can continue the discussion there.

andykirk commented 6 years ago

Great, happy to. I’ll think add @ausi’s JS parsing and nework bits to the JS section.

Also, can I clarify; am I meant to be opening the PR on the bikeshed file? Sorry if that’s a dumb question. I haven’t used bikeshed before.

marcoscaceres commented 6 years ago

Also, can I clarify; am I meant to be opening the PR on the bikeshed file? Sorry if that’s a dumb question. I haven’t used bikeshed before.

Not a dumb question at all! but yes, on the BikeShed file. Don't worry too much about getting the syntax right at this point. That's what we have @tomhodgins for :)

andykirk commented 6 years ago

Great, thanks.

andykirk commented 6 years ago

Hi, Do we still need this issue open now the PR has been merged? Cheers

beep commented 6 years ago

@andykirk Oops, good catch! I’ll close this out.

(Apologies for the oversight. I’m traveling this week, and prep for the trip has kept me away from the CQ work. I’ll be back on it next week.)

Thanks again.