Consolidate CSS stylesheets
huyenltnguyen opened this issue · comments
This ticket is semi-related to freeCodeCamp/freeCodeCamp#52030.
In order to replace Bootstrap in /learn, we need to export a stylesheet from the component library to be used as the bootstrap.min.css
replacement. However, the stylesheet situation in the component library itself needs to be sorted out, and this ticket is to track this work.
Current problem
The library currently has multiple stylesheets. Their purposes aren't clear, they have many similar CSS rules and some of the CSS rules don't match, which could cause styling issue if the import order changes.
The stylesheets are:
- https://github.com/freeCodeCamp/ui/blob/main/src/colors.css
- Contains color tokens
- https://github.com/freeCodeCamp/ui/blob/main/src/base.css:
- Contains Tailwind styles as well as some Tailwind overrides
- Was created as part of the Tailwind setup, following this documentation: https://tailwindcss.com/docs/installation/using-postcss
- https://github.com/freeCodeCamp/ui/blob/main/src/global-element-styles.css:
- Is a subset of https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.css, containing element styles (styles that use HTML element selectors and affect elements directly)
ui/src/global-element-styles.css
Lines 1 to 3 in 3886b61
- Is a subset of https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.css, containing element styles (styles that use HTML element selectors and affect elements directly)
- https://github.com/freeCodeCamp/ui/blob/main/src/normalize.css
- Is used for resetting default browser styles
- Based on a comment in the file, the code was copied from https://necolas.github.io/normalize.css/3.0.3/normalize.css
Observation:
- Except for
colors.css
, the stylesheets overlap each other:Lines 16 to 18 in 3886b61
ui/src/global-element-styles.css
Lines 397 to 400 in 3886b61
Lines 40 to 42 in 3886b61
- (Not to mention that we do have custom CSS in the implementation of each component, in the form of class names, and those custom CSS rules override the base)
- The stylesheets also have some conflicting rules:
Lines 61 to 64 in 3886b61
ui/src/global-element-styles.css
Lines 150 to 155 in 3886b61
normalize.css
is supposed to match the original https://necolas.github.io/normalize.css/3.0.3/normalize.css, but I found some discrepancies: huyenltnguyen#1- Tailwind provides a preflight stylesheet out of the box, and the purpose of the stylesheet is similar to
normalize.css
. However, we turned this option off in favor of our custom stylesheets (global-element-styles.css
andnormalize.css
)Line 6 in 1e3252f
- From what I understand, we added
global-element-styles.css
andnormalize.css
in because we wanted to mimic the /learn environment in Storybook, in order to develop components for /learnLines 1 to 5 in 3886b61
- According to the import order, if there is a conflict between
global-element-styles.css
andnormalize.css
,global-element-styles.css
will take precedence.
- Only
colors.css
andbase.css
are bundled
What we want to achieve
For the component library itself, we want:
- A simplified styling strategy
For the library consumers, we want:
- The color variables
- A stylesheet for resetting default browser styles. This should be the same stylesheet that the component library uses internally
Approaches
I think we should start developing the component library as a standalone package, rather than having /learn influence it.
So I'd propose:
- Removing
global-element-styles.css
since this comes from Bootstrap, and includes a lot of CSS customization, not just reset - Using Tailwind preflight for browser styles reset (this means simply flipping the
preflight
flag totrue
)- Here is a comparison between
normalize.css
and Tailwind preflight stylesheets: huyenltnguyen/freeCodeCamp-ui@f81770d
(#2) - The differences between them aren't significant. But my concern with
normalize.css
is the library is not actively maintained, while Tailwind is an active project and its preflight stylesheet is written upon modern-normalize, which is... more modern. - We are already using Tailwind, so I think snapping back to Tailwind preflight would prevent stylesheets conflicts, and allow us to remove an additional dependency
- Here is a comparison between
- Removing
normalize.css
, if we choose to use Tailwind preflight
As for the styling strategy in the component library, I think:
- Each component should be styled using Tailwind classes. This should be the first option when it comes to styling a component.
- If we want to override Tailwind globally, the rules should be added to
base.css
. As the file name suggests, the file should house very basic CSS styles, and we want to be mindful when adding changes as they will require overrides on the component level, which would bring inconsistencies.
Implications for the Bootstrap removal in /learn
Given that we tried replacing the Bootstrap stylesheet with normalize.css
and the result was positive (ref), I don't think the Tailwind preflight would cause a catastrophe.
/learn has a huge global.css file that has all sort of CSS rules to override Bootstrap. I think those rules would help keep the UI intact (or mostly intact) when we swap the stylesheets. (The global.css
file also needs a round of review and cleanup as part of the Bootstrap removal, but that's a separate topic.)
@ahmaxed Not sure if it's your birthday, but this one is a surprise for you 😉
I'm tagging you for a review and inputs, but I can handle the implementation. I know it's a big wall of text, so please take your time, I'm not blocked by this issue.
It does not have to be my birthday. I always celebrate when I see well-thought out issues like this.
A few thoughts:
-
At the time, I came to a conclusion that normalize is the industry standard comparing to preflight and it would make removing bootstrap easier since bootstrap was using it. If any of these assumptions are incorrect, we should move forward with preflight.
-
There should be one set of presets, for the component library regardless of what is being overwritten in learn, etc.
-
I think the main reason we added normalize and global element styles is that when the elements were imported to learn they would look different from Storybook. Might need to remove them, and see how they effect storybook and learn.
Finally, this is a great blueprint for the stylesheet consolidation. At the same time, it might be helpful to evaluate how it would impact the migration. If we decide to do this before or after the migration, I am on board either way. It is a task that we need to take care of at some point.
Thank you for going through my wall of text 😄
At the time, I came to a conclusion that normalize is the industry standard comparing to preflight and it would make removing bootstrap easier since bootstrap was using it.
I had the same impression until I had to dig deeper and compare normalize
with Tailwind preflight.
From what I gathered:
- Tailwind preflight uses modern-normalize and adds a couple more rules
modern-normalize
is built on top ofnormalize
, but with some improvements- The latest version of
normalize
is 8, and it's been 6 years since the last update
There should be one set of presets, for the component library regardless of what is being overwritten in learn, etc.
Just to clarify, by "presets", do you mean custom CSS rules and the rules would override the base Tailwind styles?
I won't object that, if that's what you mean 🙂 I think there are a couple of rules that we need to set to the component library, for branding and accessibility. Off the top of my head:
- The focus outline style - I believe we have been manually adding this to each interactive component (button, input, link, etc.), but I think this rule should be global
- Link underline - this is a custom rule and not from the original
normalize
stylesheetLines 43 to 44 in 379560e
- Font family - we do have Lato set in the library, but not Hack-ZeroSlash
Anyway, we can discuss what global styles the library should have separately. For now, I only need to confirm if I understand the idea correctly.
So I'll go ahead and experiment the proposed approach.
The steps would roughly be:
- @freecodecamp/ui
- Try enabling Tailwind preflight
- Remove
global-element-styles.css
andnormalize.css
, and probably cherry-pick some custom CSS from those files tobase.css
if the components look weird on Storybook - Bundle and release the new
base.css
(I actually don't need the new changes to be released in order to test, I just need the file content so that I can add to /learn locally)
- /learn
- Replace the Bootstrap stylesheet with the new
base.css
- Check and fix UI regression (we should pair this work with the CSS selectors/overrides cleanup in
global.css
, so that we don't have to manually testing things twice)
- Replace the Bootstrap stylesheet with the new
I meant normalizers by presets, and look forward to hear about your progress with the experimentation.
(Please ignore. I'm using this comment as my notepad.)
Rules to be removed from base.css
- Border width reset:
Lines 7 to 14 in 9698a82
- This is covered by Tailwind preflight
- Webkit tab highlight color:
Lines 20 to 24 in 9698a82
- Tailwind preflight was updated and now has this rule covered: https://github.com/tailwindlabs/tailwindcss/blob/f1f419a9ecfcd00a2001ee96ab252739fca47564/src/css/preflight.css#L39
Rules to be added to base.css
- Link underline:
Lines 43 to 44 in 9698a82
- Focus outline:
Other notes
- We only need to define
font-family
intailwind.config.js
. Tailwind automatically specifies which element should have which fontLines 90 to 93 in 9698a82
html
getssans
: https://github.com/tailwindlabs/tailwindcss/blob/f1f419a9ecfcd00a2001ee96ab252739fca47564/src/css/preflight.css#L36code
,kbd
,samp
, andpre
getmono
: https://github.com/tailwindlabs/tailwindcss/blob/f1f419a9ecfcd00a2001ee96ab252739fca47564/src/css/preflight.css#L115
- Heading elements should not have font size specified in
base.css
, as each component may have its heading in different size (Modal
is an example).- For now, we should just set the font size on the component level.
- In the future, we might want to have text components (
Title
,Subtitle
,Caption
, etc.), each has a fixed font size and accepts anas
prop that allows changing the heading level.// Pseudo code <Caption as="h1" />
- The custom
.sr-only
styles can be removed as Tailwind already supports this class