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

Feature proposal: children variant #277

Closed
benface opened this issue Dec 1, 2017 · 25 comments
Closed

Feature proposal: children variant #277

benface opened this issue Dec 1, 2017 · 25 comments

Comments

@benface
Copy link
Contributor

benface commented Dec 1, 2017

The idea would be to be able to do things like this:

Input CSS

@variants children {
    .block { ... }
}

Output CSS

.children:block > * { display: block; }
.block { display: block; }

Note: All children: variants would need to be output before the normal rule-sets so children can override rules defined by their parent (.class and .class > * have the same specificity).

HTML

<div class="children:block children:my-1">
    <a>
        I am a block with some vertical margin
    </a>
    <a>
        Me too
    </a>
    <a class="mb-0">
        I don't have bottom margin
    </a>
</div>

Advantages

  • Less repetition in the HTML (easier to change things that should be changed together)
  • Easier to read
  • Smaller HTML file size

I think this would be particularly useful for grids and lists. What do you think?

@sebastiandedeyne
Copy link
Contributor

I'd like to see this to plop on parent elements of things like generated menus.

Also, first-child and last-child variants would be welcome additions too.

@adamwathan
Copy link
Member

Happy to look at a PR for this, I think it's a cool idea 👍

@aparajita aparajita mentioned this issue Jan 29, 2018
Closed
@fedetibaldo
Copy link

@aparajita In regards to variants order, I'd invite you to post on #392. This kind of thoughts will become more and more frequent as people keep suggesting and implementing new variants. Starting to group them would be useful IMO.

In regards to subtituteAtVariantRule.js, I would suggest splitting the two features into two very distinct pull requests: the first, more verbose, to implement the three variants, the second to refactor the cited script.

@benface
Copy link
Contributor Author

benface commented Feb 25, 2018

@aparajita Do you also have children:hover, children:active, etc.? I think those would be quite useful.

@benface
Copy link
Contributor Author

benface commented Feb 25, 2018

@aparajita Why? I would like to use it for things like this:

<nav class="children:block children:p-2 children:bg-blue children:hover:bg-blue-light">
    <a>
        Home
    </a>
    <a>
        About
    </a>
    <a class="bg-orange hover:bg-orange-light">
        Log In
    </a>
</nav>

@benface
Copy link
Contributor Author

benface commented Feb 25, 2018

@aparajita

my understanding is that Tailwind is designed to avoid cascade and specificity issues

Mostly, but it still relies on the cascade for some things, like generating the hover and focus variants of each property after the property itself.

In fact your example won't work — because the children:bg-blue selector in the parent has a higher specificity than the bg-orange selector in the child, the child override has no effect.

Wrong. Please read the original post of this issue; I mention why that's not a problem:

Note: All children: variants would need to be output before the normal rule-sets so children can override rules defined by their parent (.class and .class > * have the same specificity).

EDIT: I'm not sure why @aparajita deleted his comments, but I swear I wasn't talking to myself!

@fedetibaldo
Copy link

In there any specific use case where children is actually necessary?

I mean, to avoid any kind of issue and doubt, we could force developers to apply classes directly to the child elements by leaving out the children variant from the PR

@benface
Copy link
Contributor Author

benface commented Feb 25, 2018

It's never necessary, no. This feature proposal is 99% about improving developer experience, which I believe is aligned with Tailwind's goal.

@fedetibaldo
Copy link

Suppose you have a blue table where the last and first rows are red. With the current version of Tailwind, you would style those rows manually, right? So you build the table, insert three rows and complete the job.
Later, another developer gets the task of adding a row to the table. Unfortunately, he misinterprets the design and he appends a blue row instead of shifting the red one.

In this scenario, first-child, last-child or even/odd-child would surely have granted a better developer experience, letting an uninformed developer make the right choice without any kind of documentation beforehand.

On the other hand, children doesn't create better developer experience. It creates a choice in your workflow:

should I delegate styling to the parent or to the child?

The answer is always the same: the former creates limitations (e.g. hover is not applicable via the parent with the current solution), so the ladder is the preferred way.

Why creating one-way choices? Isn't that a bad developer experience?

@benface
Copy link
Contributor Author

benface commented Feb 25, 2018

Suppose you have a table where all rows are exactly the same. With the current version of Tailwind, you would style those rows manually. Later, you need to change the padding of the rows. If you have 100 rows, you have to change it 100 times (assuming you're not using any templating language/system). Surely the children variant would have granted a better developer experience?

@fedetibaldo
Copy link

After the first repetitions, you likely created an @apply rule, making the changing problem pretty trivial

@benface
Copy link
Contributor Author

benface commented Feb 25, 2018

Depends on what you consider worthy of a "component" (i.e. a custom CSS class using @apply). If I'm only using this table on one page, I probably wouldn't create one. This is very subjective of course.

I'm not sure what we're debating exactly. Do you propose adding the -child variants without the children variant? I would find this confusing:

<div class="first-child:bg-red last-child:bg-red">
    <div class="bg-blue">
        I'm red.
    </div>
    <div class="bg-blue">
        I'm blue.
    </div>
    <div class="bg-blue">
        I'm red.
    </div>
</div>

@OwenMelbz
Copy link
Contributor

@fedetibaldo @benface

To cut the discussion short... If there's no downside to doing it - and it just enables more flexibility for people to do things with how their team feel comfortable, there should be no argument, the facility should be available.

The question might be should it built into the core or a plugin which is importable.

If there are people who have found there is a use case for it - then there's no reason to not to.

The tricker bit is finding somebody who can support this.

@adamwathan has suggested he's open to a PR for it, which suggests if somebody has time and it is implemented nicely, it will be accepted, as his life/project roadmap might not be suitable for him to add right now himself.

--

Is anybody except Adam able to provide a PR right now?

If not - Adam is this something down the line you think you're likely to add yourself?

<3 for tailwind

@benface
Copy link
Contributor Author

benface commented Apr 6, 2018

Thanks @OwenMelbz. I don't think it's possible to create custom variants with a plugin at the moment, so if Adam likes the idea, I think this should be in the core. One problem I can think of is CSS bloat though. If we want maximum flexibility, it would require the addition of quite a few variants:

  • children:
  • [screen]:children: (responsive variants)
  • children:hover:
  • [screen]:children:hover:
  • children:focus:
  • [screen]:children:focus:
  • children:active:
  • [screen]:children:active:
  • first-child:
  • [screen]:first-child:
  • first-child:hover:
  • [screen]:first-child:hover:
  • first-child:focus:
  • [screen]:first-child:focus:
  • first-child:active:
  • [screen]:first-child:active:
  • last-child:
  • [screen]:last-child:
  • last-child:hover:
  • [screen]:last-child:hover:
  • last-child:focus:
  • [screen]:last-child:focus:
  • last-child:active:
  • [screen]:last-child:active:
  • odd-child:
  • [screen]:odd-child:
  • odd-child:hover:
  • [screen]:odd-child:hover:
  • odd-child:focus:
  • [screen]:odd-child:focus:
  • odd-child:active:
  • [screen]:odd-child:active:
  • even-child:
  • [screen]:even-child:
  • even-child:hover:
  • [screen]:even-child:hover:
  • even-child:focus:
  • [screen]:even-child:focus:
  • even-child:active:
  • [screen]:even-child:active:

That's ((20 + 20 * the number of screens) * the number of utilities that have those variants enabled) new classes. I imagine that can be quite considerable even with the default config. Maybe we could skip the responsive and state sub-variants at first, but I think it would be frustrating to not have that flexibility and could potentially turn people off of this feature.

@adamwathan
Copy link
Member

The combinatorial explosion of variants is the part that has me hesitant to go too far down the path of adding variants for every idea we can come up with, even if they are disabled by default. Enabling this stuff for background colors for example adds another 7300 classes, which is pretty absurd considering there's currently only 4757 rules total in the current default build.

I think if we are going to include this sort of thing, every combined variant needs to be treated as it's own variant and not generated by default, so the config would be more like:

modules: {
  backgroundColors: ['responsive', 'hover', 'focus', 'active', 'first-child', 'first-child:hover', 'first-child:focus', ...]
},

I'm not opposed to including them this way but the second someone opens an issue saying Tailwind's output is too big with all these variants generated I'll probably want to set my computer on fire 🙃

@benface
Copy link
Contributor Author

benface commented Apr 6, 2018

That's how I was imagining it too. What should the responsive variants be called though? first-child-responsive, responsive-first-child, or responsive:first-child? I think the last one makes sense, and then the combined state and responsive variant could be like responsive:first-child:hover?

@adamwathan
Copy link
Member

I've started working on making it possible to add new variants via plugins, so going to close this with no concrete plans to add it to core for now. Once the plugin system supports this, we can play with it in a plugin and if it really makes sense to add to core we can reconsider it then 👍

@benface
Copy link
Contributor Author

benface commented Feb 15, 2019

Hey @adamwathan I just tried to do a plugin that adds a children variant as described in my first post 👆, but it doesn't seem possible for the variant rule to be generated before the standard rule (which is required so normal utilities applied to the children elements can override the children: utilities applied to the parent). I tried experimenting with the PostCSS container that's being passed to the closure in addVariant(), but it seems that the container itself is always generated after the utility's standard rule.

@benface
Copy link
Contributor Author

benface commented Feb 15, 2019

Ha I just realized I asked about this in #496 and your reply was:

I think we could solve that by adding an optional normal/plain/default variant that you could add to the list to control where the unmodified utilities are generated, and if it's not present we just push it onto the beginning of the list.

I don't think that was ever implemented though, or am I wrong? Do you still think it's a good idea?

@adamwathan
Copy link
Member

adamwathan commented Feb 15, 2019 via email

@Jerome1337
Copy link

@adamwathan Any news about it?

@benface
Copy link
Contributor Author

benface commented Mar 9, 2020

@Jerome1337 I made it as a plugin: https://github.com/benface/tailwindcss-children

@rsimp
Copy link

rsimp commented Oct 16, 2020

Is this still being considered for core? I realize the issue with bloat, however for styled components neither tailwind.macro or twin.macro rely on generated classes or support plugins. Adding these variants to core would make the macros much more useful. Disabling by default shouldn't have anymore affect on bloat than the several other variants also disabled by default

@audacioustux
Copy link

as @tailwindcss/jit is on the way, i think this should be part of the core tailwind

@yvonnetangsu
Copy link

Come here to say that I would love for this to be added to core tailwind with the new jit mode 😄 Thank you for the work you've done - @adamwathan and @benface !

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

9 participants