Zach did that thing where each of his blog posts has a special URL with the design of social image card that is screenshat by a headless browser (like Puppeteer) and used as a true meta Open Graph image, meaning it’s displayed on Twitter, Facebook, iMessage, Slack, Discord, and whatever else supports that card look.
I like it. Even though I’ve got a pretty good solution cooking now (for WordPress), the templates aren’t controlled with HTML/CSS like I wish they were.
As bit of yang to the ying here, Jim has some thoughts on the not-so-great aspects of Open Graph images:
I feel like they’ve been hijacked by auto-generated computer imagery serving as attention-grabbing filler more than supportive expression.
It’s kinda like… we can add Open Graph images, and we essentially get a totally free massive clickable target for hungry fingers, so we do add Open Graph images — even when that image is, well, boring. Just auto-generated computer barf of title text with branding. Jim’s post has examples.
I get where Jim is coming from, and I suppose I’m guilty to some degree. I feel like we’re a cut-above on CSS-Tricks though, if you’ll pardon a taste of defensiveness, because:
We have a variety of templates to choose from to switch it up, like a quote design.
We incorporate custom imagery into the final card, meaning most cards are somewhat visually unique.
We don’t just brand the cards, we usually incorporate the author for a little extra high five for the person, rather than just our brand.
There is a conversation that has been percolating for as long as I’ve been in the web design and development industry. It’s centered around the conflict between design tools and development tools. The final product of web design is often a mockup. The old joke was that web developers make websites and web designers make paintings of websites. That disconnect is a source of immense friction. Which is the source of truth?
What if there really could be a single source of truth. What if the design tool works on the same exact code as the production website? The latest chapter in this epic conversation is UXPin.
Let’s set up the facts so you can see this all play out.
UXPin is an in-browser design tool.
UXPin is a powerful design tool with all the features you’d expect, particularly focused on digital screen-based design.
The fact that it is in-browser is extra great here. Designing websites… on a website is an obvious and natural fit. It means what you are looking at is how it’s going to look. This is particularly important with typography! The implementer of this card component can see exact colors (in the right formats) are being used, as well as the exact pixel dimensions, etc.
Over a decade ago, Jason Santa Maria thought a lot about what a next-gen design tool would look like. Could we just use the browser directly?
I don’t think the browser is enough. A web designer jumping into the browser before tackling the creative and messaging problems is akin to an architect hammering pieces of wood together and then measuring afterwards. The imaginative process is cut short by the tools at hand; and it’s that imagination—or spark—at the beginning of a design that lays the path for everything that follows.
Perhaps not the browser directly, but a design tool within a browser, that could be the best of both worlds:
An application like this could change the process of web design considerably. Most importantly, it wouldn’t be a proxy application that we use to simulate the way webpages look—it would already speak the language of the web. It would truly be designing in the browser.
It’s so cool to see this play out in a way that aligns with what great designers envisioned before it was possible, and with new aspects that melt with today’s technological possibilities.
You can work on your own React components within UXPin.
This is where the source of truth magic can happen. It’s one thing if a design tool can output a React (or any other framework) component. That’s a neat trick. But it’s likely to be a one-way trip. Components in real-world projects are full of other things that aren’t entirely the domain of design. Perhaps a component uses a hook to return the current user’s permissions and disable a button if they don’t have access. The disabled button has an element of design to it, but most of that code does not.
It’s impractical to have a design tool that can’t respect other code in that component and essentially just leave it alone. Essentially, it’s not really a design tool if it exports components but can’t import them.
Now, fair is fair, this is going to take a little work to set up. Might just be a couple of hours, or it might take few days for a complete design system. UXPin only works with React and uses a webpack configuration to integrate it.
Once you’ve gotten in going, the components you use in UXPin are very literally the components you use to build your production website.
It’s pretty impressive really, to see a design tool digest pre-built components and allow them to be used on an entirely new canvas for prototyping.
They’ve got lots of help for you on getting this going on your project, including:
Knowing that, you might give yourself a prop interface for your components that provides you with lots of design control. For example, integrating theme switching.
This is all even faster with Storybook.
The great news? UXPin Merge works together awesomely with Storybook. It makes integration super quick and easy. Plus then it supports any framework, like Angular, Svelte, Vue, etc—in addition to React.
What if designers could use the very same components used by engineers and they’re all stored in a shared design system (with accurate documentation and tests)? Many of the frustrating and expensive misunderstandings between designers and engineers would stop happening.
And a plan:
Connect to any Git repo.
Learn about all the components in that repo.
Make those components available to the UXPin visual editor.
Watch for any changes to the repo and reflect those changes in the visual editor.
Let designer’s design and deliver accurate specs to developers for using those components.
As the web gets more and more capable, developers are able to make richer online experiences. There are times, however, where some new web capabilities may not work as you would expect in the interest of usability, security and privacy.
I have run into situations like this. Like lazy loading in HTML. It’s easy to drop that attribute onto an image element only to realize… it actually needs more than that to do its thing. We’ll get into that specific one in a moment as we look at a few other features that might not work exactly as you‘d expect.
:visited links have limited styling and getComputedStyle lies about their style
These days, attempting to use getComputedStyle on a :visited link returns the style of the :unvisited link instead. That’s just one of those things you have to know because that’s different from how it intuitively ought to work.
But we can get around this in two ways:
make the visited link’s style trigger a side effect (e.g. a layout shift), or
leverage the sibling (~ or +) or child (>) CSS selectors to render another style.
Regarding side effects, while there are some clever yet fragile ways to do this, the options we have for styling :visited links are limited and some styles (like background-color) will only work if they’re applied to unvisited links. As for using a sibling or child, executing getComputedStyle on these returns the style as if the link wasn’t visited to begin with.
Browsers don’t cache assets across sites anymore
One advantage of a CDN was that they allowed for a particular resource (like Google Fonts) to be cached in the browser for use across different websites. While this does provide a big performance win, it has grave privacy implications.
Given that an asset that’s already cached will take longer to load than one that’s not, a site could perform a timing attack to not only see your site history but also expose both who you are and your online activity. Jeff Kaufman gives an example:
Unfortunately, a shared cache enables a privacy leak. Summary of the simplest version:
I want to know if you’re a moderator on www.forum.example.
I know that only pages under load www.forum.example/moderators/header.css.
When you visit my page I load www.forum.example/moderators/header.css and see if it came from cache.
In light of this, browsers don’t offer this anymore.
performance.now() may be inaccurate
A scary group of vulnerabilities came out as couple of years ago, one of which was called Spectre. For an in depth explanation, see Google’s leaky.page (works best in Chromium) as a proof of concept. But for the purposes of this article, just know that the exploit relies on getting highly accurate timing, which is something that performance.now() provides, to try and map sensitive CPU data.
To mitigate Spectre, browsers have reduced its accuracy and may add noise as well. These range from 20μs to 1ms and can be changed based on various conditions like HTTP headers and browser settings.
If scripting is disabled for an element, return false.
Note This is an anti-tracking measure, because if a user agent supported lazy loading when scripting is disabled, it would still be possible for a site to track a user’s approximate scroll position throughout a session, by strategically placing images in a page’s markup such that a server can track how many images are requested and when.
Browsers can limit features based on user preferences
Some users might opt to heavily restrict browser functionality in the interest of further security and privacy. Firefox and Tor are two browsers that do this through the resist fingerprint setting which does things like reducing the precision of certain variables (dimensions and time), omitting certain variables entirely, limiting or disabling some Web APIs and never matching media queries. WebKit has a document outlining how browsers can approach fingerprint resistance.
Note that this goes beyond the standard anti-tracking features that browsers implement. It’s unlikely that a user will enable this as they would need a very specific threat model to do so. Part of this can be countered with progressive enhancement, graceful degradation, and understanding your users. This limitation is a big issue when you actually need fingerprinting, like fraud detection. So, if it’s absolutely necessary, look for an alternative means.
Screen readers might not relay the semantics of certain elements
Semantic HTML is great for many reasons, most notably that it conveys meaning in markup that software, like screen readers, interpret and announce to users who rely on them to navigate the web. It’s essential for crafting accessible websites. But, at times, those semantics aren’t conveyed—at least how you might expect. Something might be accessible, but still have usability issues.
In case of conflict, consider users over authors over implementors over specifiers over theoretical purity. In other words costs or difficulties to the user should be given more weight than costs to authors;
Another case where semantics might not be relayed is with emphasis. Take inline elements like strong, em, mark, ins, del, and data—all elements that have semantic meanings, but are unlikely to be read out because they can get noisy. This can be changed in a user’s screenreader’s settings, but if you really want it to be read you can declare it in visually hidden in the content property of either a :before or :after pseudo-element.
To illustrate this I made a brief example to see how NVDA with Firefox 89 and VoiceOver with Safari 14.6 read out semantic elements.
Unlike VoiceOver, NVDA reads out some of the semantic elements (del, ins and mark) and tries to emphasize text by gradually increasing the volume of emphasized text. Both of them have no trouble reading out the :before/:after psudo-elements however. Also, VoiceOver read out the tag’s brackets (greater than, less than), though both screenreaders have the ability to change how much punctuation is read.
To see whether or not you need to emphasize the emphasis, make sure you test with your users and see what they need. I didn’t focus on the visual aspect but the default styling of emphasis elements may be inconsistent across browsers, so make sure you provide suitable styling to go along with it.
Interesting, isn’t it? Some web features that we might expect to work a certain way just don’t. That isn’t to say that the features are wrong and need to be fixed, but more of a heads up as we write code.
It’s worth examining your own assumptions during development. Critically examine what your users need and factor it in as you make your site. You’re certainly welcome to work around these these as you encounter them, but in cases where you’re unable to, make sure to find and provide reasonable progressive enhancement and graceful degradation. It’s OK if users don’t experience a website the exact same way in every browser as long as they’re able to do what they need to.
That’s my list of things that don’t work the way I expect them to. What’s on your list? I’m sure you’ve got some and I’d love to see them in the comments!
SVGs are awesome: they are small, look sharp on any scale, and can be customized without creating a separate file. However, there is something I feel is missing in web standards today: a way to include them as an external file that also retains the format’s customization powers.
For instance, let’s say you want to use your website’s logo stored as web-logo.svg. You can do:
<img src="/images/logo.svg" />
That’s fine if your logo is going to look the same everywhere. But in many cases, you have 2-3 variations of the same logo. Slack, for example, has two versions.
If we had a way to customize fill color of our logo above, we could pass any arbitrary color to render all the variations.
Take the case of icons, too. You wouldn’t want to do something like this, would you?
To address this, I have created a library called svg-loader. Simply put, it fetches the SVG files via XHR and loads them as inline elements, allowing you to customize the properties like fill and stroke, just like inline SVGs.
For example, I have a logo on my side-project, SVGBox. Instead of creating a different file for every variation, I can have one file and customize the fill color:
I used data-src to set the URL of SVG file. The fill attribute overrides fill of the original SVG file.
To use the library, the only thing I have to ensure is that files being served have appropriate CORS headers for XHRs to succeed. The library also caches the files locally, making the subsequent much faster. Even for the first load, the performance is comparable to using <img> tags.
Dynamically-added elements and change in attributes are also handled automatically, which ensures that it works with all web frameworks. Here’s an example in React:
Can we not just inline SVG ourselves?
Inlining is the simplest way to use SVGs. Just copy and paste the SVG code in the HTML. That’s what svg-loader is ultimately doing. So, why add the extra steps to load a SVG file from somewhere else? There are two major reasons:
Inline SVGs make the code verbose: SVGs can be anywhere from a few lines to a few hundred. Inline SVGs can work well if what you need is just a couple of icons and they are all tiny. But it becomes a major pain if they are sizeable or many, because then, they become long strings of text in code that isn’t “business logic.” The code becomes hard to parse.
External SVGs are much more convenient: Copying and pasting often does the job, but external SVGs can be really convenient. Say you’re experimenting with which icon to use in your app. If you’re using inline SVGs, that means going back and forth to get the SVG code. But with external SVGs, you only have to know the name of the file.
Take a look at this example. One of the most extensive icon repository on GitHub is Material Design Icons. With svg-loader and unpkg, we can start using any of 5,000+ icons right away.
Isn’t it inefficient to trigger an HTTP request for every SVG versus making a sprite?
Not really. With HTTP2, the cost of making an HTTP request has become less relevant. Yes, there are still benefits of bundling (e.g., better compression), but for non-blocking resources and XHRs, the pros are almost non-existent in real-world scenarios.
Here’s a Pen loading 50 icons in a similar fashion as above. (Open in incognito mode as the files are cached by default):
Can we not use a build tool that inlines the SVGs?
I couldn’t find an obvious way to fetch SVGs from a URL and inline them in common bundlers, like webpack and Grunt, although they exist for inlining SVG files stored locally. Even if a plugin that does this exists, setting up bundlers isn’t exactly straightforward. In fact, I often avoid using them until the project has reached acertain level of complexity. We must also realize that a majority of the internet is alien to things like webpack and React. Simple scripts can have a much wider appeal.
What about the <object> tag?
The <object> tag is a native way to include external SVG files that work across all the browsers.:
In short, using external SVG files this way makes it ultra-convenient to use icons and other SVG assets. As covered earlier, with unpkg, we can use any icon on GitHub without needing extra code. We can avoid creating a pipeline in a bundler to process SVG files or a component for every icon, and just host the icons on a CDN.
Loading SVG files this way packs a lot of benefits with very little cost.
Just a little post I wrote up over at The Events Calendar blog. The idea is that a set of blocks can be grouped together in WordPress, then registered in a register_block_pattern() function that makes the group available to use as a “block pattern” in any page or post.
Block patterns are becoming upper-class citizens in the WordPress block editor. They were announced without much fanfare in WordPress 5.5 back in August, but have been given prominent real estate in the block inserter with its own tab next to blocks, including 10 or so default ones right out of the box.
What I find interesting is how the blocks ecosystem is evolving. We started with a set of default blocks that can be inserted into a post. We got reusable blocks that provide a way to assemble a group of blocks with consistent content across all pages of posts. Now we have a way to do the same, but in a much more flexible and editable way. The differences are subtle, but the use cases couldn’t be more different. We’ve actually been using reusable blocks here at CSS-Tricks for post explanations, like this:
We drop some text in here when we think there’s something worth calling out or that warrants a little extra explanation.
Any reusable block can be converted to a “regular” block. The styles are maintained but the content is not. That’s been our hack-y approach for speeding up our process around here, but now that block patterns are a thing, previous reusable blocks we’ve been using now make more sense as patterns.
Hard-stop gradients are one of my favorite CSS tricks. Here, Marcel Moreau combines that idea with CSS grid to solve an issue that’s otherwise a pain in the butt. Say you have like a 300px right sidebar on a desktop layout with a unique background color. Easy enough. But then say you want that background color to stretch to the right edge of the browser window even though the grid itself is width-constrained. Tricker.
Talk to anyone who has an active blog and I bet they’ll tell you it’s been valuable to them. Maybe it’s opened doors. Maybe it’s got them a job. Maybe it’s got them a conference invite. Maybe they just like the thrill of knowing people have read and responded to it. Maybe they learned a lot through its creation and maintenance.
In remote work, we communicate primarily through writing. We send messages in Slack. We document projects in Notion. We send meeting invites with a written description of the purpose. We’re writing all the time.
It’s just so damn important for team work of any kind, particularly when you aren’t next to each other physically.
While writing forces people to think clearly, writing also forces teams to think clearly. In my experience, having a clearly written thing makes it easy for folks to collaborate with me. This is because people naturally enjoy poking holes in arguments, adding points that were missed, or mentioning any risks that weren’t taken into account. I’ve found it helpful to use this human tendency to my advantage. Extra opinions and poked holes are hard to surface if you didn’t write something in the first place.
Feedbin is the RSS reader I’m using at the moment. I was reading one of Harry’s blog posts on it the other day, and I noticed a nice little interactive touch right inside Feedbin. There was a button-looking element with the number one which, as it turned out, was a footnote. I hovered over it, and it revealed the note.
<p>...they’d managed to place 27.9MB of images onto the Critical Path. Almost 30MB of previously non-render blocking assets had just been turned into blocking ones on purpose with no escape hatch. Start render time was as high as 27.1s over a cable connection<sup id="fnref:1"> <a href="#fn:1" class="footnote">1</a></sup>.</p>
Just an anchor link that points to #fn:1, and the <sup> makes it look like a footnote link. This is how the styling would look by default:
The HTML for the list of footnotes at the bottom of the blog post looks like this:
As a little side note, I notice Harry is using scroll-behavior to smooth the scroll. He’s also got some nice :target styling in there.
All in all, we have:
a link to go down and read the note
a link to pop back up
Nothing special there. No fancy libraries or anything. Just semantic HTML. That should work in any RSS reader, assuming they don’t futz with the hash links and maintain the IDs on the elements as written.
It’s Feedbin that sees this markup pattern and decides to do the extra UI styling and fancy interaction. By inspecting what’s going on, it looks like they hide the originals and replace them with their own special stuff:
That said, it’s based on an already functional foundation. Lemme end this with that same markup pattern, and I’ll try to look at it in different RSS readers to see what they do. Feel free to report what it does in your RSS reader of choice in the comments, if it does anything at all.
Azul is an abstract board game designed by Michael Kiesling and released by Plan B Games1 in 2017. From two to four players collect tiles to fill up a 5×5 player board. Players collect tiles by taking all the tiles of one color from a repository, and placing them in a row, taking turns until all the tiles for that round are taken. At that point, one tile from every filled row moves over to each player’s 5×5 board, while the rest of the tiles in the filled row are discarded. Each tile scores based on where it is placed in relation to other tiles on the board. Rounds continue until at least one player has made a row of tiles all the way across their 5×5 board.
Plan B makes other cool games like Century and Reef. ↩
Here’s the situation: You’ve bashed out a complicated design over two weeks of near full-time effort, gotten everything down to the exact spec of the design file, turn it in for stakeholder review and… you’re way off scope. Turns out a few folks on the team put their heads together, made some changes, and never sent you an updated comp.
The unfortunate truth is that this happens all too often in front-end development, but it’s really no one person’s fault because it boils down to simple collective miscommunication and a lack of transparency on the team.
Well, that’s where a project management platform like monday.com comes into play. Even if you’re on a remote team or sitting in an office with cubicle walls up to the ceiling, monday.com bridges gaps and tears down walls that could throw a project off-track. With powerful and intuitive tools, like instant messaging for those ad hoc meetings, file storage for a centralized repository of assets, and an activity dashboard for catching up on the status of a project at a glance, monday.com brings project out into the light so everyone is in the loop and on the same page.