Bootstrap: Split utilities from property utilties and get more control over generation of property utilities

Created on 26 Feb 2019  路  9Comments  路  Source: twbs/bootstrap

Split utility groups

In v4 we have 2 different kind of utilities that are a bit mixed in the documentation and in the code.

The first group is what I call the normal utilities. These utilities have more than one property and don't have the !important suffix. These utilities are:

The second group is what I call the property utilities. These utilities typically have one property (except for .mx-*, .my-*, .px-* and .py-* utilities) and always have the !important suffix.

I think we should split these utility groups. Not sure how we should call them, but for now I'll call them the utilities and property utilities.

More control over property utilities

We got a lot of requests and PRs about the generation of more responsive properties (for example responsive border utilities https://github.com/twbs/bootstrap/issues/28191) but we can't just add utility classes for all the properties because this will increase the size of the css too much.

On the other hand there's a need for more control over the generated code (which is also mentioned in https://github.com/twbs/bootstrap/issues/25941).

On yet another hand (let's just assume there's a third hand somewhere) I sometimes have the need to extend the utilities for more properties like opacity or other properties Bootstrap doesn't cover with utilities.

To tackle this problem I've started developing something to gain more control over property utilities, with some kind of API where you can choose whether you also want to have responsive utilities, but before I'm going to continue with it, I'm going to check for some other opinions here. It 'll probably also need some solid documentation to explain it all.

I'm working under v4-dev-mc-poc-property-utilities, the branch will need to be renamed, because this will not land in v4, but maybe something for v5 if I can get to something ready in time. You can see the diff here: https://github.com/twbs/bootstrap/compare/v4-dev-mc-poc-property-utilities?expand=1#diff-1500afbbcf5fcafdd95fddb9b709de83 scss/_property-utilities.scss and scss/utilities/_property-utilities.scss will probably be the most interesting files.

What do you think?

@ysds @gijsroge @twbs/css-review

css v5

Most helpful comment

Yaaasssssssss this is the kind of discussion I've been waiting for! :D

I've been thinking about this on and off for awhile now. I want to keep Bootstrap, especially it's most powerful features as approachable as possible to the greatest number of people. As it stands now, this feels a bit too verbose, which is a bit of a turn off for me. That's from a maintainer perspective, but as I think about how much work would be required to remove, add, or change one of these, I wonder if it could be simpler.

Here's the idea that's been floating around in my head鈥攐ne giant Sass map that we loop over to generate all our responsive utilities. Each nested map could have additional controls for responsive variations (default false for file size), inclusion of print variants (default false), and ideally even overrides for which breakpoints to include (default all, optional to declare specific ones from the $grid-breakpoints map).

$utilities: (
  display: (
    class: d,
    values: none inline inline-block block table table-row table-cell flex inline-flex,
    responsive: true,
    print: true
  ),

  font-weight: (
    class: text,
    values: (
      light: 100,
      lighter: lighter,
      normal: 400
      bold: 600,
      bolder: bolder
    ),
    responsive: false, // Default value perhaps?
    print: false // Default value perhaps?
  ),

  // and so on...
) !default;

Thoughts on a direction like this?

All 9 comments

This is some great work Martijn 馃

Maybe something like helpers & utilities?

My understanding of the word "helper" in this context is that it provides more than one property to assist in achieving something.

About the need for more control over utilities.

I think the extending property utilities is impressive and a smart way to build utilities and giving users a way to come up with own property utilities. You pretty much nailed this imo.

However I would give the idea of providing a full blown optional pre-made utility set a though. Otherwise, people who intensively uses utilities are required to build or copy paste their own utilities over and over again (me included 馃榿).

This however needs to be in line with the vision of Bootstrap, because it will start to look a lot like a utility framework (which is great thing imo).

Maybe the only thing I can see not working with this is generating responsive helper classes, for example the sticky top helper could use the same benefits as utilities regarding responsive classes. I can see a use case that I would only want the sticky element to be sticky on desktop.

Something to think about maybe?

One possible solution would be to just refactor those existing helpers (#28352) with responsive classes 馃榿

About the need to provide a way for users to remove unused code

Maybe another way of tackling this is to provide a small section in the docs on how to use PurgeCSS instead of Uncss. I know PurgeCSS has the option to parse javascript for classes so dynamic classes are discovered as well.

extra info on PurgeCSS docs

This would basically parse all your templates, javascript, Sass, to discover all possible used classes and removes the other ones. Very good stuff if you are heavy on utilities 馃槂

Other stuff I might consider refactoring

Confusing naming collisions with .btn-sm, .btn-group-sm, .custom-select-sm, .modal-sm, .rounded-sm, .shadow-sm, etc...

Especially .shadow-sm, .rounded-sm are super confusing regarding the responsive naming convention used in the current version of Bootstrap.

I very much like the way Tailwind CSS uses a responsive namespace, like sm:, md:, etc.. maybe something to look into, i'm not sure what the intend of v5 is, but this would cause a lot of breaking changes.

An other possible solution for this is to rename the .btn-sm, .modal-sm to .btn-small, .modal-small. But I personally prefer the namespacing to make it extra obvious. Or even do both, that would make it even more clear. So sm:shadow-small, lg:rounded-small.

But maybe this should be a separate discussion..

Maybe something like helpers & utilities?

Interesting, those names are definitely better.

However I would give the idea of providing a full blown optional pre-made utility set a though.

We could do that. Maybe we should also add a enabled key to the utility maps so that they can easily be enabled/disabled. This way we can have some control over what we enable by default and what we don't.

Maybe the only thing I can see not working with this is generating responsive helper classes

We'll need to find a way to control this. Generating responsive helpers could easily increase our default file size a lot if we do it on all helpers.

PurgeCSS

Imo this is not something we should cover. We can also suggest people should use http2 server push or inline critical css or combine all css in one file to make less requests but in the end we just want to provide css & js components/ utilities. How people use it or what workflow they use is up to them.

Namespacing

We're not planning on reviewing our namespacing in v5. This will indeed introduce a lot of breaking changes. But I agree with you, the way Tailwind CSS is handling breakpoints is more consistent than the way we do it. I guess this is something we can rediscuss after v5 is launched.

@MartijnCuppens Thank you for requesting my comment.

Intuitively, your idea absolutely improve the flexibility of the utilities 馃憤 But, please give me some more time to think about it, thanks 馃憖

@MartijnCuppens

We'll need to find a way to control this. Generating responsive helpers could easily increase our default file size a lot if we do it on all helpers.

Yes indeed, would probably be better to make the responsive stuff optional for these helpers.

Imo this is not something we should cover. We can also suggest people should use http2 server push or inline critical css or combine all css in one file to make less requests but in the end we just want to provide css & js components/ utilities. How people use it or what workflow they use is up to them.

Yeah this is not what I meant I explained it poorly. I would definitely not write a full blown guide (sounds like a nightmare to maintain 馃槰), more like "Hey btw, if you are using lots of utilities you might want to look into reducing the footprint of Bootstrap by using a tool like PurgeCSS. Good luck!"

But maybe this is even too much, although * if * Bootstrap would go on the route of providing lots of utilities this might be a necessaty to mention it somewhere.. not sure.

We're not planning on reviewing our namespacing in v5. This will indeed introduce a lot of breaking changes. But I agree with you, the way Tailwind CSS is handling breakpoints is more consistent than the way we do it. I guess this is something we can rediscuss after v5 is launched.

馃憣 good to know!

Since I read the SCSS and CSS carefully, I took time to comment.

I admire @MartijnCuppens's wonderful job! Lets go forward with this way 馃憤

This not only makes the utility more control but also reduces the file size by reducing duplicate @media.

I write down the points I care about:

  • Increased the code of margin/padding classes by separated all selectors.
  • Is there a chance to adopt * { border-color: xxx; } like the tailwind's preflight?
  • There may be some people who dislike SCSS becoming programmatically.

Increased the code of margin/padding classes by separated all selectors.

I'm aware of that. Although it increases the amount of code, it decreases the amount of selectors, so it's a bit of a win some lose some scenario. I have been thinking about not generating the negative margin utilities by default because they generate quite a lot of css. Maybe one day margin-block and margin-inline will help us getting the left/right and top/bottom properties combined, but browser support is pretty unexisting.

Is there a chance to adopt * { border-color: xxx; } like the tailwind's preflight?

I also discovered this last week and think we should do this (I would add it in the existing * selector though). I guess we can isolate this in another issue/pr.

There may be some people who dislike SCSS becoming programmatically.

Yes, that's true. But currently there's nothing to control the utilities at all. The configuration will look complex for those who are trying to learn scss. That's why I wouldn't include this in the _variables.scss file, there should be a separate utility configuration file for the "experienced" scss developer so that people won't get too overwhelmed by this. We should also document this in an _advanced usage_ section I guess.

Yaaasssssssss this is the kind of discussion I've been waiting for! :D

I've been thinking about this on and off for awhile now. I want to keep Bootstrap, especially it's most powerful features as approachable as possible to the greatest number of people. As it stands now, this feels a bit too verbose, which is a bit of a turn off for me. That's from a maintainer perspective, but as I think about how much work would be required to remove, add, or change one of these, I wonder if it could be simpler.

Here's the idea that's been floating around in my head鈥攐ne giant Sass map that we loop over to generate all our responsive utilities. Each nested map could have additional controls for responsive variations (default false for file size), inclusion of print variants (default false), and ideally even overrides for which breakpoints to include (default all, optional to declare specific ones from the $grid-breakpoints map).

$utilities: (
  display: (
    class: d,
    values: none inline inline-block block table table-row table-cell flex inline-flex,
    responsive: true,
    print: true
  ),

  font-weight: (
    class: text,
    values: (
      light: 100,
      lighter: lighter,
      normal: 400
      bold: 600,
      bolder: bolder
    ),
    responsive: false, // Default value perhaps?
    print: false // Default value perhaps?
  ),

  // and so on...
) !default;

Thoughts on a direction like this?

This idea is a revolution!

I now use the helpers & utilities names and use the $utilities map now like @mdo proposed. This was indeed a lot less complicated.

responsive: false, // Default value perhaps?
print: false // Default value perhaps?

This is already the case now.

I'll make a PR draft since it looks like this is an interesting concept.

Was this page helpful?
0 / 5 - 0 ratings