Note: Please remember, this is WiH, Written in Haste! The goal of this post is to get information out of my brain…will edit later, probably :)
I have not been so good about getting this installment out in a monthly fashion, but I have published a few posts in between including one about accessibility and one about a handy Stylelint rule (but also one that should be used with caution).
Before we dive right in, allow me to also give a brief recap of last month’s Designgineering Chronicles:
- I discussed the reasoning behind choosing my flowery job title: Senior Design Operations Engineer
- I learned an important lesson, “Perfect is the enemy of complete”, especially when it comes to something that just need to work
- Lots of progress was made on PMCSS Standards, our CSS architecture and naming conventions
- I discussed Stangler Vine refactoring and the use of utility classes in layering new CSS into legacy codebases
- I had an exciting meeting with some product folks about building out core components, but that is on pause for the time being
- There were a lot of things in the “coming up” section…
The biggest news over the past couple of months was the launch of the design refresh for IndieWire.com, a project which has been the test bed for many smaller projects including:
- Development of a pattern library
- Determining PMCSS Standards (our CSS architecture and authoring guidelines)
- The first site to use the centralized build step a.k.a
pmc-build-utils
All of these items are new for PMC, and while I’m well versed the topics, to be honest, I’ve never tried to apply them to websites as large as those at PMC. It’s definitely been a learning experience!
IndieWire Challenges
In particular with IndieWire, a challenge was figuring out how to deal with “patterned” styles and legacy styles on the same page. The project was initially supposed to be a refresh of only the homepage. From the get-go, I had planned for a template to either use patterns or not use patterns. It didn’t work out like that.
Mixing Patterns and Legacy Styles
The single homepage refresh soon turned into two additional templates, a redesigned footer, and support for the newly designed widgets on legacy templates. Oh, and the header and menu should use the legacy styles, even on the fully refreshed templates.
As I mentioned in the last Designgineering Chronicles, we had a legacy/
directory in the pattern library to handle importing legacy styles for the header and menu on pattern templates. We ended up doing something similar in the legacy Sass itself and had a refresh-2018/
directory that imports any patterns that are needed for the widgets, and a refresh-2018.css
stylesheet is compiled and enqueued after the main legacy CSS.
What didn’t work
For the widget CSS on the legacy templates, my initial thought was to only include the CSS that was needed from any given pattern via copy and paste and comments rather than importing the pattern in its entirety. The ended up being a) difficult to maintain, and b) confusing when you think you can use an existing variation of .c-title
but then realize that variation hasn’t been imported.
We ended up @import
-ing each pattern’s file instead of doing this copy/paste strategy whose only benefit was saving a few bytes from the size of the CSS file. There are much bigger performance fish to fry than the size of the stylesheet, that’s for sure.
Comments, I like them
I think the most important part about this practice of combining old and new styles, is to make sure it is know exactly the purpose of every declaration regarding backwards compatibility. That way when there comes a day to fully refresh the site design (which probably won’t be for a good while, unfortunately), we will know exactly what to check when removing CSS.
For example, this block contains pattern selectors scoped inside a legacy selector:
// Pattern overrides relevant for mulitple widgets.
.right-side {
// Overriding a margin-top: -1rem from legacy styles.
.o-story-list {
margin-top: initial;
}
// Provides a higher specificity then legacy styles selector ( .right-side h2 ) to apply identical pattern library styles.
.c-heading {
display: block;
font-size: rem-calc(35);
}
// To override default margin -16px.
.c-tagline {
margin-top: 0;
}
// To fix the line height with link titles.
.o-tease .c-title {
line-height: 1.25;
}
}
I do want to add a note about comments in general. I personally like lots of comments, and often my feedback to other developers is to add a comment if I needed to ask about it in code review. I recently read this article about self-documenting CSS from Keith J. Grant β some of which I agree with, but not all (thought it of course depends on the day). On one of the “tech leadership” calls at work we had a discussion about self-documenting code. There opposing opinions, for sure, but it seems the consensus in the end was that there is no such thing as self-documenting code that stands the test of time. The default should be to write comments. They are free, after all!
Patterns and Design Anomolies
One of the most frustrating experiences is trying to figure out fitting a non-patterned design into a pattern library. We could call that a design anomoly meaning the design varies from the spacing, layout, or sizing conventions that accounted for 95% of other instances. It’s that one thing that just different enough that it doesn’t fit into the existing system.
This happened in one particular place in IndieWire, a little call-to-action newsletter widget that appeared both in the sidebar and in a full-width context on the homepage. It also contained this little paper airplane illustration that turned out to be quite a little nuisance.
Ethan Marcotte wrote When patterns get weird. which explains this conundrum really well β I highly recommend reading that article closely. Chris Coyier calls them “one-offs”, and links to Ethan’s articles and a few others in this post.
Contextual Styles
This is a tough challenge in any system. Dave Rupert phrases it nicely, and this article outlines it well:
.some-context .thing { /* special rules and overrides */ } Does that go in thing.css or some-context.css?
β Dave Rupert (@davatron5000) February 7, 2017
To summarize the article (from memory, this might include more options) few options for dealing with this are (always in thing.css unless using a BEM Mix):
- BEM Mix β
.o-story__title
applied to.c-title
(we started with this but it seemed to add too much complexity to the naming) - Sub class:
.o-story .c-title
β Used this then one of the developers pointed out it is kind of an anti-pattern since we want to retain low specificity. This is true. - Contextual modifier β
.c-title--story
- Atomic modifiers or utilities β.
.c-title--normal.c-title--minor.u-margin-tb-0
We are using a mixture of the bottom two and it’s…okay. This will require some more standardization, but I’m leaning towards keeping it atomic and unrelated to context where possible.
What’s next for IndieWire?
Well…not much. IndieWire will likely remain a Frankenstein of patterns and legacy styles for quite a while.
When we started to talk about the launch in detail I asked something like, “What is the plan for refreshing the rest of the site and expanding the pattern library accordingly?” I really wanted to do this while the codebase was fresh in our minds, and the momentum still there. The answer was an unfortunate one: probably not for a long time, if ever. The IndieWire editorial team and stakeholders will be happy for a while, and there are 15+ other PMC brands to tend toβ¦
While this is definitely not the answer I wanted, this is where the “principle of good enough” comes in, I suppose! But we can also rephrase this question to…
Documenting Patterns with Boxes
I like to refer to writing CSS a “programming boxes” because that’s what it is. As I was doing some general clean up in the pattern library, it occurred to me…why isn’t the documentation for boxes, well, boxes? That led to examples like this for object and layout patterns:
So far, I like this a lot because objects and layouts are not UI elements, they contain UI elements and they should only contain declarations related to that responsibility. I started this practice after the initial creation of the patterns, but I will definitely test this out at the beginning of the next project to see if it is useful in development.
IndieWire Pattern Library may morph into PMC Patterns
So…although development on IndieWire itself will be coming to a close, that will not be the case for the pattern library!
Much of the naming and structure that came out of IndieWire can be adapted to work on any PMC property. I’m currently figuring out exactly what centralized front-end code will look like, but it seems like migrating reusable parts from the IW pattern library to whatever that centralized place is will be the way to go.
That repo of centralized front-end will be a kind of store or inventory of patterns any brand can use, no matter the state of the existing codebase. In some cases, those patterns may equate to ready-to-roll components, such as the PMC Footer that is on every site, and in other cases, I think they can be more developer tools such as .u-crop
or a specific layout like .l-showcase
.
Architecture-wise, I have been playing around with an npm package called pmc-packages
that contains the reusable chunks of Sass and JS. A theme can import
any Sass partial or JS file from the pmc-packages
node_module into it’s local entry points. Before we get into the details of that, let me mention…
webpack and I are friends now, good friends
In previous Designgineering Chronicles installments, I wrote about plans to only use node-sass for compiling Sass in projects. Since then, I put some effort into actually trying to understand webpack and hey…it wasn’t that bad! With the help of Sayed Taqui from rT Camp, an agency PMC does a lot of work with, we got pmc-build-utils
into a solid place where it is stable, supports project-level configuration using webpack merge, and comes with an isReact
configuration flag that will run a React-ready build configuration. The other developers on my pod pulled down the repo and got it running in multiple different brands, so I think it’s ready to be officially versioned.
The build utils are not public on npm (not sure why…but oh well) so they are installed from a private PMC Bitbucket repo. Git tags can be used for versioning, so in any given package.json, the devDependencies would include:
{
"pmc-build-utils": "git+ssh://[email protected]/penskemediacorp/pmc-build-utils.git#v0.1.1"
}
I need to figure out the best way to approach versioning β I think this iteration could be 1.0, but I hesitate to express it as totally stable…though I’m not sure why. It is being used on two different projects already, that sounds stable, right?
Bundling and chunking in webpack 4
Without proper chunking i.e. using @import
in Sass files, I found the vanilla node-sass version to be faster, but with proper chunking (e.g. importing .scss
partials directly into .js
entry points) webpack is around 30 times faster β I’m talking ~1500ms build times down to ~20ms, depending on the size of the chunk. That’s a noticeable improvement! It will require some additional mental overhead to handle imports at a more granular level, but I think for sites this large it will be worth it.
Webpack provides the ability to create aliases for file paths, so including the low-level patterns in a module could look something like this:
// PMC Patterns
import '@pmcss/layouts/l-features.scss';
import '@pmcss/objects/o-story.scss';
import '@pmcss/objects/o-story-list.scss';
import '@pmcss/components/c-title.scss';
import '@pmcss/components/c-tagline.scss';
import '@pmcss/utilities/u-text.scss';
import '@pmcss/utilities/u-flex.scss';
import '@pmcss/utilities/u-grid-3-pack.scss';
// Local CSS
import './video-gallery.scss';
Or…it could even be like this β assuming we build out PMCPatterns
to parse the array down to imports:
// In video-gallery.js
// PMC Patterns
PMCPatterns( [
'l-features',
'o-story',
'o-story-list',
'c-title',
'c-tagline'
'u-flex',
'u-text'
'u-grid-3-pack'
] );
// Local CSS
import './video-gallery.scss';
Then, video-gallery.js
β or the module entry point β is imported into a top-level entry point, or bundle. In IndieWire I’ve tested out an unusual approach to bundling based on the WordPress $template
global. In addition to enqueueing a common.css
and common.js
that contains, well, common scripts and styles, we can include template-specific assets according to their queried template instead of handling it manually with a conditional based on logic like is_home()
or is_category()
.
Let me show you what I mean (if you are reading this and are like, “wow, Lara, don’t do that” please tell me because it seems to be working and like a pretty cool solution, but I definitely don’t know everything so yeah…). This is inside a function added to wp_enqueue_scripts
:
Other cool stuff going on
Naming Algorithm and Naming Decision Tree
I made an extensive decision tree for naming components. It might be too extensive to be useful, but it’s comforting that the flow of selecting names is not so specific to my brain that it can’t be put into a logical diagram.
I also came up with an algorithm for naming single declaration utility classes. It’s pretty simple and pretty cool.
Architecture Committee
Here’s something super cool…I’m on the Architecture Committee at PMC! What is an architecture committee? Great question. In short, an architecture committee is a group of individuals β usually at a big company β that are in charge of creating or curating coding standards and the adoption of new libraries and frameworks. At PMC, this group is comprised of five working engineers (not folks in leadership roles) with a diverse range of technical experience.
I’m going to go on the record and say it’s really, really cool that me β the CSS/templating specialist β is included alongside Java and PHP programmers in this committee. I am very lucky to have my job!
Algorithms of CSS v2.0
Another super, super cool thing β PMC gave me a bunch of time to work on my talk! I just delivered the Algorithms of CSS v2.0 at WordCamp US in Nashville. It was a great success, and I’m very excited about how this topic has evolved and how relevant it is to my work at PMC.
What’s coming up?
There is a big project coming up that I’m not sure I should announce quite yet! So I will leave this section largely sparse for now.
Generating PHP templates?
One important technical challenge though, is figuring out how to have the pattern library use the same markup as the WordPress theme. I’ve been experimenting with generating PHP templates from a Twig-like syntax, and this shows some promise! I think I like writing regular expressions. The initial version looks like this:
This would be a pretty weird thing to do…but it might work. And there is no way in any corner of the universe a pattern library will maintain the test of time, so this has to be figured out.
Clarity Conf
Right now I am in. the airport in Nashville about to fly to Clarity Conf to learn all about Design Systems β I’m extremely excited about this and ready to learn as much as possible! There will absolutely be a blog post about my takeaways, so stay tuned.
Okay, that’s all for now…until next time!