Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Container queries #1563

Closed
samuelbirch opened this issue Apr 14, 2020 · 27 comments
Closed

Container queries #1563

samuelbirch opened this issue Apr 14, 2020 · 27 comments

Comments

@samuelbirch
Copy link

samuelbirch commented Apr 14, 2020

Hi,

I'm not sure if it's possible already so please forgive if it is.

I'll like to implement container queries that are not based on media queries. So in my thinking i'd like to be able specify custom breakpoints (which i know is available) but based on a parent container class rather than a media query. So for example...

<div class="thin">
    <div class="w-1/2 thin:w-full"></div>
</div>

I would apply the "thin" class to the container via Javascript.

@royvanv
Copy link

royvanv commented Apr 20, 2020

This has so many use cases, mainly themes (dark mode).

@Vorror
Copy link

Vorror commented Apr 21, 2020

Based on my understanding of how Tailwind works I'm not sure this is possible. Breaks points or "container" classes like xs:* md:* are generated statically. Unless it's a plugin, I'm not sure how Tailwind could possibly generate the necessary scaffolding to have arbitrary *:* or *:<Tailwind Class> work.

Although, maybe you could make some sort of webpack plugin/loader for your framework of choice (vue/react) etc to process those tags. But I'm sure that would probably be out of scope of Tailwind core anyway.

@samuelbirch
Copy link
Author

Aren't the breakpoint classes generated from the config json file?

You can configure your breakpoints and media queries in that file so in theory it would be great to be able to configure what container queries you want in there too, and only have those compiled into the resulting css.

the resulting css classes would be prefixed with the container class:

.thin .thin\:w-full {...}

@adamwathan
Copy link
Member

Not planning to explore this any time soon, I would recommend just managing the class list directly if you are going to use JavaScript to set the parent class anyways.

@ivansieder
Copy link

@adamwathan one use case we've recently encountered is the following: we're developing custom web components to be used and embedded as widgets on arbitrary websites. As we do not always know where and how the widgets will be used, we're currently using ResizeObserver to observe the widget container's width and apply a global class depending on the current size instead of the current screen size, which allows us to be more flexible and adaptable. Currently we're not using Tailwind CSS yet due to the above troubles we face.

Could it be an option for Tailwind to have a config option to switch from media queries to a class-based approach? Let's say for example on the parent class you set sm, md, lg, xl, 2xl, and instead of converting this to @media (min-width:768px) { ... } it's going to be converted to .sm .flex { ... }? Not sure if that won't break anything, but it maybe could be an option to evaluate.

Other than that, is there any other approach to handle such use cases?

@Angelinsky7
Copy link

@adamwathan now that Dark Mode is here, could we have this feature ?
it seems to me that this is exactly the same thing but with the possibility to customize the name, no ?

@Angelinsky7
Copy link

Sorry for the noise.
its totally possible now doing this (https://tailwindcss.com/docs/plugins#adding-variants) :

const plugin = require('tailwindcss/plugin')

plugins: [
        plugin(function ({ addVariant, e }) {
            addVariant('thin', ({ modifySelectors, separator }) => {
                modifySelectors(({ className }) => {
                    return `.${e(`thin`)} .${e(`thin${separator}${className}`)}`
                })
            })
        })
    ],

@Angelinsky7
Copy link

thanks you ! i love it :-)

@alex-w0
Copy link

alex-w0 commented Mar 18, 2021

@Angelinsky7 Your solution works, thanks.
@adamwathan Do you mind to confirm that this is the correct way to solve this? Maybe it could be useful for others to have this use case in the variants section?

@edgarasben
Copy link

We build interfaces in and from components today. The same component could look very different depending on the context - mainly how wide the parent container is?

It would be really awesome if Tailwind supported Container Queries. Some ideas here:
https://philipwalton.github.io/responsive-components/#overview

@RXminuS
Copy link

RXminuS commented Apr 8, 2021

You can actually do some kinds of "container queries" using a super cool CSS hack...no javascript/static code required. https://heydonworks.com/article/the-flexbox-holy-albatross/

If you would simply generate the flex-base root values used in the calc you could have a container-md:flex-col or container-lg:flex-row utility class

@edgarasben
Copy link

edgarasben commented Apr 9, 2021

You can actually do some kinds of "container queries" using a super cool CSS hack...no javascript/static code required. https://heydonworks.com/article/the-flexbox-holy-albatross/

If you would simply generate the flex-base root values used in the calc you could have a container-md:flex-col or container-lg:flex-row utility class

Yes, it's nice for some cases, but I cannot fully control every css attribute of child elements based on the parent width.

@fratzinger
Copy link
Contributor

Media queries can be enabled by setting a flag in the new chrome: https://css-tricks.com/say-hello-to-css-container-queries/
Maybe it's time to think about native support for media queries in tailwind?

@MichaelAllenWarner
Copy link
Contributor

I accomplish this with a custom PostCSS plugin that makes rules like

._sm ._sm\:mt-10 {
  margin-top: 2.5rem;
}

for every (un-purged) responsive Tailwind rule like

@media (min-width: 640px) {
  .sm\:mt-10 {
    margin-top: 2.5rem;
  }
}

Adds some CSS bloat, but it's worth it for me.

Then I have a client-side script that converts classes like sm:mt-10 to classes like _sm:mt-10 on elements that should depend on a container's width, with a ResizeObserver that controls the _sm/_md/etc classes on the container itself (h/t https://philipwalton.com/articles/responsive-components-a-solution-to-the-container-queries-problem/). I use a data- attribute to indicate that an element should be a container, and the script goes through all its descendants looking for those responsive utility classes. (Important never to nest the containers. Also, requires that the classes be in the mark-up; won't work with @apply rules.)

This works pretty well on the whole, at least for my purposes (making full-width components look okay when put against a sidebar). A nice benefit is that I can just use normal responsive Tailwind classes in my code. If the component is wrapped in one of those containers with a data- attribute, then the browser turns the media-queries into container-queries on the fly.

@marcushjelm
Copy link

Sorry for the noise.
its totally possible now doing this (https://tailwindcss.com/docs/plugins#adding-variants) :

const plugin = require('tailwindcss/plugin')

plugins: [
        plugin(function ({ addVariant, e }) {
            addVariant('thin', ({ modifySelectors, separator }) => {
                modifySelectors(({ className }) => {
                    return `.${e(`thin`)} .${e(`thin${separator}${className}`)}`
                })
            })
        })
    ],

@Angelinsky7, I don't think the plugin above will handle this correct:

<div class="thin">
  <div class="w-1/2 thin:hover:w-full"></div>
</div>

However, I think the following plugin solves this:

plugin(function ({ addVariant, e }) {
  addVariant('thin', ({ container, separator }) => {
    container.walkRules((rule) => {
      rule.selector = `.thin .thin${e(separator)}${rule.selector.slice(1)}`
    })
  })
})

@vbraun
Copy link

vbraun commented Oct 7, 2021

The proposed plugin also creates useless responsive variants, e.g. for p-1: In addition to the desired thin:p-1 you also get a bunch of responsive xs:thin:p-1, sm:thin:p-1, md:thin:p-1, ... classes. But the whole point of the simulated container query is to override the media queries. It would be nice if we could opt-out of the stacking with the responsive variants here.

@MichaelAllenWarner
Copy link
Contributor

@vbraun

I believe that using [class~="class-name"] instead of .class-name in a selector is how you tell Tailwind not to treat a class as a utility.

@vbraun
Copy link

vbraun commented Oct 7, 2021

Great idea, but if I hide the classes from tailwind using the attribute selector trick then the responsive variant generation errors out with:

CssSyntaxError: <css input>:1:39: Variant cannot be generated because selector contains no classes.
    at <input css erRCHz>:1:39
    at Input.error (/home/vbraun/Talque-3/talque/frontend/node_modules/tailwindcss/peers/index.js:57364:16)
    at Rule.error (/home/vbraun/Talque-3/talque/frontend/node_modules/postcss/lib/node.js:60:32)
    at /home/vbraun/Talque-3/talque/frontend/node_modules/tailwindcss/lib/lib/substituteResponsiveAtRules.js:84:24
    at /home/vbraun/Talque-3/talque/frontend/node_modules/tailwindcss/lib/util/buildSelectorVariant.js:22:9
    at tap (/home/vbraun/Talque-3/talque/frontend/node_modules/lodash/tap.js:25:3)
    at Processor.func (/home/vbraun/Talque-3/talque/frontend/node_modules/tailwindcss/lib/util/buildSelectorVariant.js:18:22)
    at Processor._runSync (/home/vbraun/Talque-3/talque/frontend/node_modules/postcss-selector-parser/dist/processor.js:102:26)
    at Processor.processSync (/home/vbraun/Talque-3/talque/frontend/node_modules/postcss-selector-parser/dist/processor.js:197:23)
    at /home/vbraun/Talque-3/talque/frontend/node_modules/tailwindcss/lib/util/buildSelectorVariant.js:28:6
    at /home/vbraun/Talque-3/talque/frontend/node_modules/tailwindcss/lib/util/useMemo.js:28:18 {

@KarelJanVanHaute
Copy link

Adding my two cents to this thread.

Chrome Labs now has a polyfill.
https://github.com/GoogleChromeLabs/container-query-polyfill?utm_source=CSS-Weekly&utm_campaign=Issue-488&utm_medium=email

Maybe someone can write a tailwind plugin that uses this polyfill. Because we want container queries today!

@basejump
Copy link

just started playing with this and its looking promising for anyone else landing here looking. https://github.com/dgknca/tailwindcss-container-query

@dsldsl
Copy link

dsldsl commented Jun 24, 2022

@basejump I'm looking at that as well. How has your experience been? Thank you!

@wenerme
Copy link

wenerme commented Aug 31, 2022

Not planning to explore this any time soon, I would recommend just managing the class list directly if you are going to use JavaScript to set the parent class anyways.

@adamwathan Hi, chrome 105 is released with container query, will look this again ?

@recurrence
Copy link

Safari 16 launched with support for this today. Super excited to see it's almost ready in Chrome as well. This must be one of, if not the the biggest, CSS features to come in many years.

@dsldsl
Copy link

dsldsl commented Sep 12, 2022

FWIW, I've been using tailwindcss-container-query library and it works great. It uses container-query-polyfill library. Native tailwind support would be great but also not a priority imo as long as these other libraries work.

The one thing - I have been noticing some memory / hanging issues with a large-ish scatterplot chart along side 5 other charts and I dont know if that is just from recharts or because of the polyfil stuff. Haven't traced it yet, but that's in my field.

@fratzinger
Copy link
Contributor

https://twitter.com/adamwathan/status/1570840782659260416

@Arturexe
Copy link

Deriving from @fratzinger 's link, any news on when this feature will be fully integrated into tailwind?

@fratzinger
Copy link
Contributor

https://tailwindcss.com/blog/tailwindcss-v3-2#container-queries 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests