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

Should @apply omit the !important or not #133

Closed
wants to merge 1 commit into from
Closed

Should @apply omit the !important or not #133

wants to merge 1 commit into from

Conversation

HellPat
Copy link

@HellPat HellPat commented Nov 7, 2017

Hey there,

I am a huge fan of !important as you already noticed ;-)
In #99 there is an ongoing PR to add some !important functionality to tailwind.

I am not sure how to use it in combination with @apply.

There are 3 Possibilities.

1. remove !important of declarations from @apply

Input

.a { color: red !important; }
.b { @apply .a; }

Output

.a { color: red !important; }
.b { color: red; }

The !important is removed.
I can add it again if I do something like that.

Input

.a { color: red !important; }
.b { @important { @apply .a; } }

Output

.a { color: red !important; }
.b { color: red !important; }

2. keep !important of declarations from @apply

Input

.a { color: red !important; }
.b { @apply .a; }

Output

.a { color: red !important; }
.b { color: red !important; }

I have no possibility to remove the !important easily of class .b

3. keep !important of declarations from @apply but allow removing

Input

.a { color: red !important; }
.b { @apply .a; }

Output

.a { color: red !important; }
.b { color: red !important; }

Input

.a { color: red !important; }
.b { @unimportant { @apply .a;} }

Output

.a { color: red !important; }
.b { color: red; }

Opinion

In my opinion utilities used in CSS directly should be important.
One should not be able to overwrite it easily (See The Importantce of !important by csswizardry).

When used in objects, the Base-Objects should not be altered but be immutable.
Instead it should be modified through modifiers.
This is The open/closed principle applied to CSS.

(For "modifier" see BEM, this links is just for documentation purpose when somebody less experienced stumbles upon this issue)

If @apply copies !important the modifier cannot be modify the base-element easily.
So Option 2 fails here IMO leaving options 1 and 3 there.

Solution 1 has some "magic". I don't like magic.
But I like the solution more that Number 3 because it does not need any extra effort to write the correct CSS.

What do you think?

I added a failing test with my favor expectation.

@mkarnicki
Copy link
Contributor

Hey, this is great :). I think option 2 makes most sense for start and option 3 optionally next (as a separate PR). Similarly to you, I dislike the 'magic' from option 1. Cheers man!

@HellPat
Copy link
Author

HellPat commented Nov 7, 2017

@mkarnicki Option 2 is the "don't do anything" option and the current behavior.
My problem here is, that it is not possible to remove the !important which was "inherited" from the utility. (I always mark my utilities with !important.

In short:

  • Option 1 => everything possible, sensible defaults, con: magic
  • Option 2 => no magic, con: missing features
  • Option 3 => everything possible, no magic, con: no sensible defaults

@mkarnicki
Copy link
Contributor

There's a separate bug or comment (perhaps even yours) that suggests that @imporant could be applied to selection of utilities, and I guess that would be the way out. Until then, Option 2 makes most sense. I see no sense in applying a utility - which you know is !important - to later not want that !important part in your new CSS class. Perhaps I don't have enough experience with CSS to see the value in what's missing from 'option 2', which I'm completely comfortable with. 👍

@HellPat
Copy link
Author

HellPat commented Nov 7, 2017

@mkarnicki the problem only appears if you extract components out of your current css. Imagine what happens if all your utliities have !important.

This would result in

.btn-blue { color: blue !important; }

which is good. But if you have a base-component and modifiers this can be tricky.
Imagine.

Input:

.btn { @apply .bg-grey; }
.btn-blue { color: blue; }

Output:

.btn { color: 333 !important; }
.btn-blue { color: blue; }

=> fail. Now you have to add !important yourself, or you're forced to use the @applywith an other utility-class (which does not even exist)

@mkarnicki
Copy link
Contributor

Makes sense. So this would work if your input was either:

.btn { @apply .bg-grey; }
.btn-blue { color: blue !important; }

or

.btn { @apply .bg-grey; }
.btn-blue { @apply .blue }

assuming there's .blue utility (which there is yet none).

I think:

  1. If you're a fan of making utilities important, you can live with adding !important to your CSS (since you already wrote it with CSS and not Tailwind classes).
  2. I anticipate it's only a matter of time when we have color classes in Tailwind. I understand this affects all utilities, but since all would be !imporant, there's no problem.

After having this conversation I'm even more happy I'm dropping a CSS kit I purchased in favor of Tailwind, because having no !imporant classes and having tailwind utilities at the end will save me a lot of headache :).

@HellPat
Copy link
Author

HellPat commented Nov 7, 2017

because having no !imporant classes and having tailwind utilities at the end will save me a lot of headache :).

Only if you don't have to combine tailwind with legacy CSS.
If the legacy CSS already has high specificity you have to add !important to all yout utilities no matter if you have tailwind at the end of the file.

since you already wrote it with CSS and not Tailwind classes

Tailwind-Classes are Utility-Classes, so i added !important to all of them

@adamwathan
Copy link
Member

I personally like option 1 the best, which is very easy to implement just by making sure our PostCSS plugins run in the right order, and doesn't feel like magic to me if you have the correct mental model that @important rules are processed last in the chain.

If you have !important hard coded into a utility it would get included, but if you are only decorating a set of utilities with @important {}, the mixing in would happen before processing those rules.

Imagine @important was a separate PostCSS plugin outside of Tailwind. It would be applied after all of Tailwind's processing, thus any utilities defined at the time @apply rules are processed that did not have !important applied, would not have !important mixed in to the class where it was used.

To me this is the most useful way for this to work.

Don't forget, you can also use config() to access any Tailwind values directly without using @apply.

For example, you can replace this code:

.btn {
  @apply .bg-grey;
}

...with this code, and achieve the same result:

.btn {
  background-color: config('backgroundColors.grey')
}

So you always have that escape hatch available.

I'm going to close this for now as its really part of the discussion around adding @important {} in general, and that PR is still open.

@adamwathan adamwathan closed this Nov 7, 2017
DCzajkowski pushed a commit to DCzajkowski/tailwindcss that referenced this pull request Jul 23, 2019
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

Successfully merging this pull request may close these issues.

3 participants