Moving to GPS method
Which methods live on? Which methods die?
Great advice from helpful articles
Trialling out GPS, some old stuff from ECSS, and my idea: "Thema styles".
I'm not entirely convinced yet about GPS-style css, but I DO believe in minimalism and increasingly have a brutalist mindset. While it's nice to have a fancy UI, it isn't necessary, and it's a real bugger to maintain and update as the code complexity increases. CSS is definitely not one of the nicest languages to code in.
- Cut Code Down (an old opinionated site)
- GPS concept (global, page, section)
- ECSS (the original method)[^1]
- CSS styleguides from Google and MDO
The general idea
For example, with ECSS you'd write a special .scoped-Class for each and every item. This is a big no-no in GPS and it advocates for simplifying the class names, using raw html elements to style, and reducing repetition. However, some naming conventions are necessary ...
What about <div>s when there's no relevant HTML element to use? It's quite helpful to have some visual indication when you're scanning the css document as to what component lives where. If you don't have a nested element such as .gl-Card header, and you've got two nested div > div that gives no information.
<!-- simple naming convention -->
<div class="split">
<div class="split-left">
...
</div>
</div>
<!-- ECSS naming convention -->
<div class="gl-Section"> <!-- If it's a global element GPS condones scoping as `.gl-`obal -->
<div class="gl-Section_Left">
...
</div>
</div>
The general idea with GPS is to scope things as .gl-obal, #page level, or section (nested under it's page). It aims to reduce bloat that BEM and ECSS bring with (some would say) unnecessary class names. The problems that seem to crop up when changing to this format are:
-
If you have a fragment (like
#answer) which is just for linking to, where does this live? - Are there any instances where inheritance becomes a potential problem? (unique ECSS classes solved this problem)
-
If templates are slightly different, how do we deal with these? (Missing!
div#answeris in a different position) -
Is styling raw HTML elements always preferable to adding an explicit
.classor not?- Design-systems will naturally have parent and child elements ... not all of them explicit as to their purpose as raw html
-
.gl-Form pseems a bit weak compared to more explicit.gl-Form_Errorwhich is far more explicit ... - See here for an example of before and after: using a flat class style vs nested style.
- I guess the GPS way is to just give it a singular class
.gl-Form .error?
-
Having to constantly create class names is a pain, but sometimes explicitness is preferable:
- If not nested,
gl-Card_KeyPointtells me a lot about what it is and who its parent is. - I guess it's unlikely elements will be moved around, but you'd potentially lose some of their styling if so:
- i.e:
.gl-Card > pwould break if you movedpinside adiv. Perhaps this is just something you have to be aware of.
- i.e:
- If not nested,
- How to avoid any inheritance issues rising from code order?[^1]
-
Should placeholder elements, classes, or ids be discouraged?
- For instance, a
.gl-Wrapperclass that hasn't been styled yet. Is it really needed?
- For instance, a
-
Do we prefer flat style css or nested?
-
.gl-Card { .wrapper { ... } }vs.gl-Card .wrapper -
.gl-Card h1 code bseems a bit too nested for my tastes, but perhaps it's just habit.
-
-
If we have a
.nightmodeclass, should all override styles live together, or style in-place multiple times?- For example, have multiple instances of night mode where it's needed:
.gl-Card { .nightmode & { ... } }? - The same goes for
@mediastyles. They can add up pretty fast (see Print First CSS)
- For example, have multiple instances of night mode where it's needed:
-
Reusing templates is better, but sometimes this isn't possible.
- Slight variations in templates mean they share
.gl-styles except for very slight changes. - With ECSS we'd completely separate (and duplicate) those styles into two distinct css files.
- Remember Elm Lang's lessons: just because something is similar does not mean it is the same!
- Slight variations in templates mean they share
-
Another subtle example is our
#demopage. It's serving two distinct templates but they're basically exactly the same:[^2]- At what point does a
.gl-element become a distinct#page #sectionand vice-versa? - Should I be naming
#demoa.gl-Demorather than a distinct#pagetype? - Can
#pageelements be repeated or must they be unique?
- At what point does a
- Another what-if in a similar vain is ... is it every OK to style a
.gl-element under a#pagelevel one?[^3]- You could style it in the
global-element.lessfile like.gl-Element { #page & { ... } } - Or otherwise you could convert a
.gl-Elementto a#page #elementbut that's waaaaay overkill in my case. - Or, you could add a
-variantclass, such as.gl-Element-changed...
- You could style it in the
TL;DR
One of the biggest upsides of using ECSS is isolation and descriptiveness.
.gl-Card_KeyPoint-selectedis very descriptive. You lose that a bit with GPS. So whatever you do, make rules concrete.
- Use decent HTML5 tags where possible to style content. Make them obvious and accessible.
-
section,header,aside,navare descriptive enough, sort of. -
pandulfeel a bit weaker, especially if it's a design system element (is it descriptive enough without a class?)
-
- If
<div>is used, and it's a child of anotherdiv, consider naming them as parent and child somehow. - Ideally you'd want to style as much as possible in your raw html
/partialsfolder.- For our Anki cards, we really only have one style of heading, but that's inside a
.gl-Card. - Are we ever going to use a
h1outside of this context? How much do we style in/partials? - To me
.gl-Cardis a component. I'm not sure it should live as the specimen file (basich1 -> h6styles)
- For our Anki cards, we really only have one style of heading, but that's inside a
- #144 — be consistent!
- When dealing with similar but not the same
.gl-,#page,#sectionelements, WE NEED A PLAN! - Unique
#sectionelements should always be wrapped in a#page
[^1]: One example of this is <code> styling. We want to style the default, but it also needs styling in a few different occasions: Within a <header> element, inside <pre> tags (specifically with .sourceCode which is a Skylighting class), so on. For h1 code we want font-style: inherit but where does that code live? We're only really using headings inside of our .gl-Card but we might need header styles as regular headings at some point. Do we style the raw HTML or the .gl-Card header h1? And if we're placing "inherit" in our raw html styles (in /partials), will code inherit the styles from our .gl-Card headings too? I don't know! Test it out!
[^2]: Im not sure that GPS gives us definitive answers to these problems. It's kind of subjective in these cases.
[^3]: This is another area with nuance that we've got to be aware of. At what point do you split out a .global style into a different (but similar) global style? I think it's generally that a #section should be UNIQUE. But it might be similar to a global design component. Again, we don't worry about this with ECSS.