-
Notifications
You must be signed in to change notification settings - Fork 4.6k
Add @silent
at-rule
#169
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
Add @silent
at-rule
#169
Conversation
Just because it's insanely complex to support it in any weird nested ways and I'd rather people get an error for now instead of bizarre unexpected results.
I'm all for this. I understand with Tailwind you're trying to push utility classes in HTML over slapping |
Adam, I am once again torn on whether or not this should be done as a custom at-rule, or simply done in the Tailwind config. Considering some of the config ideas we've been bouncing around lately, I wonder if we should do something like this: {
options: {
silent: true,
}
} |
Expanding on my previous comment, my fear is that just because we've got this power to create custom at-rules in PostCSS, does that mean we should for everything? Having some obviously makes sense (apply, responsive, tailwind), but I wonder how wise it is to create tons of these. Using custom at-rules seems way more likely to create future compatibly issues over simply managing this in our own JS config file. |
The issue with doing it in the config file means *all* instances of
rendering the utilities would be silent. The problem we’re trying to solve
here is allowing people to render the utilities once in a global
stylesheet, and still use `@apply` to reference those utilities from
separate CSS trees, like those inside a Vue component.
There might be other solutions to this too but worried they come with their
own complexity; for example Tailwind could continuously build a global
cache of all touched styles during a build and `@apply` could look there.
I’m sure that would be absolute hell to get working properly with watch
though.
What I’d actually be curious to see is a real world example of where you
would use `@apply` in a Vue component instead of using the utilities
directly. If you’re already encapsulated in a component, the benefit of
`@apply` vs using utilities directly gets pretty close to zero, since you
aren’t avoiding duplication anymore; the Vue component is handling that for
you already.
I’d also be curious to understand more about the general styling
architecture when building a SPA with lots of CSS in JS; do you still have
a global stylesheet at all? If not I wonder how well *any* CSS framework
really fits into that story?
…On Thu, Nov 9, 2017 at 6:02 PM Jonathan Reinink ***@***.***> wrote:
Expanding on my previous comment, my fear is that just because we've got
this power to create custom at-rules in PostCSS, does that mean we should
for everything? Having some obviously makes sense (apply, responsive,
tailwind), but I wonder how wise it is to create tons of these. Using
custom at-rules seems way more likely to create future compatibly issues
over simply managing this in our own JS config file.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#169 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AEH3bBDZaiC3uWbYIiFGHXpqFHkxs5k_ks5s04SigaJpZM4QYsUq>
.
|
Yeah real good points. I'd love to explore this a little more as well:
Like, why build a CSS component if you're already building a JS component? What's the point? |
I'm trying to understand this too; I'd love to see an example of a real Vue component where it feels necessary to use |
For me the point is limiting the bundle sizes. The css for tailwinds is 170kb (obviously less if gzipped), but I may not need that for initial load. I like using nuxt for frontend, which makes it easy to control what gets downloaded and when. I like the consistency of using a system like tailwind. Which I think may be better than what I'm currently doing. My current set up is having a config file with CSS4 vars, I import that file in to every vue component that needs style and use the vars in that component. It allows complete control over the download size while maintaining a consistent config. I think using tailwind in a similar set up would be nice, // BaseContainer.vue
<template>
<div>
<slot />
</div>
</template>
<style scoped>
div {
@apply .container .mx-auto
}
</style> |
@adamwathan Extracting lots of components is a good practice but I find myself dreading having to create custom components for things like buttons, text fields, and other form fields that don't add any additional functionality on top of the native element. Sometimes it's nice to have a class for consistently styling them without fully encapsulating them within a component. |
@syropian I'm confused; why can't you just create a Where are you defining |
@adamwathan For example, my login/register screens may have certain styles of inputs and buttons that differ than the main app screens. I could create these styles in a global stylesheet of course, but I prefer the encapsulation of keeping them in the components. It's about trying to find a balance of "keeping styles encapsulated" without over-encapsulating my creating a new Vue component for every single little element. |
@syropian I get that but why do you need to use <template>
...
</template>
<script>
...
</script>
<style>
.btn {
@apply .bg-blue .text-white .etc;
}
</style> ...if you can't even reuse that I guess there's the situation where you have one component with two input fields that look the same; in that case could you just use a computed property instead? <template>
<div>
<input :class="[inputStyles]">
<input :class="[inputStyles]">
</div>
</template>
<script>
export default {
// ...
computed: {
inputStyles() {
return 'appearance-none px-4 py-2 border ...'
}
}
}
</script> Personally I would still just do this: <template>
<div>
<input class="appearance-none px-4 py-2 border ...">
<input class="appearance-none px-4 py-2 border ...">
</div>
</template>
<script>
export default {
// ...
}
</script> I guess I just don't understand the real benefit to composing CSS classes that can only be reused in the same file. I can understand the desire for it but I'm struggling to justify the effort it would take to support it in a sane way 😕 |
There's definitely no shortage of different ways to accomplish it, this is just my ideal method. I don't love the idea using computed props for pure presentational purposes personally. All this being said this isn't make or break for me. I'd like this feature but if it gets added or not, I would still keep using Tailwind :) |
Alright so me and @reinink just talked about this for about an hour and a half, so here's a summary of our thoughts on it all. Goals
(If we're misunderstanding the goals here, please let us know!) Solution #1:
|
@adamwathan Thanks for the detailed response! You guys are awesome, and I love the work you guys are doing. I will probably play with this branch a bit and see what happens. |
I personally would love @apply to behave similarly to scss mixins, or perhaps an alternative keyword that does. You can import entire mixins file in scss, and none of it gets included in your final bundle, except for the mixin styles that are applied to your class. I'm using Vue and Nuxt, which gives some powerful code splitting right out of the box. If @apply worked like mixins, I would be able to avoid pulling in the entire tailwind css generated file, and could instead just mixin tailwind CSS into my components where needed, benefiting from a reduced initial load time, while getting the consistency that tailwind provides. |
Just chiming in on this closed issue 😜 , I agree it could be a powerful feature if @apply could be used to pull in Tailwind's utility classes without having to first render out all of it's utility classes. This definitely would be optimum for using Tailwind with component based UI frameworks like React and Vue. It could also be handy for controlling file size, instead of looking at adding Purge CSS to the ends of our build tooling and cross our fingers this doesn't break anything. Not at all saying something like supporting this workflow is more important than mission critical things like adding missing utilities, better fleshing out the docs, or building out an extension and theming system! All of those sound awesome! 👍 But if you guys do come up with an optimum solution while you're chipping away on those, there definitely seems to be a desire, and it may help with issues like the following: nuxt/nuxt#2273, Integrating TailwindCSS into Nuxt SFC Apologies, I have little else to contribute other than chiming in from the peanut gallery. My understanding of how Postcss plugins work and the limits of what you can do with them is close to non existent at the moment. |
Also adding my 2 cents that this would be a great feature to have. I love the flexibility we gain with a utility-first pattern, however, being able to inherit from existing classes and styles is an extremely popular and powerful feature of modern preprocessor languages such as less and sass, that I think a lot of the development community has become used to and reliant upon them. In my specific use case, I would like to be able to do something like the following: // components/alert/alert.css
.alert {
@apply .border-t-4;
@apply .rounded-b;
@apply .px-4;
@apply .py-3;
@apply .shadow-md;
}
.alert--info {
@apply .bg-teal-lightest;
@apply .border-teal;
@apply .text-teal-darkest;
} // core.css
@tailwind preflight;
@tailwind utilities;
@import 'base.css';
@import '../components/alert/alert.css'; // components/alert/alert.js
import React from 'react';
import classnames from 'classnames';
import PropTypes from 'prop-types';
class Alert extends React.Component {
render() {
return (
<div className={classnames(
'alert',
'alert--info',
this.props.className
)} role='alert'>
<div className='flex'>
<div className='py-1'><svg className='fill-current h-6 w-6 text-teal mr-4' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'><path d='M2.93 17.07A10 10 0 1 1 17.07 2.93 10 10 0 0 1 2.93 17.07zm12.73-1.41A8 8 0 1 0 4.34 4.34a8 8 0 0 0 11.32 11.32zM9 11V9h2v6H9v-4zm0-6h2v2H9V5z' /></svg></div>
<div>
<p className='font-bold'>Our privacy policy has changed</p>
<p className='text-sm'>Make sure you know how these changes affect you.</p>
</div>
</div>
</div>
);
}
}
Alert.propTypes = {
className: PropTypes.string
};
export default Alert; When learning that tailwind would be implemented solely in CSS rather than less or sass, not being able to extend from tailwind classes was definitely one of my major concerns. The same as @01ivr3, I'm not able to offer much more than a +1 on this request, but hopefully this comment helps you prioritize this feature. Thanks |
@viglucci what you are asking for actually already works exactly like you want. It’s only trying to use |
@adamwathan is it supposed to work without using the postcss import plugin? I was receiving the below error until i found your comment here that mentioned the import plugin.
|
No you’ll need to use that plugin. If you don’t then the browser is going
to make many synchronous HTTP requests to fetch all of your separate CSS
files, which I’m assuming you don’t want.
…On Thu, Dec 21, 2017 at 6:31 PM Kevin Viglucci ***@***.***> wrote:
@adamwathan <https://github.com/adamwathan> is it supposed to work
without using the postcss import plugin
<https://github.com/postcss/postcss-import>?
I was receiving the below error until i found your comment here
<tailwindlabs/discuss#25 (comment)>
that mentioned the import plugin.
(2:5) @apply cannot be used with .border-t-4 because .border-t-4 either
cannot be found, or it's actual definition includes a pseudo-selector like
:hover, :active, etc. If you're sure that .border-t-4 exists, make sure
that any @import statements are being properly processed *before*
Tailwind CSS sees your CSS, as @apply can only be used for classes in the
same CSS tree.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#169 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AEH3bJiJYxdLlccY8v88K4AArkjV29VVks5tCupXgaJpZM4QYsUq>
.
|
Found Tailwind a week or so ago and was super excited because I thought it would solve this problem because of the docs on extracting components. This is actually a deciding feature in my book and not just a nice to have. I am trying to use Tailwind in Vue single file components. At the risk of sounding dramatic, without this feature I see little to no difference between Bootstrap, Bulma or Tailwind or any other CSS framework beyond aesthetics. And to try to pull the sting out of the above statement, let me clarify, without this the only way to use Tailwind the way I need it to work is by importing it through a LESS reference, and if I'm doing that why not just use Bulma or Bootstrap? @import (less,reference) "bootstrap";
@import (less,reference) "bulma";
@import (less,reference) "tailwind"; Been trying to get <style lang="postcss">
@reference {
// @tailwind preflight;
// @tailwind utilities;
@import "tailwind/preflight";
@import "tailwind/utilities";
}
.nav {
@apply .flex .items-center .justify-between .flex-wrap .bg-orange-dark .p-6;
}
</style> I've been messing with Webpack/Postcss/Tailwind config files every night for over a week now trying to figure this out, only stumbling across this issue today. Less won't extend the responsive classes like tl;drAll frameworks should include a feature like this, its a necessity for how they are used in SPA and to build optimized websites. |
As @adamwathan pointed out here and to avoid repeating the same styles over and over again as the template gets bigger, this is how i am using it in .vue files and it feels nice for me. <template>
<div :class="tailwind.card">
<p :class="tailwind.header">I am a card</p>
</div>
</template>
<script>
export default {
computed: {
tailwind() {
return {
card: 'p-8 bg-white shadow rounded',
header: 'text-gray-dark font-bold',
}
}
}
}
</script> |
@kamalkhan presumably that only works if you're including the global stylesheet somewhere? Guess I'm looking for a better balance of enabling my laziness without sacrificing performance. 😜 I want to be able to reference anything in the framework while developing, without needing to include the entire framework globally, and have the final result be concise. I want to have my cake and eat it to. Right now the 🍰 is a lie. |
This is a bit of a ridiculous statement considering the entire approach to CSS architecture is different among these tools. You choose Tailwind to take a utility-first approach to building custom user interfaces; you choose Bootstrap if you want predesigned components you can piece together.
Less won't be able to extend any of Tailwind's classes because they aren't generated until after Less has finished running. Regardless, the documentation is clear about how you should handle these situations:
Yes, this is how Tailwind is intended to be used.
Use a tool for removing unused CSS like PurgeCSS.
Not sure what this means; Tailwind doesn't make any promises about this workflow. You are meant to use Tailwind's classes in the As mentioned in earlier comments, we agree it would be nice for It's also loaded with hard decisions and complexity, because right now That said though, the "only use Tailwind's classes in If we can make changes down the road that make that workflow possible without any negative consequences against the workflow we actually endorse, then sure, but we're much more focused on making the recommended workflow better than devoting time to enabling a workflow we think is bad. Workflow aside; as far as I understand it creating one-off classes for every single component is actually bad for performance. The browser is faster at applying the same class to many elements than it is at parsing many classes that contain duplicate declarations and applying those one-off classes once or twice. Put another way, applying |
I apologize, wasn't intending to rile anyone up. The extracting components feature/docs is very similar to what I want to do, related to Semantic Remapping (which is my cake), my intention was to throw my hat in the ring of support for this feature/issue, and explain my reasoning for it. Had this issue not existed, I would have gone on my merry way and continue my search of a framework/solution that fits my workflow. While I'm sure I could use a refresher in best practices, my goal is not have 100 For example a component that styles form field blocks .field {
@apply .mb-4;
& > label {
@apply .hidden .select-none .uppercase .text-grey-dark .text-xs .font-bold .mb-2;
}
& > input {
@apply .appearance-none .w-full .py-2 .px-1 .border-0 .border-b-2 .border-blue-lighter .bg-transparent;
&::placeholder {
@apply .text-grey-dark;
}
&:focus {
@apply .shadow .border-blue;
&::placeholder {
@apply .text-grey-darkest;
}
}
}
& > .error {
@apply .hidden .text-red-light .text-xs .italic .py-2 .px-1;
}
} <!--
this is much more in line with my goals as there will be 100+ form fields easily
being able to update all of them with a tiny CSS tweak would be ideal
-->
<div class="field">
<label for="foo">Name</label>
<input id="foo" placeholder="John" v-model.trim="name">
</div>
<!--
vs
-->
<div class="mb-4">
<label class="hidden select-none uppercase text-grey-dark text-xs font-bold mb-2" for="foo">Name</label>
<input class="appearance-none w-full py-2 px-1 border-0 border-b-2 border-blue-lighter bg-transparent" id="foo" placeholder="John" v-model.trim="name">
</div> That CSS might eventually be extracted out into a global style rather than stored in a Vue |
Totally hear you; the funny thing is I used to be a big advocate of writing CSS that way a few years ago, here's a blog post for example: http://transmission.vehikl.com/using-bootstrap-as-a-semantic-mixin-library/ These days I disagree with everything I recommend in that article 😄 I wrote about what convinced me to take a different approach here if you're interested: https://adamwathan.me/css-utility-classes-and-separation-of-concerns/ That post basically outlines all of the motivations behind creating Tailwind in the first place 👍 Anyways, I am still interested in making this work eventually, it's just mega low priority because I will personally never use the framework that way, and this being something I built for myself that I can only dedicate a few hours a week to in my spare time, I'm naturally going to prioritize the stuff that's most helpful to me and best aligned with what I see being the vision for the framework. |
The best way I've found to handle repetitive class lists in Vue is to use CSS modules. They are easy to use in Single File Components and there's a way to do composition, even from the global CSS scope. So, something like this: <template>
<div>
<p :class="$style.myParagraph">Paragraph 1</p>
<p :class="$style.myParagraph">Paragraph 2</p>
<p :class="$style.myParagraph">Paragraph 3</p>
</div>
</template>
<script>
export default {
name: 'Example'
}
</script>
<style lang="postcss" module>
.myParagraph {
composes: m-2 p-2 border border-grey text-blue from global;
}
</style> will output the following HTML: <div>
<p class="Example_myParagraph__1Qr6s_0 m-2 p-2 border border-grey text-blue">Paragraph 1</p>
<p class="Example_myParagraph__1Qr6s_0 m-2 p-2 border border-grey text-blue">Paragraph 2</p>
<p class="Example_myParagraph__1Qr6s_0 m-2 p-2 border border-grey text-blue">Paragraph 3</p>
</div> and the following empty ruleset: <style type="text/css">
.Example_myParagraph__1Qr6s_0 {
}
</style> which could easily be optimized away with another PostCSS plugin. Here's a full runnable example. |
Hey @adamwathan I know that this is closed and I appreciate your comments about higher priority things, but I have what I think might be a "legitimate" use-case for this. I'm using v-autocomplete - it does some magic and creates elements on-the fly when included. I'm just instantiating the component, never touching those smaller divs and inputs. It's official recommendation for how to style and interact with the app is to style particular classes. So roughly my component looks something like this:
It's not necessarily a high-priority issue because I can just style those classes in my main.css, but ideally I'd like those style definitions to live right beside the only place they're ever used - in this AutoComplete component. |
Another use case is when you are restyling external components, where you don't have access to html. The best practice would be to have it in a component with component bound styling (css modules in react, or separate .sass file in angular). The only way to change the styling of an external component would be to override the css classes, but tailwind only allows that for the root stylesheet. |
I'm not convinced I want to merge this but opening for discussion.
This PR adds support for this syntax:
...which would generate:
This lets you do things like this:
The goal is to try and resolve situations like #150, where people want to use
@apply
to reference utility classes inside of scoped style blocks like in a Vue component.If anyone in that situation wants to pull this branch down and give it a shot, I'd be interested in knowing your feedback.