Coder Social home page Coder Social logo

container-queries's Introduction

container-queries

This incubation successfully resulted in Container Queries being specified in https://www.w3.org/TR/css-contain-3/

Contain queires are now a standard part of the web platform.

If you have any questions or concerns with container queries, please direct enquiries to the CSS Working Group.

This repository has been archived for historical purposes.

container-queries's People

Contributors

eeeps avatar marcoscaceres avatar wilto avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

container-queries's Issues

A rough proposal for syntax

May Tim Berners-Lee have mercy on our souls, because it is time to kick off The Great Bikesheddening.

I’m a big fan of the syntax @jonathantneal proposed way back when, but I have two issues with my own preference:

First, it doesn’t make sense strictly in terms of container queries. This syntax is fine for styling child elements if we always assume something like this:

.element:media( min-width: 60em ) .child-el {
  background: papayawhip;
}

But there’s nothing stopping someone from writing:

.element:media( min-width: 60em ) {
  background: papayawhip;
}

At which point, would we just throw those styles away? That seems strange.

The second issue is the repurposing of media, which doesn’t seem to make semantic sense in this context. It feels a little telephone-gamed from media="handheld"—which checks out—to @media( min-width: 30em )—which kinda makes sense—to .el:media( min-width: 30em ), which makes no sense whatsoever.

Proposal for a slightly different syntax and function

In #2 (comment) I posted an idea about a different syntax. It looks like:

.child:container(min-width: 150px) {
    color: red;
}

And the nearest qualified ancestor is selected as the container to run the query against by the browser.

As I put more thoughts into this I got an idea of how the implementation issue (jumping between compute style and layout) could possibly be solved.

If I’m right the browser computes the styles by traversing the DOM tree from top to bottom. In this process it could already calculate and store the width if it knows that it doesn’t depend on its descendants. If it then reaches an element with a container query rule it already knows what the right container is – it’s the nearest ancestor for which it was able to calculate a width – and which width it has. So it should be possible to resolve the container queries without doing the layout process.

It may be that I’m totally wrong with my assumptions about browser internals, but it would be great if it is implementable this way.

If someone is interested in this idea I also wrote a prolyfill and a blog post about this version of container queries.

Container queries via custom properties (aka CSS variables)

I’ve got a new idea for a solution to container queries 🤓

What we already have today

To describe the concept, lets first take a look at what we already have in browsers, imagine the following setup:

:root {
    --context-width: 100vw;
}
.one-third {
    width: 33.3%;
    --context-width: calc(parent-var(--context-width) / 3);
}
.two-thirds {
    width: 66.6%;
    --context-width: calc(parent-var(--context-width) / 3 * 2);
}

Now I can create a component that is in a 16:9 ratio to its context width as easy as:

.component {
    height: calc(var(--context-width) / 16 * 9);
}

No matter how nested the one-third and two-thirds containers are, a component inside them or at the root level would always be in the desired 16:9 ratio. This works already, take a look at this CodePen, although we need to hack a little because parent-var() is not a thing yet.

New concept for CSS conditions

If we take this idea further and introduce a concept for custom property conditions with this syntax:

if( <condition> , <value-if-true>, <value-if-false> )

we could do something like:

.component {
    float: if(var(--context-width) > 200px, left, none);
}

This way we told the component to only float left if it’s in a context (or container?) with more than 200px width, otherwise it should not float. Sounds pretty much like container queries to me 🎉

From the perspective of a browser

My knowledge for browser internals in very limited, but AFAIK one big problem with an implementation of container queries is, that the engine would have to jump between layout and style computation, which could result in unstable results and might be very bad for performance. I think the concept of simple CSS conditions would not suffer from that problem. Taking the example from above, the condition var(--context-width) > 200px can be worked out without the need for a layout. First the var() part would be resolved to something like calc((100vw / 3) / 3 * 2) and further to 22.22vw. This value can then be easily compared to 200px.

Flexibility

Another benefit I see with this solution is, that the CSS author can decide how to set and inherit the variables. If one creates a website which has bright and dark sections, he could set --context-dark to true or false and create components that just look perfect in every place. Such binary conditions already work in browsers today if you are very creative.

Downsides

The main downside of this solution is that we need to set variables for every container that changes the available width for its children. And we would sometimes not get the “exact” value if e.g. a scrollbar reduces the available width.

What do you think?

Update Spec with Content

Hi RICG!

I've been working on my own syntax for container-query style element queries - and have begun writing that up as a spec! I'd love to see some action in this repository (it's been a year and a half since the last update) and see if there's anything from my spec we can bring over, or what we can do to breathe some life into this again.

The repository for my container query syntax is here: https://github.com/tomhodgins/element-queries-spec

And the syntax described in that document is already able to be tested with the EQCSS JavaScript plugin. You can already find over a hundred examples of this syntax in use (case studies, and demos) on Codepen here: http://codepen.io/search/pens?q=eqcss&limit=all&type=type-pens

New year, refreshed desire to make Element Queries part of CSS!

Heydon’s “Holy Albatross”

Heydon Pickering recently posted a great trick for making a flex items wrap below a breakpoint and display inline above the breakpoint — and the breakpoint is dependent on container width, not viewport. The trick involves using calc() to force flex-basis to be either an arbirarily low negative or high positive value.

This is one particular case of container queries, solved using today’s CSS. I know that, using flexbox & grid, there are a few other specific cases that can be accomplished as well. In fact, I believe his technique can be used to solve the specific use-case given in our Use Cases document.

This leaves me with two questions:

  1. What specific use-case(s) remain that cannot be accomplished using similar means?
  2. Can we somehow tap into the existing power of flexbox/grid wrapping, and maybe provide a shorthand syntax that uses existing mechanics to solve some (if not all) container query problems?

What about "display: frame" ?

Hi everyone,

I apologize in advance because I'm more a javascript developer than CSS, so the following may not make sense.

My understanding of the container-queries's circular problem is that a chidl rule could conflict with one of it's parent and influence him back.

However, a browser window (for example), resolve implicitly this problem : there is no way the HTML can influence the size of the window.

Why not create a new value frame for the display property ?

  • It inherit from all display: block behavior
  • It's the default value for <HTML>
  • Any container with this value can't be influenced by it's child. In another words: containers will act as the window will normally do if it was the container. It can't either influence itself (e.g: changing it's own display property).
  • Any container with this value will still act like a normal block for the "outside world" and could be resize by the environment.
  • A container query rule it's ignore if performed outside a frame (container:min-width(450px) > .child will be ignore if .container has no display: frame).

Example:

.container {
  display: frame;
  float: left;
}
.container:hover {
   display : block;
}
.child {
  width: 500px;
}
.container:min-width(450px) > .child {
  width: 400px;
}
  • When .container width >= 450px: child is 400px
  • When .container widh < 450px, child is 500px, but don't influence the parent size. An scrollbar may be displayed (depending of the overflow-x value)
  • When hover on the container, both the child and the container are 500px.

Regards,

Abraham

Should we archive this repo?

Hi y'all... given that lack of activity in over a year, it might be time to concede defeat on this and "archive" this incubation.

Although we've not managed to solve this exactly problem on the Web, would it be fair to say that we have a set of capabilities on the web that are helping solve some the same problems (e.g., CSS grid and sub-grid)?

What do you all think? Or should we try to keep going? We can always un-archive later.

cc @WICG/chairs

Change name of repo/solution from “container queries” to “element queries”?

I would like us to start the discussion this year by deciding on a "name" everyone could get behind.

Now I know that even the repo is called "container-queries", but I think there are some people out there that would rather call it "element query", or something else altogether.

Why is this important?
We need to be on the same page on this from the beginning, otherwise when it comes to talking about the exact syntax, I can already see ourselves get sidetracked by the fact that someone used "container" while another example has "element" and a third some version of "media".

In my opinion this could lead to discussions that are ultimately pointless, very much like the semicolon vs no semicolon in javascript.

Let's just pick a name, and stick with it.
That will also make syntax examples more consistent.

Now, My Opinion

I would keep the "container" name. 😂

I saw some people proposing syntaxes with "media", but I think we should make it obvious from the very beginning that this is something different from media queries to avoid confusion.

Historically to me it seems that we first started with "element" query, which was only about changing an element's styling based on some conditions on that very element.

Then, "container" queries started to pop up, which could also affect child elements inside the main "containing" element, hence the naming.

Example on how different the two might feel with a made-up syntax:

@element .SomeClass (width > 200px) {
  /* Only rules are allowed here */
  font-size: 16px;
}
@container .SomeClass (width > 200px) {
  :self {
    font-size: 14px;
  }

  .Child {
    font-size: 16px;
  }
}

In the case of the latter, instances of the ".SomeClass" element individually influence child nodes' styles, based on their own conditions.
(They are scoped in this sense.)

From experience, I think the latter is way more powerful than only applying styles to the element itself.

Now all that being said, I'm not totally against calling it @element query either, so long as the same concept of containment / scoping applies.

2019 Proposal/Solution for Container Queries

Before I go into details of this algorithm / solution, it's useful to establish some semantics.

First, there is some historical conflation of the terms "container queries" and "element queries". Depending on the solution (how someone thinks about the problem), these are often conflated to mean the same thing. There's discussion here about renaming the repo from "container queries" to "element queries" based on various conventions, etc, but I find that what's often missed when people talk about container queries vs. element queries is that people think they're talking about the same thing, when they often aren't.

To clarify:

  • A container query queries an element's container in order to apply styles
  • An element query queries a given element in order to apply styles to that element. (In some proposed solutions, the element is queried in order to apply styles to children.)

Someone may say, "Yes, but isn't the container always an element?" In short, no. In some proposals, yes. In this proposal, no, and for (IMO) very good reasons.

The 2019 Container Queries Proposal

Summary

This algorithm / approach has the following:

  • Zero circularity
  • Single-pass resolution of queries (negates the claim here that any container query algorithm must be applied multiple times)
  • Minimal syntax additions

What are we querying?

This is absolutely crucial, and what makes this query algorithm fast (as fast as media queries), deterministic, and single-pass.

What we are querying is the allocated width/height of the content box that this element will be placed in.

screen shot 2019-01-06 at 12 23 45 pm

Immediately, someone may point out that the content box eventual dimensions can be affected by children. In order for this algorithm to be successful, that's why we must query what the content box is irrespective of children. In other words, what are the dimensions if no children were present?**

** Note: this doesn't mean we would measure as if the container were truly empty; specifically, an :empty selector would not apply during measurement if children are present, children just don't affect the allocated width/height for the purposes of this algorithm.

Why the content box?

Just to briefly address this question, the reason why we query the content box specifically vs. the parent element's width is to avoid ambiguity / surprise when switching box models. Queries always refer to the "available space" to the child element, so that you can set properties of the child based on what pixels (or other units) will actually be available. Querying the parent element's actual (or calculated) width value would strongly bind the child element to the parent's box model. Therefore, the container must be a known constant: the content box dimensions of the parent before children are rendered.

Syntax additions

:container([MQ]) - selector query of the container, using MQ Level 3 or Level 4-style queries, and can query width / height [/ inline / block] (-axes)
aw / ah / ai / ab - units relating to 1% of width / height / inline-axis / block-axis (semantically similar to vw / vh / vi / vb)

Examples

<div class="parent">
  <div class="child"></div>
</div>
.parent {
  width: 100px;
  height: 200px;
}
.child {
  background: red;
  color: white;
}
/* Also can be written (min-width: 100px) */
.child:container(width >= 100px) { 
  background: blue;
}

So far, this is similar to most other container query algorithms. Where it differs is that this query is non-circular.

For example:

.parent {
  min-width: 50px;
}
.child:container(width <= 50px) { 
  width: 200px;
}
/** Will not apply **/
.child:container(width >= 200px) {
  width: 50px;
}

The .parent class, when laying out, has only been allocated a width of 50px. Therefore the allocated width of .parent will stay fixed at 50px unless it is allocated a new width (not sized by children). (100aw = 50px)

Here's another simple example, assuming the same markup

.parent {
  float: left;
}
.child {
  width: 200px;
  height: 100px;
  background: red;
}
.child:container(min-width: 200px) {
  background: blue;
}

In this example, because a float "wraps" around the child, and has no defined width to calculate irrespective of children, then the allocated width/height are both 0 (zero). Meaning the container query (min-width: 200px) will not apply, and the background of .child will be red.

We can make the container query apply by changing this to the following:

.parent {
  float: left;
  width: 200px;
  height: 100px;
}
.child {
  width: 100%;
  height: 100%;
  background: red;
}
.child:container(min-width: 200px) {
  background: blue;
}

In the above example, the background of .child will be blue.

Other collapsing boxes

Other examples of boxes that don't have allocated width / height would be inline boxes (display: inline-box / inline-flex / inline-grid), or using width: fit-content / min-content. If they don't have a width / min-width or height / min-height value that can calculate an allocated value before the layout of children is determined, then those values will be zero.

width: auto

Note that block boxes with a width of auto will have an allocated (non-zero) value. That is, an allocated width can be determined irrespective of children.

So, given a viewport of 1024px, and this markup:

<body>
  <div class="wrapper"></div>
</body>
body {
  padding: 0; margin: 0;
}
.wrapper:container(width >= 1024px) {
  background: red;
}

In this case, a user agent stylesheet styles <body> as a block with a width of auto. Therefore the wrapper's container query applies and the background will be red.

An example with CSS Grid

Note that a container query applies to the pre-children content box of the parent. If you are slotting children into a grid, the queries of direct children of the grid will not be related to column / row slotting.

Meaning:

.parent {
  width: 300px;
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
}
.child {
  grid-column: 1;
}
/** Does not apply */
.child:container(width = 100px) {
  background: blue;
}
/** Does apply */
.child:container(width = 300px) {
  background: red;
}

The above example helps make the important distinction between element queries and container queries. We're not querying the width that will be calculated for .child. We are strictly querying the initial content box of .parent.

However, we could easily nest children to "query" the width of the column for some powerful layout possibilities.

Given the following:

<div class="grid">
  <div class="grid-item">
    <div class="child">First</div>
  </div>
  <div class="grid-item">
    <div class="child">Second</div>
  </div>
</div>
.grid {
  display: grid;
  width: 300px;
  grid-template-columns: 2fr 1fr;
}
.child {
  height: 100px;
  color: white;
}
.child:container(width = 200px) {
  background: red;
}
.child:container(width = 100px) {
  background: blue;
}

This would give you a layout like this:

screen shot 2019-01-06 at 1 27 21 pm

Once .grid-item is slotted into a column, it has a calculated initial content box width that can then be queried by the .child.

Using height / inline / block

Most of these examples have been querying width because of the way we typically layout pages, and because of default collapsing behavior. But, given a fixed (or minimum) height on a parent, it can also be queried.

.parent {
  height: 100px;
}
.child:container(height >= 100px) {
  background: blue;
}

We can also query the inline-axis or block-axis, depending on writing direction or layout settings.

.child:container(inline >= 100px) {
  background: blue;
}
.child:container(block >= 100px) {
  background: blue;
}

Page / programmatic resizing

An important thing to note is that while the initial content box dimensions of an element used for a query can't be affected by children layout, it doesn't mean it's a "fixed" value per page load. A parent element may be resized by resize of the viewport (depending on initial width / height values) or changed programmatically.

On resize, the browser must determine if a parent element has a new initial content box size. In other words, just because the element is "resized", doesn't mean the initial content box size has changed.

This is best demonstrated by example. In the following example, no amount of "resizing" the viewport / browser window will cause the container query to match.

.parent {
  float: left;
}
.child {
  width: 100vw;
}
.child:container(width >= 50vw) {
  background: blue;
}

The initial content box width of parent is always 0 (zero), even though the .parent element may be visibly resizing on-screen. (As an aside, this is an advantage over ResizeObserver-based polyfills of content queries, which are subject to circularity, since they respond to any resize of the element.)

In the following example, however, resizing of the viewport will trigger matches / un-matches of the container query, and will dynamically apply those styles.

/** Assuming parent is a child of `<body>` */
.parent {
  width: auto;
}
.child {
  background: blue;
}
.child:container(width >= 200px) {
  background: black;
}
.child:container(width >= 400px) {
  background: red;
}

In the above example, note that container queries follow rules of the cascade. By default, .child has a background of blue. Once the available content width is 200px or greater, the background is black, overriding blue. Once the available content width is 400px or greater, the background is red, overriding black and blue.

Resizing with JavaScript

If the .parent has explicit dimensions set as inline styles with JavaScript, then the available content box width would be updated, and container queries that query the .parent content box would be re-evaluated.

Using allocated units

2019 Container Queries are extremely powerful, but have an important companion piece which is allocated units. This allows you to easily make your CSS styles more modular / adaptive regardless of container.

Allocated units (aw / ah / ai / ab) are units relating to 1% of initial container box width / height / inline-axis / block-axis, respectively.

Let's re-use our grid example.

<div class="grid">
  <div class="grid-item">
    <div class="child">First Child</div>
  </div>
  <div class="grid-item">
    <div class="child">Second Child</div>
  </div>
</div>

Based on how much space .child may take, we can scale font-size to be reflective of that additional space.

.grid {
  display: grid;
  width: 310px;
  grid-template-columns: 2fr 1fr;
  grid-gap: 10px;
}
.child {
  height: 100px;
  padding: 10px;
  color: white;
  background: blue;
  font-size: 15aw;  /** 15% of allocated content box width */
}

This would result in:

screen shot 2019-01-06 at 2 30 07 pm

Of course, you can use a combination of calc() or newer min(), max() or clamp() CSS functions (when available) to moderate the range / effect of allocated units.

As a result, you can define individual, reusable "modules" that adapt to defined containers.

Note that 100aw or 100ah etc. may resolve to 0 (zero) if the parent content box has no intrinsic dimensions.

Question to resolve: Would it be important to define a syntax for a default container width/height for a child element if a query returns a zero for either value? Or is min() / clamp() sufficient? 🤔

More advanced queries

A variety of examples of queries

/** MQ4 - value range */
.a:container(400px < width < 1000px) {}

/** can target children of queries, as expected */
.a:container(width > 10em) .b {}

/** negating queries - not equal to 100px */
.a:not(:container(width = 100px)) {}

/** Joining queries */
.a:container(width > 100px):container(height > 100px) {}

/** Nesting queries */
.a:container(width > 100px) .b:container(width > 50px) {}

Feedback

Feedback welcome. There are likely to be opinions™ around various points of this proposal, such as syntax. I think the selling points are, because this query algorithm is one-way, fast, and predictable, it's something that I believe could be implemented in browsers much sooner than previous proposals, mostly because of zero circularity. Layout / queries can be determined in a single pass, as quickly as media queries are today. This makes this a potential drop-in replacement for many/most media queries, since as noted by many other, smarter people, many people use @media queries when what they mean are container queries (the available width for my component).

That said, there are obvious use cases of using both @media and 2019 Container Queries. I just didn't want to get too far in the weeds of creating use cases / examples, as this proposal was already quite long.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.