Web Standards

Bunny Fonts

Css Tricks - Thu, 06/30/2022 - 7:28am

Bunny Fonts bills itself as the “privacy-first web font platform designed to put privacy back into the internet.” According to its FAQ:

With a zero-tracking and no-logging policy, Bunny Fonts helps you stay fully GDPR compliant and puts your user’s personal data into their own hands.

Hard for my mind not to go straight to Google Fonts. Bunny Fonts even says they are a drop-in replacement for Google Fonts. It offers the same open source fonts and holds the same API structure used by Google Fonts.

Now, I’m no GDPR expert but the possibility of Google collecting data through its Fonts API is hardly unsurprising or even unexpected. I was curious to check out Google’s privacy statement for Fonts:

The Google Fonts API logs the details of the HTTP request, which includes the timestamp, requested URL, and all HTTP headers (including referrer and user agent string) provided in connection with the use of our CSS API.

IP addresses are not logged.

Comparing that to what Bunny Fonts says in its FAQ:

When using Bunny Fonts, no personal data or logs are stored. All the requests are processed completely anonymously.

Or perhaps more thoroughly explained on the bunny.net GDPR statement:

In most cases, the data held and collected by bunny.net does not contain any user identifiable data. In some cases, which depend on how you are using bunny.net and how your website is structured, personal data may be collected from your users. Such information includes hosting user uploaded content as well as personal data that might be transmitted in the URL, User-Agent or Referer headers of the HTTP protocol.

Sounds pretty similar, right? Well, it may not have been that similar earlier this year when a German court ruled that embedded Google Fonts violated GDPR compliance. It appears that one line in the Google Fonts privacy statement about IP addresses came after the ruling, once the API scrubbed them from collected data.

So, do you need to ditch Google Fonts to be GDPR compliant? I would imagine not if IP addresses were the sole concern, but I’ll leave that for folks who know the rules to comment on that.

But if you are concerned about Google Font’s GDPR compliance, I guess Bunny Fonts is worth a look! And seeing that it’s powered by bunny.net’s CDN services, you should get pretty comparable performance marks.

To Shared LinkPermalink on CSS-Tricks

Bunny Fonts originally published on CSS-Tricks. You should get the newsletter.

Text-overflow: ellipsis considered harmful

Css Tricks - Thu, 06/30/2022 - 3:38am

Eric Eggert:

There are a few legitimate use cases for this technique. For example, you might have a table with titles and descriptions. To preserve more space for the title, you constrain the description to one line on small viewports to the one-line and you repeat the description on the detail page for this item.

However, I often see it used on items like buttons or even form labels to make them look nicer(?) or when aligning them vertically. But once you change the viewport or resize the text, the end of the text disappears.

I think “… if used in certain situations” belongs there, but it certainly makes for a better blog post title without it. As Eric says, there are legitimate use cases for truncating text. Maybe only a few, but legitimate nonetheless.

The ultimate goal is to prevent “losing” data, something that can certainly happen in CSS. Text that inadvertently overflows a container is lost in the sense that it’s simply not there. And if that text is simply not there, users will miss it, even if it is the best and most well-crafted call to action ever published to the web.

Eric points out that there is no way to make the text truncated by text-overflow: ellipsis visible. Once it’s gone, it’s gone (although screen readers seem to announce it). It’s practically lost data. You might be OK with that. That’s cool as long as you know what’s happening and it’s intended.

But here’s what Eric says that made me want to share this:

Don’t constrain the content to fit your design, make your CSS flexible to handle longer words gracefully.

Again, you might want to conform content to the design. But I’d probably argue, like Eric, that the design should adapt to the content rather than the other way around. I have a hard time recalling any situation where the text on a page is unimportant or without purpose to the extent that I’d be cool cutting if off at any arbitrary point determined by a CSS property. Maybe an archive of blog posts where each post shows an excerpt of the post content before truncating, but that’s not exactly a use case for text-overflow: ellipse.

CSS has the tools to make a flexible design that accounts for varying lengths of text. So maybe err on the side of writing defensive CSS… CSS that anticipates issues and knows how to gracefully handle different content scenarios. text-overflow: ellipsis might be part of your CSS arsenal for that. But it might also be throwing the baby out with the bath water. Worth asking whether losing that data is worth the cost of what that content is supposed to do before giving giving it a haircut.

While we’re talking about truncating text…

Link on Oct 1, 2021 Line Clampin’ (Truncating Multiple Line Text) Chris Coyier Link on Sep 20, 2021 Embracing Asymmetrical Design Chris Coyier Link on Jul 21, 2020 Using Flexbox and text ellipsis together Chris Coyier Link on Sep 4, 2019 Multiline truncated text with “show more” button Chris Coyier

To Shared LinkPermalink on CSS-Tricks

Text-overflow: ellipsis considered harmful originally published on CSS-Tricks. You should get the newsletter.

How I Chose an Animation Library for My Solitaire Game

Css Tricks - Wed, 06/29/2022 - 2:55am

There is an abundance of both CSS and JavaScript libraries for animation libraries out there. So many, in fact, that choosing the right one for your project can seem impossible. That’s the situation I faced when I decided to build an online Solitaire game. I knew I’d need an animation library, but which was the right one to choose?

In this article, I’ll go through which considerations I made, what to look out for and present you with some of the most popular libraries available. I’ll go through some real-world examples with you to illustrate my points, and in the end, hopefully, you’ll be better equipped than me when I first had to choose an animation library.

Your mileage with this advice may vary, of course. Everything I’m sharing here is specific to a thing I wanted to build. Your project may have completely different requirements and priorities and that’s OK. I think what’s important here is getting a first-hand account of thinking like a front-end developer with a particular goal.

Speaking of which, I do consider myself a front-end developer but my background is super heavy in design. So I know code, but not to the extent of someone who is a JavaScript engineer. Just wanted to clear that up because experience can certainly impact the final decision.

Here’s the goal

Before we get into any decision-making let’s take a look at the sorts of animations I needed to make in this CSS-Tricks-ified version of the game:

@media (max-width: 800px) { #solitaire_embed > div { padding-bottom: 90% !important; /* Change aspect ratio on mobile */ } } @media (max-width: 568px) { #solitaire_embed > div { padding-bottom: 100% !important; /* Change aspect ratio on mobile */ } } @media (max-width: 414px) { #solitaire_embed > div { padding-bottom: 120% !important; /* Change aspect ratio on mobile */ } }

Pretty sweet, right? There’s nothing exactly trivial about these animations. There’s a lot going on — sometimes simultaneously — and a lot to orchestrate. Plus, a majority of the animations are triggered by user interactions. So, that left me with a few priorities heading into my decision:

  • Smooth animations: The way animations are applied can have a big impact on whether they run smoothly, or display a little choppiness.
  • Performance: Adopting any library is going to add weight to a project and I wanted my game to be as lean as possible.
  • Convenience: I wanted a nice, clean syntax that makes it easier to write and manage the animations. I’d even trade a little extra convenience for a small performance cost if it allows me to write better, more maintainable code. Again, this bodes well for a designer-turned-developer.
  • Browser support: Of course I wanted my game to work on any modern browser using some form of progressive enhancement to prevent completely borking legacy browsers. Plus, I definitely wanted  some future-proofing.

That’s what I took with me as I went in search of the right tool for this particular job.

Choosing between CSS or JavaScript animation libraries

The first thing I considered when choosing an animation library was whether to go with a CSS or JavaScript-based library. There are lots of great CSS libraries, many of them with excellent performance which was a high priority for me. I was looking to do some heavy-duty animations, like the  ability to sequence animations and get callbacks on animation completion. That’s all totally possible with pure CSS — still, it’s a lot less smooth than what most JavaScript libraries offer.

Let’s see how a simple sequenced animation looks in CSS and compare it to jQuery, which has plenty of built-in animation helpers:

CodePen Embed Fallback

The animations look the same but are created differently. To make the CSS animation, first, we have to define the keyframe animation in our CSS and attach it to a class:

.card.move { animation : move 2s; } @keyframes move { 0% { left: 0 } 50% { left: 100px } 100% { left: 0 } }

We then execute the animation using JavaScript and listen for a CSS callback on the element:

var cardElement = document.getElementsByClassName("card")[0]; var statusElement = document.getElementsByClassName("status")[0]; cardElement.classList.add("move"); statusElement.innerHTML = "Animating" var animationEndCallback = function() { cardElement.classList.remove("move"); statusElement.innerHTML = "Inactive" } cardElement.addEventListener("webkitAnimationEnd", animationEndCallback); cardElement.addEventListener("oAnimationEnd", animationEndCallback);  cardElement.addEventListener("antionend", animationEndCallback);

Having things happen in different places might be fine in a simple example like this, but it can become very confusing once things get a bit more complex. 

Compare this to how the animation is done with jQuery:

$(".status").text("Animating") $( ".card" ).animate({ left: "100px" }, 1000); $( ".card" ).animate({ left: 0 }, 1000, function() { $(".status").text("Inactive") });

Here, everything happens in the same place, simplifying things should the animations grow more complex in the future.

It seemed clear that a JavaScript library was the right way to go, but which was the right one to choose for my Solitaire game? I mean, jQuery is great and still widely used even today, but that’s not something I want to hang my hat on. There are plenty of JavaScript animation libraries, so I wanted to consider something built specifically to handle the type of heavy animations I had in mind.

Choosing a JavaScript animation library

It quickly became apparent to me that there’s no lack of JavaScript animation libraries and new, exciting technologies. They all have benefits and drawbacks, so let’s go through some of the ones I considered and why.

The Web Animations API is one such case that might replace many JavaScript animation libraries in the future. With it, you’ll be able to create complex staggered animations without loading any external libraries and with the same performance as CSS animations. The only drawback is that not all browsers support it yet

The <canvas> element presents another exciting opportunity. In it, we can animate things with JavaScript, as we would with the DOM, but the animation is rendered as raster, which means we can make some high-performance animations. The only drawback is that the canvas element is essentially rendered as an image in the DOM, so if we’re looking for pixel-perfection, we might be out of luck. As someone acutely in tune with design, this was a dealbreaker for me.

I needed something tried and tested, so I knew I probably had to go with one of the many JavaScript libraries. I started looking at libraries and narrowed my choices to Anime.js and GSAP. They both seemed to handle complex animations well and had excellent notes on performance. Anime is a well-maintained library with over 42.000 stars on GitHub, while GSAP is a super popular, battle-tested library with a thriving community.

An active community was critical to me since I needed a place to ask for help, and I didn’t want to use a library that might later be abandoned. I considered this as part of my convenience requirements.

Sequencing animations and callbacks

Once I had my choices narrowed down, the next step was to implement a complex animation using my two libraries. A recurrent animation in a solitaire game is that of a card moving somewhere and then turning over, so let’s see how that looks:

CodePen Embed Fallback

Both animations look great! They’re smooth, and implementing both of them was pretty straightforward. Both libraries had a timeline function that made creating sequences a breeze. This is how the implementation looks in AnimeJS:

var timeline = anime.timeline({ begin: function() { $(".status").text("Animating") }, complete: function() { $(".status").text("Inactive") } }); timeline.add({ targets: '.card', left: [0, 300], easing: 'easeInOutSine', duration: 500 }).add({ targets: '.card .back', rotateY: [0, 90], easing: 'easeInSine', duration: 200 }).add({ targets: '.card .front', rotateY: [-90, 0], easing: 'easeOutSine', duration: 200 })

Anime’s timeline() function comes built-in with callbacks on beginning and ending the animation, and creating the sequence is as easy as appending the sequential animations. First, I move the card, then I turn my back-image 90 degrees, so it goes out of view, and then I turn my front-image 90 degrees, so it comes into view.

The same implementation using GSAP’s timeline() function looks very similar:

var timeline = gsap.timeline({ onStart: function() { $(".status").text("Animating") }, onComplete: function() { $(".status").text("Inactive") } }); timeline.fromTo(".card", { left: 0 }, { duration: 0.5, left: 300 }).fromTo(".card .back", { rotationY: 0 }, { rotationY: 90, ease: "power1.easeIn", duration: 0.2 }).fromTo(".card .front", { rotationY: -90 }, { rotationY: 0, ease: "power1.easeOut", duration: 0.2 }) Decision time

The main difference between Anime and GSAP appears to be the syntax, where GSAP might be a little more elaborate. I was stuck with two great libraries that had very similar functionality, were able to deal with complex animation, and had a thriving community. It seemed like I had a tie race!

PriorityAnimeGSAPSmooth animations✅✅Performance✅✅Convenience✅✅Browser support✅✅

So, what made me choose one library over the other?

I was very concerned about how the library would act under pressure. Having laggy animations in a game like Solitaire can greatly impact how fun it is to play the game. I knew I wouldn’t be able to fully see how the library performed before I created the game. Luckily, GSAP had made a stress test that compared different animation libraries to each other, including Anime.

CodePen Embed Fallback

Looking at that, GSAP certainly looked to be the superior library for dealing with loads of complex animations. GSAP was giving me upwards of 26 frames per second on a heavy animation that Anime was only able to top out at 19.  After reading up on GSAP more and looking into their forums, it became clear that performance was of the highest priority to the guys behind GSAP.

And even though both GSAP and Anime have been around a while, Anime’s repo has been sitting somewhat dormant a couple of years while GSAP had made commits in the past couple of months.

I ended up using GSAP and haven’t regretted my decision!

How about you? Does any of this square with how you evaluate and compare front-end tooling? Are there other priorities you might have considered (e.g. accessibility, etc.) in a project like this? Or do you have a project where you had to pare down your choices from a bunch of different options? Please share in the comments because I’d like to know! 

Oh, and if you want to see how it looks when animating a whole deck of cards, you can head over to my site and play a game of Solitaire. Have fun!

How I Chose an Animation Library for My Solitaire Game originally published on CSS-Tricks. You should get the newsletter.

Help Shape the Future of CSS-Tricks!

Css Tricks - Tue, 06/28/2022 - 9:52am

Hey, so it’s been a minute since we announced that CSS-Tricks is now part of the DigitalOcean family. Things are pretty much business as usual and hopefully it feels that way to you, too. Now that we’re getting settled, we’re eager to start poking at the future of this site.

What sort of things are we poking at? Well, that’s where you come in. You see, there’s no shortage of ideas for CSS-Tricks, but we only want to work on things that continue to make CSS-Tricks one of the spots you come to time and again for all things front-end (including actual CSS tricks).

So, we put together a short little survey for you. Nothing intense, just a few questions to help us vet those ideas and ultimately shape the future of CSS-Tricks.

Take the survey!

Thanks so much for your help! And while I have you, thanks for continuing to hang with us. In the seven years I’ve been working here at CSS-Tricks, I know this site wouldn’t even be here today without y’all. Here’s to the future of CSS-Tricks and learning together!

CSS-Tricks Newsletter

Oh, and one more update for all of you who miss the newsletter: it will be back! But we had to drop a ton of you off the list (seriously, like 80% of all subscribers) to be compliant with legal stuff that’s over my head. No worries, though, because you can re-subscribe right down here with your email address.

Help Shape the Future of CSS-Tricks! originally published on CSS-Tricks. You should get the newsletter.

My Dumbest CSS Mistakes

Css Tricks - Tue, 06/28/2022 - 5:10am

We all make mistakes in our code. It happens! I know if I had one of those “Days Since Last Mistake” signs hanging over my desk, a big ol’ goose egg would be hovering above me all the time. It doesn’t have to be big mistakes, either. My clumsy self has committed small errors to repos ranging from typos all the way to complete npm module directories.


That’s one of the things I really love about CSS: it’s forgiving as heck. If it doesn’t understand a typo, it keeps looking up the cascade in search of a match. None of that stuff where one out of place characters breaks a site and takes no prisoners. But it’s still embarrassing when CSS mistakes pop up!

Like this one I find myself making way more times than I’d like to admit:

.element { display: flexbox; /* &#x1f926;‍♂️ */ }

Or when I try setting a gradient without a background property:

.gradient { linear-gradient(45deg, rgb(50% 100% 90%), rgb(62% 85% 93%)); }

I hate how close X and C are on a keyboard because I can’t count how many times I’m blazing through something and mistake px for pc units.

.element { font-size: 16pc; /* I meant pixels! */ }

Another CSS mistake I catch every so often is one I know many other folks make because I spot it too often in blog posts with code snippets:

// This is not a CSS comment. .element { /* This is a CSS comment. */ }

Have you ever forgotten to use var() around a CSS variable? I sure have.

.element { color: --primary-color; }

Speaking of CSS variables, naming them is hard (like everything else) and I often use some incorrect version of a variable that I named!

:root { --color-primary: #FF5722; --color-secondary: #3E2723; } /* Much later on... */ .element { color: var(--primary-color); /* &#x1f643; */ }

Yes, I have indeed copied a snippet of CSS before only to have fancy quotes get in the way of making it work:

.element::before { content: “”; /* Should be "" */ }

And, yes, I have spent way too long figuring out those quotes were the culprit.

Looking at that last one reminds me that I sometimes forget to set the content property when I’m working with ::before or ::after. Which reminds me of how I’ve forgotten to set an element’s position before trying to offset it or change its z-index. Seriously, these things happen!

It’s hard talking about mistakes

Have you ever finished reading some blog post sharing some amazing trick and felt some sort of Imposter Syndrome? I think that’s largely because blog posts often mask the real work — and failures — that go into amazing tricks. As someone who reads posts like that for a living, I can tell you that many, if not the vast majority, go through many rounds of editing where potentially embarrassing mistakes are weeded out and smoothed over.

Even those ridiculously awesome articles have to fail before they get all those ooooos and ahhhhhs.

The same is true of any app, website, demo, or whatever you happen to come across. The chances any of them came out perfect the first time is next to nothin’.

But if I’m being totally honest with you, I’m often more amazed (and interested) in the journey it takes to accomplish something, warts and all. The journey is a glimpse into what it’s like to think like a front-end developer. That’s where real (and most valuable) learning happens.

And all of this is merely building up to what I really want to ask…

What are your dumbest CSS mistakes?

C’mon, we all know you’ve made some! Let us learn from them!

My Dumbest CSS Mistakes originally published on CSS-Tricks. You should get the newsletter.

Great (and Free!) Web Development Books You Can Get Online

Css Tricks - Mon, 06/27/2022 - 3:27am

Right after “Where is the best place to learn?” perhaps the most commonly asked question I hear from folks getting into code is “What web development books should I get to learn?” Well, consider this an answer to that question as I’ve curated a list of books that are not only great for getting into front-end development but also freely available.

Table of Contents
  1. Books on CSS
  2. Books on HTML & CSS
  3. Books on process
  4. Books on JavaScript
  5. Wrapping up
Books on CSS

This is the bulk of where we’re going to hang out because, well, this is a site mostly about CSS!

The Magic of CSS by Adam Schwartz
  • Perfect for: Next steps in your CSS journey
  • Learning level: Intermediate
  • Requires: Some basic understanding of CSS

Adam Schwartz covers six CSS concepts in this book, including the box model, layout, tables, color, typography, and transitions. These are things even stump some seasoned CSSers, some of these concepts might be confusing. Adam has gone to a great length to demystify each.

In addition to the book being a great primer on complex CSS concepts, I love how each of the CSS properties mentioned throughout the book is clickable so you can always click on them to see how each is applied. There are many illustrative examples and recommendations for further reading, should you desire to learn more about each chapter.

I found the chapter on colors very interesting not only because it gets into the best practices for using color accessibly, but also because there’s super practical applications, like when Adam gets into using CSS to support an organization’s branding.

Direct link Resilient Web Design by Jeremy Keith
  • Perfect for: Developing strategies for writing code
  • Learning level: Intermediate
  • Requires: Some basic understanding of CSS

Straight from the introduction:

You won’t find any code in here to help you build better websites. But you will find ideas and approaches. Ideas are more resilient than code. I’ve tried to combine the most resilient ideas from the history of web design into an approach for building the websites of the future.

What Jeremy does so well is describing soft skills, like planning, outlining, and approaches for writing code. So, rather than dropping in code snippets throughout the book, what you’ll find are details about code strategies, such as progressive enhancement, deciding on what tooling to use, and the challenges of writing future-friendly code.

And for those of you who have not had the pleasure of listening to Jeremy narrate content (like he does in the Web History series), there’s an audio file available to download.

Direct link Beginning CSS Web Development: From Novice to Professional by Simon Collison
  • Perfect for: The fundamentals of CSS
  • Learning level: Absolute beginners
  • Requires: Nothing but time and motivation

It may be written in 2006, but Simon’s coverage of web standards and accessibility is timeless and relevant today. He provides an understanding of interoperability as well as approaches for building web applications, including the early planning phases that often go overlooked.

The book has two broad parts which are further divided into 16 chapters. Part 1 covers CSS topics, like working with text, links, lists, backgrounds, images, tables, and forms. It really doesn’t skimp on the details either.

Part 2 is all about layout, shedding light on usability and layout manipulation, plus a handy case study. The chapters are arranged in such a way that one chapter naturally flows into the next. Each chapter also contains a concluding section that highlights all the important concepts covered in the chapter.

Indeed, the book provides novice developers a solid background in CSS and helps them gradually with more advanced concepts. It will make your CSS journey easier.

Direct link Books on HTML & CSS

CSS and HTML are often taught together, which can be especially helpful when you’re writing your first lines of code and want to know how the two languages interact with one another.

Learn to Code HTML & CSS by Shay Howe
  • Perfect for: Starting your front-end journey
  • Learning level: Beginners
  • Requires: No prior experience at all

Shay refers to this book as a simple and comprehensive guide dedicated to helping beginners learn HTML and CSS. He does this by focusing on common elements of front-end design and development. Some of the lessons covered are Box Model, Positioning, Typography, Background and Gradients, Lists, Media, Forms, and Tables. In the first chapter *Building Your First Web Page, Shay analyzed the contents of a typical website including elements, attributes and setting up the HTML document structure, code validation, selectors and CSS resets. I find the book very instructive especially as it went beyond the surface to address many key concepts with code samples, which you can follow along.

One profound thing about this great book is that, Shay built a complete project from scratch throughout the 12 lessons and at the end of each lesson, he provided a summary and links to the current state of that website (so you can compare with yours if you follow along) and the source code at every stage of the lessons.

If you’re a learner who learns by doing, you will find this material very useful and by the time you’re done, you will have developed a multi page functional website.

An advanced sequel of the course is also available free via the same link.

Direct link HTML & CSS: Learn the Fundamentals in 7 Days by Michael Knapp
  • Perfect for: Starting your front-end journey
  • Learning level: Beginners
  • Requires: No prior experience at all

Can you possibly learn everything there is to know about the HTML and CSS in seven days? Probably not, but that’s why this 2017 book by Michael Knapp is focused straight on the fundamentals. Michael delves into a brief history lesson before launching into HTML and CSS structure, logic, and presentation. You’re going to get all up to speed to the point where you should feel pretty confident about putting a basic webpage together, plus a few extras along the way as the book touches on SEO and analytics.

The book is comprised of simple programs that you can run on your computer if you wish to follow along.

The ebook version is available for free on Apple Books, but there is a Kindle version as well if you already have a subscription there.

Apple Books Kindle The Greatest CSS Tricks Vol. 1 by Chris Coyier
  • Perfect for: Marveling at what CSS can do
  • Learning level: Intermediate
  • Requires: Some CSS experience

Did you know that CSS-Tricks has a book on CSS too? It would be silly to leave that off this list because what you get is a collection of classic CSS trickery that’s explained by none other than Chris Coyier. In fact, Chris handpicked all of the examples covered in the book from his many, many (many!) years running this here site from the plentitude of tricks that have crossed his desk.

Each trick solves a particular pain point. For instance, the first “Pin Scrolling to Bottom” trickdemonstrates how the overflow-anchor CSS property can be used to create the same chat-like interface of a tool like Slack, where the screen is anchored at the bottom in a way that feels as though the page is scrolling for you as new items are added.

Direct Link Books on process

Code is just as much about how we write code and collaborate on projects with others as it is about the actual code we write. The following books are great starting points for everything from planning and project management to communicating and collaborating with others.

Collaborate: Bring People Together Around Digital Projects by Ellen De Vries
  • Perfect for: Being a better collaborator
  • Learning level: N/A
  • Requires: An open mind to working well with others!

Ellen addresses something in this book that we all have to deal with: collaborating with others. And it’s no small deal — the book is divided into four parts that go super deep into things we can go to work well with others:

  • Know how to prepare the ground and create the right conditions for collaboration.
  • Nurture the group culture in the early stages of collaboration.
  • Maintain a healthy collaborative process.
  • Reap the rewards of a collaboration.

As a content strategist, Ellen has the right kind of experience to help anyone be part of a collaborative project, or get the most from a collaboration.

Direct link The Modern Web Design Process by webflow
  • Perfect for: Senior designers, project managers
  • Learning level: N/A
  • Requires: Some basic understanding of CSS

This free ebook features a seven-step design process that’s meant to help define the workflow for today’s brand of web design.

That includes:

  • Setting goals
  • Defining scope
  • Sitemaps and wireframes
  • Working with content
  • Handling visual elements
  • Testing
  • Shipping

Anyone starting a new design project or in the middle of a design project will find the invaluable insights throughout the book. And what’s most remarkable is how this is written in a way that almost feels as though you are being hand-held through an entire project from concept to completion.

Direct link Designing for the Web by Mark Boulton
  • Perfect for: Learning to work with clients
  • Learning level: Beginners
  • Requires: A genuine interest in design

It seems many organizations tackle design differently. But author Mark Boulton documents a thorough design workflow in Designing for the Web that de-mystifies many challenges and covers everything you need to know.

What’s unique about this book is that it’s really about work. Sure, there’s a bunch of hugely valuable information on design best practices for things like typography, color, and layout, but what you’re really going to take away from this book is how these fit into a design workflow. It teaches you how to research, the technologies we have to implement ideas, and ultimately, how to work with others as well as clients — perfect fodder for folks including design leads, project managers, freelancers, or anyone who’s involved in the project delivery process.

Direct Link Learn Version Control with Git by Tower
  • Perfect for: Mastering Git
  • Learning level: All levels welcome
  • Requires: No prior knowledge at all

In this book, the team behind the popular Tower client for Git introduce learners to the crux of version control system using Git. Developers who work in teams will particularly find this very useful, as it helps in effectively collaborating with team members building different features of a project even when you’re thousands of miles apart. That said, it’s still really great for anyone who might be shy of the command line and wants to build confidence there.

And since the book is by the maker of an application that interacts with Git, you’re going to get a nice dose of using Tower as a GUI in addition to working directly on the command line.

So, whether it’s committing, branching, merging, pull requests, forking work, or handling merge conflicts, you’re going to get a whole lot from this book.

Direct Link Books on JavaScript

Learning JavaScript always seems to be en vogue. In fact, Jason Rodriguez wrote about the JavaScript learning landscape in 2018 and provided a nice list of free books. Not too much has cropped up since then, but here are my thoughts on the following books.

Eloquent JavaScript by Marijn Haverbeke
  • Perfect for: Getting better at writing JavaScript
  • Learning level: Intermediate to seasoned developers
  • Requires: Prior JavaScript experience

Eloquent JavaScript really lives up to its name. Personally, I consider this one of the best-written JavaScript books I have ever come across. Marjin’s writing style is engaging, especially with how he introduces programming concepts and carries the reader along. In his words, the book is simply about instructing computers and making them do what you want them to do.

The book is a deep dive into JavaScript spread across three parts and 21 chapters. You’re going to read a bunch about basic programming concepts, such as values, types, operators and functions, to advanced concepts like regular expressions, modules, the DOM, and asynchronous programming. He starts every chapter with a somewhat philosophical quote to prepare the reader for what lies ahead and then dives straight into the topic.

Plus, there’s three projects to help you practice your newfound skills.

Direct link Understanding JavaScript Promises by Nicholas C. Zakas
  • Perfect for: Those who want to learn all about asynchronous programming with promises in JavaScript.
  • Learning level: Intermediate
  • Requires: Basic JavaScript chops

JavaScript promises were introduced in 2015 as part of the ES6 specification to handle asynchronous functions in JavaScript. According to MDN:

A promise is an object representing the eventual completion or failure of an asynchronous operation

In this 51-page book, Nicholas explains the concept of Promises over three chapters: Basics, Chaining Promises, and Working with Multiple Promises. Although the link to the book we’re providing is the free community version, the full version (available on Amazon) has two more chapters on Async Functions and Unhandled Rejection Tracking. Nicholas simplified the concept of Promises with several illustrations and examples. You will learn how to use then(), catch(), and finally() and understand how to chain multiple promises together. Nicholas also covers the assignment of rejection and settlement handlers. You may want to give the book a read to solidify your understanding of the topic.

Nicholas is a veteran JavaScript book author who has been writing about JavaScript for over 15 years. He brings his wealth of experience to bear in this book (just as he has in his work here at CSS-Tricks).

Direct link Speaking JavaScript by Axel Rauschmayer
  • Perfect for: Leveling up from beginning JavaScript
  • Learning level: Intermediate
  • Requires: Knowledge of object oriented programming

This book is presented in four chapters covering more than 30 topics. Here’s how it breaks down:

  1. The first chapter is a nice refresher on syntax, variable types, functions and exception handling.
  2. The second chapter offers historical perspective into JavaScript as a prelude for the types of features covered throughout the rest of the book.
  3. Chapter 3 is presented as more or less a reference book with short, clean examples.
  4. The final chapter outlines tips, tools and libraries to help write better JavaScript and follow best practices.
Direct Link Secrets of the JavaScript Ninja by John Resig and Bear Bibeault
  • Perfect for: Creating a cross-browser JavaScript library from the ground up
  • Learning level: Intermediate
  • Requires: Some prior programming experience

There’s actually a newer edition of this book, but the 2012 edition is the one that’s free. Either way, it’s a good opportunity to learn from John Resig; you know, the guy who created jQuery.

The techniques covered here include closures, functions, the DOM, object orientation with prototypes, and cross-browser strategies. One nice perk is that each chapter is followed by a brief recap that’s perfect for a reference once you’ve finished the book.

Direct Link Learning JavaScript Design Patterns by Addy Osmani
  • Perfect for: Learning to write more efficient JavaScript
  • Learning level: Intermediate
  • Requires: A decent level of JavaScript experience

The concept of design pattern refers to a reusable solution to a commonly recurring problem in application development. In this book, Addy Osmani covers the implementation of common design patterns using ES6 and beyond, as well as React-specific design patterns, which can be super handy when working on complex React apps where maintainability is a primary goal.

Some of the patterns covered include Singleton, Proxy, Provider, Prototype and Observer patterns. In some cases, Addy includes pros and cons of using some of these patterns and how they may affect the performance of your application.

Direct Link You Don’t Know JS by Kyle Simpson
  • Perfect for: Mastering JavaScript
  • Learning level: Beginner
  • Requires: Little or no prior programming experience

While the title might be a bit provocative, what Kyle is implying here is that he writes this book assuming you have no prior JavaScript experience whatsoever.

Kyle begins starts by going through the rudiments of programming as seen through the lens of JavaScript. He then proceeds, in subsequent chapters, to introduce more advanced concepts like scope and closure, the this keyword, object prototypes, async, and performance.

There’s a lot of excellent details and explanations in here, and Kyle makes it super easy to understand by avoiding super technical jargon. There is also many exercises designed to reinforce your learning. This book will definitely get you up to speed with JavaScript. There’s second edition of the book in the works that you can track in GitHub.

Direct link The JavaScript Beginner’s Handbook by Flavio Copes
  • Perfect for: A beginner’s reference
  • Learning level: Just getting started
  • Requires: Email sign-up, maybe some prior experience

Flavio has put together a very useful JavaScript reference for those just starting out. It’s more like a quick reference guide than a textbook, so those of you just starting out might want to consider this as something you keep on your desk rather than something you sit with for long periods of time.

Direct link JavaScript for Data Science by Gans, Hodges & Wilson
  • Perfect for: Getting into data visualizations
  • Learning level: Intermediate to advanced
  • Requires: A decent handle on JavaScript

The authors cover core features of modern JavScript, including callbacks, promises, inheritance, objects and classes. They also get into testing using Mocha, React, and data vizualization, all of which are great for anyone looking to level up their code and how its written. The book doesn’t get as deep into many the concepts as some of the other books, but it really shines when it gets into data science.

The book uses Data-Forge; a JavaScript library designed for working with tabular data. There are numerous exercises to help readers keep up to speed with the subject of discussion. The last chapter also includes a capstone project that pulls everything together.

Direct Link Wrapping up

I sure hope this collection of books help you, whether you’re taking your first steps in front-end web development, have a dozen years under your belt, or you fall somewhere in between. I know how hard it is to get into something new for the first time and the feeling of not knowing where to look. I also know how it feels to hit a plateau and need something to level me up. There should be something for everyone here, regardless of where you are in your learning journey.

And, hey, if you have any other books that are available to snag for free online, please share them in the comments! I bet we can get an even bigger list going.

Great (and Free!) Web Development Books You Can Get Online originally published on CSS-Tricks. You should get the newsletter.

Single Element Loaders: The Bars

Css Tricks - Fri, 06/24/2022 - 10:00am

We’ve looked at spinners. We’ve looked at dots. Now we’re going to tackle another common pattern for loaders: bars. And we’re going to do the same thing in this third article of the series as we have the others by making it with only one element and with flexible CSS that makes it easy to create variations.

Article series

Let’s start with not one, not two, but 20 examples of bar loaders.

CodePen Embed Fallback CodePen Embed Fallback

What?! Are you going to detail each one of them? That’s too much for an article!

It might seem like that at first glance! But all of them rely on the same code structure and we only update a few values to create variations. That’s all the power of CSS. We don’t learn how to create one loader, but we learn different techniques that allow us to create as much loader as we want using merely the same code structure.

Let’s make some bars!

We start by defining the dimensions for them using width (or height) with aspect-ratio to maintain proportion:

.bars { width: 45px; aspect-ratio: 1; }

We sort of “fake” three bars with a linear gradient on the background — very similar to how we created dot loaders in Part 2 of this series.

.bars { width: 45px; aspect-ratio: 1; --c: no-repeat linear-gradient(#000 0 0); /* we define the color here */ background: var(--c) 0% 50%, var(--c) 50% 50%, var(--c) 100% 50%; background-size: 20% 100%; /* 20% * (3 bars + 2 spaces) = 100% */ }

The above code will give us the following result:

Like the other articles in this series, we are going to deal with a lot of background trickery. So, if you ever feel like we’re jumping around too fast or feel you need a little more detail, please do check those out. You can also read my Stack Overflow answer where I give a detailed explanation on how all this works.

Animating the bars

We either animate the element’s size or position to create the bar loader. Let’s animate the size by defining the following animation keyframes:

@keyframes load { 0% { background-size: 20% 100%, 20% 100%, 20% 100%; } /* 1 */ 33% { background-size: 20% 10% , 20% 100%, 20% 100%; } /* 2 */ 50% { background-size: 20% 100%, 20% 10% , 20% 100%; } /* 3 */ 66% { background-size: 20% 100%, 20% 100%, 20% 10%; } /* 4 */ 100% { background-size: 20% 100%, 20% 100%, 20% 100%; } /* 5 */ }

See what’s happening there? Between 0% and 100%, the animation changes the background-size of the element’s background gradient. Each keyframe sets three background sizes (one for each gradient).

And here’s what we get:

CodePen Embed Fallback

Can you start to imagine all the possible variations we can get by playing with different animation configurations for the sizes or the positions?

Let’s fix the size to 20% 50% and update the positions this time:

.loader { width: 45px; aspect-ratio: .75; --c: no-repeat linear-gradient(#000 0 0); background: var(--c), var(--c), var(--c); background-size: 20% 50%; animation: load 1s infinite linear; } @keyframes load { 0% { background-position: 0% 100%, 50% 100%, 100% 100%; } /* 1 */ 20% { background-position: 0% 50% , 50% 100%, 100% 100%; } /* 2 */ 40% { background-position: 0% 0% , 50% 50% , 100% 100%; } /* 3 */ 60% { background-position: 0% 100%, 50% 0% , 100% 50%; } /* 4 */ 80% { background-position: 0% 100%, 50% 100%, 100% 0%; } /* 5 */ 100% { background-position: 0% 100%, 50% 100%, 100% 100%; } /* 6 */ }

…which gets us another loader!

CodePen Embed Fallback

You’ve probably got the trick by now. All you need is to define a timeline that you translate into a keyframe. By animating the size, the position — or both! — there’s an infinite number of loader possibilities at our fingertips.

And once we get comfortable with such a technique we can go further and use a more complex gradient to create even more loaders.

CodePen Embed Fallback

Expect for the last two examples in that demo, all of the bar loaders use the same underlying markup and styles and different combinations of animations. Open the code and try to visualize each frame independently; you’ll see how relatively trivial it is to make dozens — if not hundreds — of variations.

Getting fancy

Did you remember the mask trick we did with the dot loaders in the second article of this series? We can do the same here!

If we apply all the above logic inside the mask property we can use any background configuration to add a fancy coloration to our loaders.

Let’s take one demo and update it:

CodePen Embed Fallback

All I did is updating all the background-* with mask-* and I added a gradient coloration. As simple as that and yet we get another cool loader.

So there is no difference between the dots and the bars?

No difference! I wrote two different articles to cover as many examples as possible but in both, I am relying on the same techniques:

  1. Gradients to create the shapes (dots or bars or maybe something else)
  2. Animating background-size and/or background-position to create the loader animation
  3. Adding mask to add a touch of colors
Rounding the bars

Let’s try something different this time where we can round the edges of our bars.

CodePen Embed Fallback

Using one element and its ::before and ::after pseudos, we define three identical bars:

.loader { --s: 100px; /* control the size */ display: grid; place-items: center; place-content: center; margin: 0 calc(var(--s) / 2); /* 50px */ } .loader::before, .loader::after { content: ""; grid-area: 1/1; } .loader, .loader::before, .loader::after { height: var(--s); width: calc(var(--s) / 5); /* 20px */ border-radius: var(--s); transform: translate(calc(var(--_i, 0) * 200%)); } .loader::before { --_i: -1; } .loader::after { --_i: 1; }

That gives us three bars, this time without relying on a linear gradient:

Now the trick is to fill in those bars with a lovely gradient. To simulate a continuous gradient, we need to play with background properties. In the above figure, the green area defines the area covered by the loader. That area should be the size of the gradient and, if we do the math, it’s equal to multiplying both sides labeled S in the diagram, or background-size: var(--s) var(--s).

Since our elements are individually placed, we need to update the position of the gradient inside each one to make sure all of them overlap. This way, we’re simulating one continuous gradient even though it’s really three of them.

For the main element (placed at the center), the background needs to be at the center. We use the following:

.loader { /* etc. */ background: linear-gradient() 50% / var(--s) var(--s); }

For the pseudo-element on the left, we need the background on the left

.loader::before { /* etc. */ background: linear-gradient() 0% / var(--s) var(--s); }

And for the pseudo on the right, the background needs to be positioned to the right:

.loader::after { background: linear-gradient() 100% / var(--s) var(--s); }

Using the same CSS variable, --_i, that we used for the translate, we can write the code like this:

.loader { --s: 100px; /* control the size */ --c: linear-gradient(/* etc. */); /* control the coloration */ display: grid; place-items: center; place-content: center; } .loader::before, .loader::after{ content: ""; grid-area: 1/1; } .loader, .loader::before, .loader::after{ height: var(--s); width: calc(var(--s) / 5); border-radius: var(--s); background: var(--c) calc(50% + var(--_i, 0) * 50%) / var(--s) var(--s); transform: translate(calc(var(--_i, 0) * 200%)); } .loader::before { --_i: -1; } .loader::after { --_i: 1; }

Now, all we have to do is to animate the height and add some delays! Here are three examples where all that’s different are the colors and sizes:

CodePen Embed Fallback Wrapping up

I hope so far you are feeling super encouraged by all the powers you have to make complex-looking loading animations. All we need is one element, either gradients or pseudos to draw the bars, then some keyframes to move things around. That’s the entire recipe for getting an endless number of possibilities, so go out and starting cooking up some neat stuff!

Until the next article, I will leave you with a funny collection of loaders where I am combining the dots and the bars!

CodePen Embed Fallback CodePen Embed Fallback Article series

Single Element Loaders: The Bars originally published on CSS-Tricks. You should get the newsletter.

Different Ways to Write CSS in React

Css Tricks - Wed, 06/22/2022 - 4:24am

We’re all familiar with the standard way of linking up a stylesheet to the <head> of an HTML doc, right? That’s just one of several ways we’re able to write CSS. But what does it look like to style things in a single-page application (SPA), say in a React project?

Turns out there are several ways to go about styling a React application. Some overlap with traditional styling, others not so much. But let’s count all the ways we can do it.

Importing external stylesheets

As the name suggests, React can import CSS files. The process is similar to how we link up CSS file in the HTML <head>:

  1. Create a new CSS file in your project directory.
  2. Write CSS.
  3. Import it into the React file.

Like this:

import "./style.css";

That usually goes at the top of the file where other imports happen:

import { React } from "react"; import "./Components/css/App.css"; function App() { return ( <div className="main"> </div> ); } export default App;

In this example, a CSS file is imported into an App.js from the /Components/css folder.

Write inline styles

You may be used to hearing that inline styling isn’t all that great for maintainability and whatnot, but there are definitely situations (here’s one!) where it makes sense. And maintainability is less of an issue in React, as the CSS often already sits inside the same file anyway.

This is a super simple example of inline styling in React:

<div className="main" style={{color:"red"}}>

A better approach, though, is to use objects:

  1. First, create an object that contains styles for different elements.
  2. Then add it to an element using the style attribute and then select the property to style.

Let’s see that in context:

import { React } from "react"; function App() { const styles = { main: { backgroundColor: "#f1f1f1", width: "100%", }, inputText: { padding: "10px", color: "red", }, }; return ( <div className="main" style={styles.main}> <input type="text" style={styles.inputText}></input> </div> ); } export default App;

This example contains a styles object containing two more objects, one for the .main class and the other for a text input, which contain style rules similar to what we’d expect to see in an external stylesheet. Those objects are then applied to the style attribute of elements that are in the returned markup.

Note that curly brackets are used when referencing styles rather than the quotation marks we’d normally use in plain HTML.

Use CSS Modules

CSS Modules… what the heck happened to those, right? They have the benefit of locally scoped variables and can be used right alongside React. But what are they, again, exactly?

Quoting the repo’s documentation:

CSS Modules works by compiling individual CSS files into both CSS and data. The CSS output is normal, global CSS, which can be injected directly into the browser or concatenated together and written to a file for production use. The data is used to map the human-readable names you’ve used in the files to the globally-safe output CSS.

In simpler terms, CSS Modules allows us to use the same class name in multiple files without clashes since each class name is given a unique programmatic name. This is especially useful in larger applications. Every class name is scoped locally to the specific component in which it is being imported.

A CSS Module stylesheet is similar to a regular stylesheet, only with a different extension (e.g. styles.module.css). Here’s how they’re set up:

  1. Create a file with .module.css as the extension.
  2. Import that module into the React app (like we saw earlier)
  3. Add a className to an element or component and reference the particular style from the imported styles.

Super simple example:

/* styles.module.css */ .font { color: #f00; font-size: 20px; } import { React } from "react"; import styles from "./styles.module.css"; function App() { return ( <h1 className={styles.heading}>Hello World</h1> ); } export default App; Use styled-components

Have you used styled-components? It’s quite popular and allows you to build custom components using actual CSS in your JavaScript. A styled-component is basically a React component with — get ready for it — styles. Some of the features include unique class names, dynamic styling and better management of the CSS as each component has its own separate styles.

Install the styled-components npm package in the command line:

npm install styled-components

Next up, import it into the React app:

import styled from 'styled-components'

Create a component and assign a styled property to it. Note the use of template literals denoted by backticks in the Wrapper object:

import { React } from "react"; import styled from "styled-components"; function App() { const Wrapper = styled.div` width: 100%; height: 100px; background-color: red; display: block; `; return <Wrapper />; } export default App;

The above Wrapper component will be rendered as a div that contains those styles.

Conditional styling

One of the advantages of styled-components is that the components themselves are functional, as in you can use props within the CSS. This opens the door up to conditional statements and changing styles based on a state or prop.

Here’s a demo showing that off:

Here, we are manipulating the div’s display property on the display state. This state is controlled by a button that toggles the div’s state when clicked. This, in turn, toggles between the styles of two different states.

In inline if statements, we use a ? instead of the usual if/else syntax. The else part is after the semicolon. And remember to always call or use the state after it has been initialized. In that last demo, for example, the state should be above the Wrapper component’s styles.

Happy React styling!

That’s a wrap, folks! We looked at a handful of different ways to write styles in a React application. And it’s not like one is any better than the rest; the approach you use depends on the situation, of course. Hopefully now you’ve got a good understanding of them and know that you have a bunch of tools in your React styling arsenal.

Different Ways to Write CSS in React originally published on CSS-Tricks. You should get the newsletter.

Single Element Loaders: The Dots

Css Tricks - Fri, 06/17/2022 - 4:47am

We’re looking at loaders in this series. More than that, we’re breaking down some common loader patterns and how to re-create them with nothing more than a single div. So far, we’ve picked apart the classic spinning loader. Now, let’s look at another one you’re likely well aware of: the dots.

Dot loaders are all over the place. They’re neat because they usually consist of three dots that sort of look like a text ellipsis (…) that dances around.

Article series

Our goal here is to make this same thing out of a single div element. In other words, there is no one div per dot or individual animations for each dot.

CodePen Embed Fallback

That example of a loader up above is made with a single div element, a few CSS declarations, and no pseudo-elements. I am combining two techniques using CSS background and mask. And when we’re done, we’ll see how animating a background gradient helps create the illusion of each dot changing colors as they move up and down in succession.

The background animation

Let’s start with the background animation:

.loader { width: 180px; /* this controls the size */ aspect-ratio: 8/5; /* maintain the scale */ background: conic-gradient(red 50%, blue 0) no-repeat, /* top colors */ conic-gradient(green 50%, purple 0) no-repeat; /* bottom colors */ background-size: 200% 50%; animation: back 4s infinite linear; /* applies the animation */ } /* define the animation */ @keyframes back { 0%, /* X Y , X Y */ 100% { background-position: 0% 0%, 0% 100%; } 25% { background-position: 100% 0%, 0% 100%; } 50% { background-position: 100% 0%, 100% 100%; } 75% { background-position: 0% 0%, 100% 100%; } }

I hope this looks pretty straightforward. What we’ve got is a 180px-wide .loader element that shows two conic gradients sporting hard color stops between two colors each — the first gradient is red and blue along the top half of the .loader, and the second gradient is green and purple along the bottom half.

The way the loader’s background is sized (200% wide), we only see one of those colors in each half at a time. Then we have this little animation that pushes the position of those background gradients left, right, and back again forever and ever.

When dealing with background properties — especially background-position — I always refer to my Stack Overflow answer where I am giving a detailed explanation on how all this works. If you are uncomfortable with CSS background trickery, I highly recommend reading that answer to help with what comes next.

In the animation, notice that the first layer is Y=0% (placed at the top) while X is changes from 0% to 100%. For the second layer, we have the same for X but Y=100% (placed at the bottom).

CodePen Embed Fallback

Why using a conic-gradient() instead of linear-gradient()?

Good question! Intuitively, we should use a linear gradient to create a two-color gradients like this:

linear-gradient(90deg, red 50%, blue 0)

But we can also reach for the same using a conic-gradient() — and with less of code. We reduce the code and also learn a new trick in the process!

Sliding the colors left and right is a nice way to make it look like we’re changing colors, but it might be better if we instantly change colors instead — that way, there’s no chance of a loader dot flashing two colors at the same time. To do this, let’s change the animation‘s timing function from linear to steps(1)

CodePen Embed Fallback The loader dots

If you followed along with the first article in this series, I bet you know what comes next: CSS masks! What makes masks so great is that they let us sort of “cut out” parts of a background in the shape of another element. So, in this case, we want to make a few dots, show the background gradients through the dots, and cut out any parts of the background that are not part of a dot.

We are going to use radial-gradient() for this:

.loader { width: 180px; aspect-ratio: 8/5; mask: radial-gradient(#000 68%, #0000 71%) no-repeat, radial-gradient(#000 68%, #0000 71%) no-repeat, radial-gradient(#000 68%, #0000 71%) no-repeat; mask-size: 25% 40%; /* the size of our dots */ }

There’s some duplicated code in there, so let’s make a CSS variable to slim things down:

.loader { width: 180px; aspect-ratio: 8/5; --_g: radial-gradient(#000 68%, #0000 71%) no-repeat; mask: var(--_g),var(--_g),var(--_g); mask-size: 25% 40%; }

Cool cool. But now we need a new animation that helps move the dots up and down between the animated gradients.

.loader { /* same as before */ animation: load 2s infinite; } @keyframes load { /* X Y, X Y, X Y */ 0% { mask-position: 0% 0% , 50% 0% , 100% 0%; } /* all of them at the top */ 16.67% { mask-position: 0% 100%, 50% 0% , 100% 0%; } 33.33% { mask-position: 0% 100%, 50% 100%, 100% 0%; } 50% { mask-position: 0% 100%, 50% 100%, 100% 100%; } /* all of them at the bottom */ 66.67% { mask-position: 0% 0% , 50% 100%, 100% 100%; } 83.33% { mask-position: 0% 0% , 50% 0% , 100% 100%; } 100% { mask-position: 0% 0% , 50% 0% , 100% 0%; } /* all of them at the top */ }

Yes, that’s a total of three radial gradients in there, all with the same configuration and the same size — the animation will update the position of each one. Note that the X coordinate of each dot is fixed. The mask-position is defined such that the first dot is at the left (0%), the second one at the center (50%), and the third one at the right (100%). We only update the Y coordinate from 0% to 100% to make the dots dance.

Here’s what we get:

CodePen Embed Fallback

Now, combine this with our gradient animation and magic starts to happen:

CodePen Embed Fallback Dot loader variations

The CSS variable we made in the last example makes it all that much easier to swap in new colors and create more variations of the same loader. For example, different colors and sizes:

CodePen Embed Fallback

What about another movement for our dots?

CodePen Embed Fallback

Here, all I did was update the animation to consider different positions, and we get another loader with the same code structure!

The animation technique I used for the mask layers can also be used with background layers to create a lot of different loaders with a single color. I wrote a detailed article about this. You will see that from the same code structure we can create different variations by simply changing a few values. I am sharing a few examples at the end of the article.

Why not a loader with one dot?

CodePen Embed Fallback

This one should be fairly easy to grok as I am using the same technique but with a more simple logic:

CodePen Embed Fallback

Here is another example of loader where I am also animating radial-gradient combined with CSS filters and mix-blend-mode to create a blobby effect:

CodePen Embed Fallback

If you check the code, you will see that all I am really doing there is animating the background-position, exactly like we did with the previous loader, but adding a dash of background-size to make it look like the blob gets bigger as it absorbs dots.

If you want to understand the magic behind that blob effect, you can refer to these interactive slides (Chrome only) by Ana Tudor because she covers the topic so well!

Here is another dot loader idea, this time using a different technique:

CodePen Embed Fallback

This one is only 10 CSS declarations and a keyframe. The main element and its two pseudo-elements have the same background configuration with one radial gradient. Each one creates one dot, for a total of three. The animation moves the gradient from top to bottom by using different delays for each dot..

Oh, and take note how this demo uses CSS Grid. This allows us to leverage the grid’s default stretch alignment so that both pseudo-elements cover the whole area of their parent. No need for sizing! Push the around a little with translate() and we’re all set.

More examples!

Just to drive the point home, I want to leave you with a bunch of additional examples that are really variations of what we’ve looked at. As you view the demos, you’ll see that the approaches we’ve covered here are super flexible and open up tons of design possibilities.

CodePen Embed Fallback CodePen Embed Fallback CodePen Embed Fallback CodePen Embed Fallback CodePen Embed Fallback Next up…

OK, so we covered dot loaders in this article and spinners in the last one. In the next article of this four-part series, we’ll turn our attention to another common type of loader: the bars. We’ll take a lot of what we learned so far and see how we can extend them to create yet another single element loader with as little code and as much flexibility as possible.

Article series

Single Element Loaders: The Dots originally published on CSS-Tricks. You should get the newsletter.

De-Mystifying IndieWeb on a WordPress Site

Css Tricks - Tue, 06/14/2022 - 6:48am

Well, sheesh. I opened a little can of worms when sharing Miriam’s “Am I on the IndieWeb yet?” with a short post bemoaning my own trouble getting on the IndieWeb train. But it’s a good can of worms.

I think it was something like the next day after publishing that short post that David Shanske reached out and offered to help wrap my head around IndieWeb and the components that it comprises. And gosh dang if it wasn’t ridiculously helpful! So much so that I’d like to link you up to a new post David wrote after we talked, then summarize things here as best as I can because (1) it’s helpful to write things down and (2) have a reference for later.

Yes, IndieWeb is confusing.

David had actually helped someone get their WordPress site all set up with IndieWeb powers. That person, too, was struggling to understand how the various pieces fit together. So, David already had this top of mind when Miriam and I were writing.

“IndieWeb” is a new term for many folks and that’s where a lot of confusion breeds. Is it a framework? A philosophy? A set of standards? Depending on which one it is, the expectations shift as far as what it looks like to be a part of it.

It’s sort of all of the above. And that needs to be solidified a bit. There’s nothing inherently confusing about IndieWeb itself once you view it through those different lenses. After reading David’s post my understanding is that IndieWeb is more of a set of protocols. Sorta like working with structured data or OpenGraph in markup. There’s nothing to install per se, but there are standards for how to integrate them into your work.

Your identity powers IndieWeb. In other words, your site establishes your identity and can be used to do lots of things, like:

  • Notify other IndieWeb-supported sites when they are mentioned
  • Receive notifications from other IndieWeb sites when you are mentioned
  • Fetch information from a mention and format it for display
  • Authenticate your identity through your own website (a là a Google sign-in button but connected to your site)
  • …among other things.

If that sorta sounds like pingbacks, well, it sorta is. But much more robust and maintained.

It’s different (and perhaps easier) to implement IndieWeb features on WordPress than it is a static site.

The big difference is that WordPress provides a lot of the requirements needed to do IndieWeb-y things. I like how David explains it:

The IndieWeb implementation on WordPress is a [series] of building blocks that you can or cannot choose to use, which is what makes it wonderful, but sometimes confusing. WordPress has a philosophy of decisions, not options. But the IndieWeb is all about options…about building the features that are right for you.

Those building blocks are plugins that you install to add IndieWeb protocols and technologies to WordPress. It’s awesome those are readily available because that takes a a lot of the work out of things. Running a static site, though, you’re on the hook for establishing most of that yourself.

David’s post is 100% focused on the WordPress implementation. Your mileage may vary, but you will certainly walk away with a better idea of what protocols are available and how they fit together after reading his post — and hopefully this one as well.

The IndieWeb WordPress plugin establishes your identity.

I thought it was doing so much stuff behind the scenes, but it’s a lot more simple than that:

The plugin by itself handles establishing your identity as the IndieWeb sees it. It offers an h-card template and widget. H-Card is the markup for marking up information about a person or place. So, this is an element many people opt to put on their site anyway.

So, really, it’s possible to get the same sort of thing by correctly marking up a WordPress theme. The convenience here is that you get a handy little template that’s marked up to support the h-card open format and a widget to drop it into a theme’s widget area.

Here’s a super detailed example of the h-card markup pulled from the documentation for Microformats2:

<div class="h-card"> <img class="u-photo" alt="photo of Mitchell" src="https://webfwd.org/content/about-experts/300.mitchellbaker/mentor_mbaker.jpg"/> <a class="p-name u-url" href="http://blog.lizardwrangler.com/" >Mitchell Baker</a> (<a class="u-url" href="https://twitter.com/MitchellBaker" >@MitchellBaker</a>) <span class="p-org">Mozilla Foundation</span> <p class="p-note"> Mitchell is responsible for setting the direction and scope of the Mozilla Foundation and its activities. </p> <span class="p-category">Strategy</span> <span class="p-category">Leadership</span> </div>

See those class names? Classes like .h-card, u-photo, p-name, etc. all provide contextual meaning for a person’s identity which it then parsed as JSON:

{ "items": [{ "type": ["h-card"], "properties": { "photo": ["https://webfwd.org/content/about-experts/300.mitchellbaker/mentor_mbaker.jpg"], "name": ["Mitchell Baker"], "url": [ "http://blog.lizardwrangler.com/", "https://twitter.com/MitchellBaker" ], "org": ["Mozilla Foundation"], "note": ["Mitchell is responsible for setting the direction and scope of the Mozilla Foundation and its activities."], "category": [ "Strategy", "Leadership" ] } }] }

The plugin isn’t doing the sending, receiving, or parsing. Instead, it provides a WordPress site with a way to verify your identity in the markup.

Not all WordPress themes support Microformats

If you scratched your head first time you saw “Microformats” like I did, David defines it nicely:

[…] Microformats…a way of marking up HTML to allow elements to be identified. It is one of several ways of doing this, but is a very simple and readable one, which is why it is popular in the IndieWeb community.

The problem, as David continues, is that many themes aren’t marked up in a Microformats-friendly way — which is what the Microformats2 plugin is designed to fix. That said, David is quick to call out that the plugin is extremely limited in how it accomplishes this, and he recommends instead marking up a theme by hand.

According to David, the next major release of the Webmention plugin will likely include smarter ways of detecting content and images it can use and formatting them for Microformats2 support.

Webmentions send and receive notifications.

OK, so if you’ve established your identity through your site so you are discoverable, and your site is marked up for h-card support using Microformats2. Great! You still need something in the middle working as an operator that sends and receives notifications. In other words, when another site mentions you — called a Webmention — the site mentioning you needs a way to support sending that mention to you, and your site needs a way to accept it (or vice versa).

That’s what the Webmention plugin is for. It’s also probably the source of most of my IndieWeb confusion. I thought it was formatting data and needed an additional service to send and receive it. Nope! It’s actually sending and receiving the data rather than creating the mention. Back to David:

Back when it was built, the plugin handled only the business of receiving and sending webmentions, not handling display to any degree. Semantic Linkbacks, a separate plugin handled that for not only webmentions, but the older pingback and trackback protocols.

So, the Webmention plugin is communicating notifications. Meanwhile, another plugin called Semantic Linkbacks is what handles the data. And what the heck are Semantic Linkbacks?

Semantic Linkbacks fetch and handle data.

Semantic Linkbacks is another plugin that handles another piece of the process. There’s no way I can explain it better than David already does:

Semantic Linkbacks takes a webmention, which is a notification that another site has linked to something on your site, fetches the other site, and tries to render a display of the information. How that is done can vary from just a profile photo (if it can find one), to interpreting it as a full comment.

It does this using Microformats.

I expected that the main IndieWeb plugin was already doing this since it handles other markup. But it only provides the template and widget to get your identity on your site. Once the Semantic Linkbacks plugin fetches an incoming webmention, it takes the data, formats it, then attempts to display it.

Sounds like the plugin will be somewhat merged with (or replaced by) an upcoming version of the Webmention plugin:

Since many people are not inclined, or not comfortable modifying a theme, the new version of Webmentions will include several different alternative ways to try to find an image or summary to display…from OpenGraph (which Facebook and Twitter use to display URLs provided to it) to detecting the WordPress REST API version of a page and using that to get the author name and profile image. None of them will provided as much context as Microformats, but the experience will still be something worth installing.

That’s certainly nice as it taps into the WordPress REST API for the JSON response and formats that for display.

Brid.gy is a service to help display interactions.

A Webmention can be an interaction, say someone likes your post on Twitter or retweets it.

Differentiating a like from a repost from a comment from a whatever needs to happen, and you’d need to implement the Twitter (or whatever) API to draw those distinctions.

That’s something you can certainly do! But if you’d rather plug and play, one of the IndieWeb community members made a service called Brid.gy. You create an account, hook up your site, and give app permissions to the service… then you’re done!

What Brid.gy has done is essentially implement the APIs for Twitter, Facebook, Instagram, and others, so that when it detects that a post in those services that interacts with your syndicated post, a Webmention is sent to your site and goes through the process of publishing on your own site.

There’s so much more!

Quick hits:

  • IndieAuth: This is a protocol based on OAuth 2. The plugin establishes an endpoint in the WordPress REST API that can be used to authenticate your identity through your own self-hosted site — essentially your own Google sign-in button but without establishing that endpoint yourself or needing to rely on a separate hosted API.
  • Micropub: For those who use WordPress but prefer a different editor can install the Micropub plugin. This adds an endpoint that allows you to publish content to your site and using a Micropub-supported editor create items in a Microformats2 feed, giving you way more options for writing content outside of the WordPress Block Editor.
  • Simple Location: David wrote this plugin and I was super impressed when he demoed it for me. The idea is it pulls in data from your current location that can used for everything from displaying the weather at the time you wrote a post, to creating an entire archive of posts on an embedded map based on the post location. I’d honestly love to see something like this baked directly into WordPress.
The updated flow

I attempted to make an illustration that outlines the various pieces in my last post, but let’s try again with an updated understanding of what’s happening:

(Full size) Is this all making sense?

High fives to David for both reaching out and taking the time to show me what it looks like to implement IndieWeb on WordPress. I can’t claim I fully understand all the nuances, but I at least feel like I have a decent grasp of the pieces — the philosophy, protocols, and tech — that are required to make it happen.

I’d like to turn it around to you! Does this help clarify things for you? Is there anything you’re struggling to understand? Think you’re able to configure a WordPress site with IndieWeb features now? Let’s take it to the comments!

De-Mystifying IndieWeb on a WordPress Site originally published on CSS-Tricks. You should get the newsletter.

Useful Tools for Visualizing Databases on a Budget

Css Tricks - Mon, 06/13/2022 - 9:15am

A diagram is a graphical representation of information that depicts the structure, relationship, or operation of anything. Diagrams enable your audience to visually grasp hidden information and engage with them in ways that words alone cannot. Depending on the type of project, there are numerous ways to use diagrams. For example, if you want to depict the relationship between distinct pieces, we usually use an Entity Relationship Diagram (ERD). There are many great tools that can help you sketch out your database designs beautifully.

In this article, I will be sharing some of my favorite tools that I use to curate my data structures and bring my ideas to life.

Google Docs Drawing

The drawing function in Google Docs allows you to add illustrations to your pages. You can add custom shapes, charts, graphs, infographics, and text boxes to your document with the built-in drawing tool.

Sketching with Google Docs

Although it is simple to add a graphic to your Google Docs, the procedure is not totally visible. Here’s how:

1 . Open a new document on Google Docs.

2 . Click on the insert button and select Drawing . Then, from the drop-down option, choose New to open the drawing screen.

3 . You can use the toolbox on this screen to add text boxes, select lines, and shapes, and modify the colors of your drawing.

4 . You may also use the cursor to adjust the size of your drawings and the color of your designs by using the toolbox at the top of your screen.

5 . When finished, click the Save and close button. You can click on the “File” toolbar displayed on the top of your screen to download your document.

Features CostFree.CLI? GUI? Online?Online.Requires an Account?Yes, a Google account is required.Collaborative Editing?Yes, with Google Drive sharing.Import SQLNot Applicable.Export SQLNot Applicable.Export Formats.doc, .pdf, .rtf, .odt, .txt, .html, .epubGenerate Shareable URLYes.

Google Docs offers amazing convenience. However, diagramming databases is not something it was intended for. You may find yourself frustrated with redrawing arrows and relationships if you are making frequent edits to your model.


Graphviz is a free graph visualization software that allows us to express information diagrammatically.

Graphviz implements the DOT language. The DOT language is an abstract grammar that makes use of terminals, non terminals, parentheses, square brackets, and vertical bars. More information about the DOT language can be found in its documentation.

Features CostFree.CLI? GUI? Online?CLI.
Visual Studio Code, Eclipse, and Notepad++.
Graphical Interfaces.Requires an Account?No.Collaborative Editing?Not Applicable.Import SQLYes, using SQL Graphviz.Export SQLYes, using SQL Graphviz.Export Formats.gif, .png, .jpeg, .json, .pdf and moreGenerate Shareable URLNot Applicable.

Graphviz has an impressive and supportive community. However, a high level of SQL support is only available when you install additional third-party software. This overhead may make it less approachable to users that are not comfortable setting up their computer to support these tools.


ERDPlus is a database modeling tool that allows you to create Entity Relationship Diagrams, Relational Schemas, Star Schemas, and SQL DDL statements.

It includes a brief guide on how to create your ER diagrams, which is especially useful for beginners. You can also easily convert your created ER diagrams to relation schemas.

Features CostFree.CLI? GUI? Online?Online.Requires an Account?Not required, but recommended for saving.Collaborative Editing?Not Applicable.Import SQLNo.Export SQLYes, with the support of SQL DDL statements.Export Formats.pngGenerate Shareable URLNot Applicable.

ERDPlus is suited for SQL. It does lack additional export formats and ability to share with teams, but these features are not necessary with import and export.


Diagrams.net (previously Draw.io) is a free online diagramming tool that can be used to create flowcharts, UML diagrams, database models, and other types of diagrams.

Features CostFree.CLI? GUI? Online?Desktop and Online.Requires an Account?Not required, but recommended for saving.Collaborative Editing?Sharing requires Google Drive or OneDrive.Import SQLYes.Export SQLNo.Export Formats.png, .jpeg, .svg, .pdf, .html and more.Generate Shareable URLYes, export as URL an option.

Diagrams.net is designed to support many different workflows. Its ability to easily integrate with third-party integrations such as Trello, Quip, Notion, and others distinguishes it from the other options. The ability to share and collaborate may make it work well for collaborative teams.


This article is based on using free database tools that could help visualize your ideas and their capabilities with limitations to great details on how to use these tools.

In my research, I also came across other excellent tools with free trials available for creating database diagrams like Lucidchart, EDrawMax, and, DrawSQL. However, these free trials have limitations which may make them less suited for developers working on multiple projects.

I strongly recommend that you read the documentation for each of these tools to determine what works best for you and, most importantly, to avoid any difficulties in using these tools.

Thank you for taking the time to read this far, and I hope you found what you were looking for. Have a wonderful day!

Useful Tools for Visualizing Databases on a Budget originally published on CSS-Tricks. You should get the newsletter.

Single Element Loaders: The Spinner

Css Tricks - Fri, 06/10/2022 - 4:26am

Making CSS-only loaders is one of my favorite tasks. It’s always satisfying to look at those infinite animations. And, of course, there are lots of techniques and approaches to make them — no need to look further than CodePen to see just how many. In this article, though, we will see how to make a single element loader writing as little code as possible.

I have made a collection of more than 500 single div loaders and in this four-part series, I am going to share the tricks I used to create many of them. We will cover a huge number of examples, showing how small adjustments can lead to fun variations, and how little code we need to write to make it all happen!

Single-Element Loaders series:
  1. Single Element Loaders: The Spinner — you are here
  2. Single Element Loaders: The Dots
  3. Single Element Loaders: The Bars
  4. Single Element Loaders: Going 3D

For this first article, we are going to create a one of the more common loader patterns: spinning bars:

CodePen Embed Fallback Here’s the approach

A trivial implementation for this loader is to create one element for each bar wrapped inside a parent element (for nine total elements), then play with opacity and transform to get the spinning effect.

My implementation, though, requires only one element:

<div class="loader"></div>

…and 10 CSS declarations:

.loader { width: 150px; /* control the size */ aspect-ratio: 1; display: grid; mask: conic-gradient(from 22deg, #0003, #000); animation: load 1s steps(8) infinite; } .loader, .loader:before { --_g: linear-gradient(#17177c 0 0) 50%; /* update the color here */ background: var(--_g)/34% 8% space no-repeat, var(--_g)/8% 34% no-repeat space; } .loader:before { content: ""; transform: rotate(45deg); } @keyframes load { to { transform: rotate(1turn); } } Let’s break that down

At first glance, the code may look strange but you will see that it’s more simple than what you might think. The first step is to define the dimension of the element. In our case, it’s a 150px square. We can put aspect-ratio to use so the element stays square no matter what.

.loader { width: 150px; /* control the size */ aspect-ratio: 1; /* make height equal to width */ }

When building CSS loaders, I always try to have one value for controlling the overall size. In this case, it’s the width and all the calculations we cover will refer to that value. This allows me to change a single value to control the loader. It’s always important to be able to easily adjust the size of our loaders without the need to adjust a lot of additional values.

Next, we will use gradients to create the bars. This is the trickiest part! Let’s use one gradient to create two bars like the below:

background: linear-gradient(#17177c 0 0) 50%/34% 8% space no-repeat;

Our gradient is defined with one color and two color stops. The result is a solid color with no fading or transitions. The size is equal to 34% wide and 8% tall. It’s also placed in the center (50%). The trick is the use of the keyword value space — this duplicates the gradient, giving us two total bars.

From the specification:

The image is repeated as often as will fit within the background positioning area without being clipped and then the images are spaced out to fill the area. The first and last images touch the edges of the area.

I am using a width equal to 34% which means we cannot have more than two bars (3*34% is greater than 100%) but with two bars we will have empty spaces (100% - 2 * 34% = 32%). That space is placed in the center between the two bars. In other words, we use a width for the gradient that is between 33% and 50% to make sure we have at least two bars with a little bit of space between them. The value space is what correctly places them for us.

We do the same and make a second similar gradient to get two more bars at the top and bottom, which give us a background property value of:

background: linear-gradient(#17177c 0 0) 50%/34% 8% space no-repeat, linear-gradient(#17177c 0 0) 50%/8% 34% no-repeat space;

We can optimize that using a CSS variable to avoid repetition:

--_g: linear-gradient(#17177c 0 0) 50%; /* update the color here */ background: var(--_g)/34% 8% space no-repeat, var(--_g)/8% 34% no-repeat space;

So, now we have four bars and, thanks to CSS variables, we can write the color value once which makes it easy to update later (like we did with the size of the loader).

To create the remaining bars, let’s tap into the .loader element and its ::before pseudo-element to get four more bars for a grand total of eight in all.

.loader { width: 150px; /* control the size */ aspect-ratio: 1; display: grid; } .loader, .loader::before { --_g: linear-gradient(#17177c 0 0) 50%; /* update the color here */ background: var(--_g)/34% 8% space no-repeat, var(--_g)/8% 34% no-repeat space; } .loader::before { content: ""; transform: rotate(45deg); }

Note the use of display: grid. This allows us to rely on the grid’s default stretch alignment to make the pseudo-element cover the whole area of its parent; thus there’s no need to specify a dimension on it — another trick that reduces the code and avoid us to deal with a lot of values!

Now let’s rotate the pseudo-element by 45deg to position the remaining bars. Hover the following demo to see the trick:

CodePen Embed Fallback Setting opacity

What we’re trying to do is create the impression that there is one bar that leaves a trail of fading bars behind it as it travels a circular path. What we need now is to play with the transparency of our bars to make that trail, which we are going to do with CSS mask combined with a conic-gradient as follows:

mask: conic-gradient(from 22deg,#0003,#000);

To better see the trick, let’s apply this to a full-colored box:

CodePen Embed Fallback

The transparency of the red color is gradually increasing clockwise. We apply this to our loader and we have the bars with different opacity:

In reality, each bar appears to fade because it’s masked by a gradient and falls between two semi-transparent colors. It’s hardly noticeable when this runs, so it’s sort of like being able to say that all the bars have the same color with a different level of opacity.

The rotation

Let’s apply a rotation animation to get our loader. Note, that we need a stepped animation and not a continuous one that’s why I am using steps(8). 8 is nothing but the number of the bars, so that value can be changed depending on how many bars are in use.

.loader { animation: load 3s steps(8) infinite; } /* Same as before: */ @keyframes load { to { transform: rotate(1turn) } } CodePen Embed Fallback

That’s it! We have our loader with only one element and a few lines of CSS. We can easily control its size and color by adjusting one value.

CodePen Embed Fallback

Since we only used the ::before pseudo-element, we can add four more bars by using ::after to end with 12 bars in total and almost the same code:

CodePen Embed Fallback

We update the rotation of our pseudo-elements to consider 30deg and 60deg instead of 45deg while using an twelve-step animation, rather than eight. I also decreased the height to 5% instead of 8% to make the bars a little thinner.

Notice, too, that we have grid-area: 1/1 on the pseudo-elements. This allows us to place them in the same area as one another, stacked on top of each other.

Guess what? We can reach for the same loader using another implementation:

CodePen Embed Fallback

Can you figure out the logic behind the code? Here is a hint: the opacity is no longer handled with a CSS mask but inside the gradient and is also using the opacity property.

Why not dots instead?

We can totally do that:

CodePen Embed Fallback

If you check the code, you will see that we’re now working with a radial gradient instead of a linear one. Otherwise, the concept is exactly the same where the mask creates the impression of opacity, but we made the shapes as circles instead of lines.

Below is a figure to illustrate the new gradient configuration:

If you’re using Safari, note that the demo may be buggy. That’s because Safari currently lacks support for the at syntax in radial gradients. But we can reconfigure the gradient a bit to overcome that:

.loader, .loader:before, .loader:after { background: radial-gradient( circle closest-side, currentColor 90%, #0000 98% ) 50% -150%/20% 80% repeat-y, radial-gradient( circle closest-side, currentColor 90%, #0000 98% ) -150% 50%/80% 20% repeat-x; } CodePen Embed Fallback More loader examples

Here is another idea for a spinner loader similar to the previous one.

CodePen Embed Fallback

For this one, I am only relying on background and mask to create the shape (no pseudo-elements needed). I am also defining the configuration with CSS variables to be able to create a lot of variations from the same code — another example of just the powers of CSS variables. I wrote another article about this technique if you want to more details.

Note that some browsers still rely on a -webkit- prefix for mask-composite with its own set of values, and will not display the spinner in the demo. Here is a way to do it without mast-composite for more browser support.

I have another one for you:

CodePen Embed Fallback

For this one, I am using a background-color to control the color, and use mask and mask-composite to create the final shape:

Before we end, here are some more spinning loaders I made a while back. I am relying on different techniques but still using gradients, masks, pseudo-element, etc. It could be a good exercise to figure out the logic of each one and learn new tricks at the same time. This said, if you have any question about them, the comment section is down below.

CodePen Embed Fallback CodePen Embed Fallback CodePen Embed Fallback Wrapping up

See, there’s so much we can do in CSS with nothing but a single div, a couple of gradients, pseudo-elements, variables. It seems like we created a whole bunch of different spinning loaders, but they’re all basically the same thing with slight modifications.

This is only the the beginning. In this series, we will be looking at more ideas and advanced concepts for creating CSS loaders.

Single-Element Loaders series:
  1. Single Element Loaders: The Spinner — you are here
  2. Single Element Loaders: The Dots
  3. Single Element Loaders: The Bars
  4. Single Element Loaders: Going 3D

Single Element Loaders: The Spinner originally published on CSS-Tricks. You should get the newsletter.

Am I on the IndieWeb yet?

Css Tricks - Thu, 06/09/2022 - 5:32am

Can’t smash the Like button hard enough for what Miriam Suzanne has to say on the challenging technical hurdles of implementing Webmentions:

The first round required several online services along with HTML & JS changes to my static site, just to verify my indieweb identity. Then more changes to the site and more online services to help fetch any mentions (so far, nothing to see, but that’s probably expected). It seems the only way to test the setup is to launch all those changes publicly, and then ask for other devs to send you mentions.


I’m an experienced web developer, and I can figure it out. But the steps aren’t simple, and most of my friends are not web developers. So, to me, this all feels like the prototype of an idea – a proof of concept.

A proof of concept for sure. And one that has been around for quite some time. The IndieWeb idea of owning your own data and using your website as a social hub is right up my alley — and likely yours, too, as someone working on the front end.

Update! David Shanske is one of the developers of the WordPress plugins that support IndieWeb features and he not only published a wonderful explanation of how everything fits together, but also reached out directly and helped me wrap it all around my head.

Yet, I’ve tinkered on and off with it — specifically Webmentions — over the past like three years with little to show for it. The problem isn’t so much the documentation of getting started because it’s all there. It’s more a combination of things…

  • The wiki is confusing. Wikis are super cool in general, but the non-linear nature of it makes it tough to know where to start and where to end.
  • The plugin ecosystem is complex. My personal site is on WordPress and there’s a plugin designed to make it easy to integrate IndieWeb features on it. Except that it’s really one plugin that steers you to install several others, each one introducing a technology that I honestly struggle to understand.
  • There’s a bunch of terms to learn. I mean, “IndieWeb” and “Webmention” are already difficult to grok. Toss in things like “Micropub,” “Microformats,” “IndieAuth,” and “Semantic Linkbacks,” and suddenly it feels like a bunch of puzzle pieces from different puzzles trying to fit together.
  • Some middleware seems necessary? For example, I had to give a service called Bridgy access to my Twitter to get that activity going. It apparently has something to do with Twitter’s shortened t.co URLs and making them play well with microformats.

But, like Miriam, I struggled my way through it and got something working in the end. This is the sort of visual I wish I had when I was first getting started, and maybe it’ll help you too.

Feels like a lot to get Webmentions going, but maybe that’s only because I have such a light grasp of the tech and how it all fits together. All the pieces are there, though, and even with the initial struggle, I love the IndieWeb concept, er prototype.

To Shared LinkPermalink on CSS-Tricks

Am I on the IndieWeb yet? originally published on CSS-Tricks. You should get the newsletter.

Let’s Make a QR Code Generator With a Serverless Function!

Css Tricks - Wed, 06/08/2022 - 4:30am

QR codes are funny, right? We love them, then hate them, then love them again. Anyways, they’ve lately been popping up again and it got me thinking about how they’re made. There are like a gazillion QR code generators out there, but say it’s something you need to do on your own website. This package can do that. But it’s also weighs in at a hefty 180 KB for everything it needs to generate stuff. You wouldn’t want to serve all that along with the rest of your scripts.

Now, I’m relatively new to the concept of cloud functions, but I hear that’s the bee’s knees for something just like this. That way, the function lives somewhere on a server that can be called when it’s needed. Sorta like a little API to run the function.

Some hosts offer some sort of cloud function feature. DigitalOcean happens to be one of them! And, like Droplets, functions are pretty easy to deploy.

Create a functions folder locally

DigitalOcean has a CLI that with a command that’ll scaffold things for us, so cd wherever you want to set things up and run:

doctl serverless init --language js qr-generator

Notice the language is explicitly declared. DigitalOcean functions also support PHP and Python.

We get a nice clean project called qr-generator with a /packages folder that holds all the project’s functions. There’s a sample function in there, but we can overlook it for now and create a qr folder right next to it:

That folder is where both the qrcode package and our qr.js function are going to live. So, let’s cd into packages/sample/qr and install the package:

npm install --save qrcode

Now we can write the function in a new qr.js file:

const qrcode = require('qrcode') exports.main = (args) => { return qrcode.toDataURL(args.text).then(res => ({ headers: { 'content-type': 'text/html; charset=UTF-8' }, body: args.img == undefined ? res : `<img src="${res}">` })) } if (process.env.TEST) exports.main({text:"hello"}).then(console.log)

All that’s doing is requiring the the qrcode package and exporting a function that basically generates an <img> tag with the a base64 PNG for the source. We can even test it out in the terminal:

doctl serverless functions invoke sample/qr -p "text:css-tricks.com" Check the config file

There is one extra step we need here. When the project was scaffolded, we got this little project.yml file and it configures the function with some information about it. This is what’s in there by default:

targetNamespace: '' parameters: {} packages: - name: sample environment: {} parameters: {} annotations: {} actions: - name: hello binary: false main: '' runtime: 'nodejs:default' web: true parameters: {} environment: {} annotations: {} limits: {}

See those highlighted lines? The packages: name property is where in the packages folder the function lives, which is a folder called sample in this case. The actions/ name property is the name of the function itself, which is the name of the file. It’s hello by default when we spin up the project, but we named ours qr.js, so we oughta change that line from hello to qr before moving on.

Deploy the function

We can do it straight from the command line! First, we connect to the DigitalOcean sandbox environment so we have a live URL for testing:

## You will need an DO API key handy doctl sandbox connect

Now we can deploy the function:

doctl sandbox deploy qr-generator

Once deployed, we can access the function at a URL. What’s the URL? There’s a command for that:

doctl sbx fn get sample/qr --url https://faas-nyc1-2ef2e6cc.doserverless.co/api/v1/web/fn-10a937cb-1f12-427b-aadd-f43d0b08d64a/sample/qr

Heck yeah! No more need to ship that entire package with the rest of the scripts! We can hit that URL and generate the QR code from there.


We fetch the API and that’s really all there is to it!

CodePen Embed Fallback

Let’s Make a QR Code Generator With a Serverless Function! originally published on CSS-Tricks. You should get the newsletter.

Building Interoperable Web Components That Even Work With React

Css Tricks - Tue, 06/07/2022 - 3:57am

Those of us who’ve been web developers more than a few years have probably written code using more than one JavaScript framework. With all the choices out there — React, Svelte, Vue, Angular, Solid — it’s all but inevitable. One of the more frustrating things we have to deal with when working across frameworks is re-creating all those low-level UI components: buttons, tabs, dropdowns, etc. What’s particularly frustrating is that we’ll typically have them defined in one framework, say React, but then need to rewrite them if we want to build something in Svelte. Or Vue. Or Solid. And so on.

Wouldn’t it be better if we could define these low-level UI components once, in a framework-agnostic way, and then re-use them between frameworks? Of course it would! And we can; web components are the way. This post will show you how.

As of now, the SSR story for web components is a bit lacking. Declarative shadow DOM (DSD) is how a web component is server-side rendered, but, as of this writing, it’s not integrated with your favorite application frameworks like Next, Remix or SvelteKit. If that’s a requirement for you, be sure to check the latest status of DSD. But otherwise, if SSR isn’t something you’re using, read on.

First, some context

Web Components are essentially HTML elements that you define yourself, like <yummy-pizza> or whatever, from the ground up. They’re covered all over here at CSS-Tricks (including an extensive series by Caleb Williams and one by John Rhea) but we’ll briefly walk through the process. Essentially, you define a JavaScript class, inherit it from HTMLElement, and then define whatever properties, attributes and styles the web component has and, of course, the markup it will ultimately render to your users.

Being able to define custom HTML elements that aren’t bound to any particular component is exciting. But this freedom is also a limitation. Existing independently of any JavaScript framework means you can’t really interact with those JavaScript frameworks. Think of a React component which fetches some data and then renders some other React component, passing along the data. This wouldn’t really work as a web component, since a web component doesn’t know how to render a React component.

Web components particularly excel as leaf components. Leaf components are the last thing to be rendered in a component tree. These are the components which receive some props, and render some UI. These are not the components sitting in the middle of your component tree, passing data along, setting context, etc. — just pure pieces of UI that will look the same, no matter which JavaScript framework is powering the rest of the app.

The web component we’re building

Rather than build something boring (and common), like a button, let’s build something a little bit different. In my last post we looked at using blurry image previews to prevent content reflow, and provide a decent UI for users while our images load. We looked at base64 encoding a blurry, degraded versions of our images, and showing that in our UI while the real image loaded. We also looked at generating incredibly compact, blurry previews using a tool called Blurhash.

That post showed you how to generate those previews and use them in a React project. This post will show you how to use those previews from a web component so they can be used by any JavaScript framework.

But we need to walk before we can run, so we’ll walk through something trivial and silly first to see exactly how web components work.

Everything in this post will build vanilla web components without any tooling. That means the code will have a bit of boilerplate, but should be relatively easy to follow. Tools like Lit or Stencil are designed for building web components and can be used to remove much of this boilerplate. I urge you to check them out! But for this post, I’ll prefer a little more boilerplate in exchange for not having to introduce and teach another dependency.

A simple counter component

Let’s build the classic “Hello World” of JavaScript components: a counter. We’ll render a value, and a button that increments that value. Simple and boring, but it’ll let us look at the simplest possible web component.

In order to build a web component, the first step is to make a JavaScript class, which inherits from HTMLElement:

class Counter extends HTMLElement {}

The last step is to register the web component, but only if we haven’t registered it already:

if (!customElements.get("counter-wc")) { customElements.define("counter-wc", Counter); }

And, of course, render it:


And everything in between is us making the web component do whatever we want it to. One common lifecycle method is connectedCallback, which fires when our web component is added to the DOM. We could use that method to render whatever content we’d like. Remember, this is a JS class inheriting from HTMLElement, which means our this value is the web component element itself, with all the normal DOM manipulation methods you already know and love.

At it’s most simple, we could do this:

class Counter extends HTMLElement { connectedCallback() { this.innerHTML = "<div style='color: green'>Hey</div>"; } } if (!customElements.get("counter-wc")) { customElements.define("counter-wc", Counter); }

…which will work just fine.

Adding real content

Let’s add some useful, interactive content. We need a <span> to hold the current number value and a <button> to increment the counter. For now, we’ll create this content in our constructor and append it when the web component is actually in the DOM:

constructor() { super(); const container = document.createElement('div'); this.valSpan = document.createElement('span'); const increment = document.createElement('button'); increment.innerText = 'Increment'; increment.addEventListener('click', () => { this.#value = this.#currentValue + 1; }); container.appendChild(this.valSpan); container.appendChild(document.createElement('br')); container.appendChild(increment); this.container = container; } connectedCallback() { this.appendChild(this.container); this.update(); }

If you’re really grossed out by the manual DOM creation, remember you can set innerHTML, or even create a template element once as a static property of your web component class, clone it, and insert the contents for new web component instances. There’s probably some other options I’m not thinking of, or you can always use a web component framework like Lit or Stencil. But for this post, we’ll continue to keep it simple.

Moving on, we need a settable JavaScript class property named value

#currentValue = 0; set #value(val) { this.#currentValue = val; this.update(); }

It’s just a standard class property with a setter, along with a second property to hold the value. One fun twist is that I’m using the private JavaScript class property syntax for these values. That means nobody outside our web component can ever touch these values. This is standard JavaScript that’s supported in all modern browsers, so don’t be afraid to use it.

Or feel free to call it _value if you prefer. And, lastly, our update method:

update() { this.valSpan.innerText = this.#currentValue; }

It works!

Obviously this is not code you’d want to maintain at scale. Here’s a full working example if you’d like a closer look. As I’ve said, tools like Lit and Stencil are designed to make this simpler.

Adding some more functionality

This post is not a deep dive into web components. We won’t cover all the APIs and lifecycles; we won’t even cover shadow roots or slots. There’s endless content on those topics. My goal here is to provide a decent enough introduction to spark some interest, along with some useful guidance on actually using web components with the popular JavaScript frameworks you already know and love.

To that end, let’s enhance our counter web component a bit. Let’s have it accept a color attribute, to control the color of the value that’s displayed. And let’s also have it accept an increment property, so consumers of this web component can have it increment by 2, 3, 4 at a time. And to drive these state changes, let’s use our new counter in a Svelte sandbox — we’ll get to React in a bit.

We’ll start with the same web component as before and add a color attribute. To configure our web component to accept and respond to an attribute, we add a static observedAttributes property that returns the attributes that our web component listens for.

static observedAttributes = ["color"];

With that in place, we can add a attributeChangedCallback lifecycle method, which will run whenever any of the attributes listed in observedAttributes are set, or updated.

attributeChangedCallback(name, oldValue, newValue) { if (name === "color") { this.update(); } }

Now we update our update method to actually use it:

update() { this.valSpan.innerText = this._currentValue; this.valSpan.style.color = this.getAttribute("color") || "black"; }

Lastly, let’s add our increment property:

increment = 1;

Simple and humble.

Using the counter component in Svelte

Let’s use what we just made. We’ll go into our Svelte app component and add something like this:

<script> let color = "red"; </script> <style> main { text-align: center; } </style> <main> <select bind:value={color}> <option value="red">Red</option> <option value="green">Green</option> <option value="blue">Blue</option> </select> <counter-wc color={color}></counter-wc> </main>

And it works! Our counter renders, increments, and the dropdown updates the color. As you can see, we render the color attribute in our Svelte template and, when the value changes, Svelte handles the legwork of calling setAttribute on our underlying web component instance. There’s nothing special here: this is the same thing it already does for the attributes of any HTML element.

Things get a little bit interesting with the increment prop. This is not an attribute on our web component; it’s a prop on the web component’s class. That means it needs to be set on the web component’s instance. Bear with me, as things will wind up much simpler in a bit.

First, we’ll add some variables to our Svelte component:

let increment = 1; let wcInstance;

Our powerhouse of a counter component will let you increment by 1, or by 2:

<button on:click={() => increment = 1}>Increment 1</button> <button on:click={() => increment = 2}>Increment 2</button>

But, in theory, we need to get the actual instance of our web component. This is the same thing we always do anytime we add a ref with React. With Svelte, it’s a simple bind:this directive:

<counter-wc bind:this={wcInstance} color={color}></counter-wc>

Now, in our Svelte template, we listen for changes to our component’s increment variable and set the underlying web component property.

$: { if (wcInstance) { wcInstance.increment = increment; } }

You can test it out over at this live demo.

We obviously don’t want to do this for every web component or prop we need to manage. Wouldn’t it be nice if we could just set increment right on our web component, in markup, like we normally do for component props, and have it, you know, just work? In other words, it’d be nice if we could delete all usages of wcInstance and use this simpler code instead:

<counter-wc increment={increment} color={color}></counter-wc>

It turns out we can. This code works; Svelte handles all that legwork for us. Check it out in this demo. This is standard behavior for pretty much all JavaScript frameworks.

So why did I show you the manual way of setting the web component’s prop? Two reasons: it’s useful to understand how these things work and, a moment ago, I said this works for “pretty much” all JavaScript frameworks. But there’s one framework which, maddeningly, does not support web component prop setting like we just saw.

React is a different beast

React. The most popular JavaScript framework on the planet does not support basic interop with web components. This is a well-known problem that’s unique to React. Interestingly, this is actually fixed in React’s experimental branch, but for some reason wasn’t merged into version 18. That said, we can still track the progress of it. And you can try this yourself with a live demo.

The solution, of course, is to use a ref, grab the web component instance, and manually set increment when that value changes. It looks like this:

import React, { useState, useRef, useEffect } from 'react'; import './counter-wc'; export default function App() { const [increment, setIncrement] = useState(1); const [color, setColor] = useState('red'); const wcRef = useRef(null); useEffect(() => { wcRef.current.increment = increment; }, [increment]); return ( <div> <div className="increment-container"> <button onClick={() => setIncrement(1)}>Increment by 1</button> <button onClick={() => setIncrement(2)}>Increment by 2</button> </div> <select value={color} onChange={(e) => setColor(e.target.value)}> <option value="red">Red</option> <option value="green">Green</option> <option value="blue">Blue</option> </select> <counter-wc ref={wcRef} increment={increment} color={color}></counter-wc> </div> ); } Live demo

As we discussed, coding this up manually for every web component property is simply not scalable. But all is not lost because we have a couple of options.

Option 1: Use attributes everywhere

We have attributes. If you clicked the React demo above, the increment prop wasn’t working, but the color correctly changed. Can’t we code everything with attributes? Sadly, no. Attribute values can only be strings. That’s good enough here, and we’d be able to get somewhat far with this approach. Numbers like increment can be converted to and from strings. We could even JSON stringify/parse objects. But eventually we’ll need to pass a function into a web component, and at that point we’d be out of options.

Option 2: Wrap it

There’s an old saying that you can solve any problem in computer science by adding a level of indirection (except the problem of too many levels of indirection). The code to set these props is pretty predictable and simple. What if we hide it in a library? The smart folks behind Lit have one solution. This library creates a new React component for you after you give it a web component, and list out the properties it needs. While clever, I’m not a fan of this approach.

Rather than have a one-to-one mapping of web components to manually-created React components, what I prefer is just one React component that we pass our web component tag name to (counter-wc in our case) — along with all the attributes and properties — and for this component to render our web component, add the ref, then figure out what is a prop and what is an attribute. That’s the ideal solution in my opinion. I don’t know of a library that does this, but it should be straightforward to create. Let’s give it a shot!

This is the usage we’re looking for:

<WcWrapper wcTag="counter-wc" increment={increment} color={color} />

wcTag is the web component tag name; the rest are the properties and attributes we want passed along.

Here’s what my implementation looks like:

import React, { createElement, useRef, useLayoutEffect, memo } from 'react'; const _WcWrapper = (props) => { const { wcTag, children, ...restProps } = props; const wcRef = useRef(null); useLayoutEffect(() => { const wc = wcRef.current; for (const [key, value] of Object.entries(restProps)) { if (key in wc) { if (wc[key] !== value) { wc[key] = value; } } else { if (wc.getAttribute(key) !== value) { wc.setAttribute(key, value); } } } }); return createElement(wcTag, { ref: wcRef }); }; export const WcWrapper = memo(_WcWrapper);

The most interesting line is at the end:

return createElement(wcTag, { ref: wcRef });

This is how we create an element in React with a dynamic name. In fact, this is what React normally transpiles JSX into. All our divs are converted to createElement("div") calls. We don’t normally need to call this API directly but it’s there when we need it.

Beyond that, we want to run a layout effect and loop through every prop that we’ve passed to our component. We loop through all of them and check to see if it’s a property with an in check that checks the web component instance object as well as its prototype chain, which will catch any getters/setters that wind up on the class prototype. If no such property exists, it’s assumed to be an attribute. In either case, we only set it if the value has actually changed.

If you’re wondering why we use useLayoutEffect instead of useEffect, it’s because we want to immediately run these updates before our content is rendered. Also, note that we have no dependency array to our useLayoutEffect; this means we want to run this update on every render. This can be risky since React tends to re-render a lot. I ameliorate this by wrapping the whole thing in React.memo. This is essentially the modern version of React.PureComponent, which means the component will only re-render if any of its actual props have changed — and it checks whether that’s happened via a simple equality check.

The only risk here is that if you’re passing an object prop that you’re mutating directly without re-assigning, then you won’t see the updates. But this is highly discouraged, especially in the React community, so I wouldn’t worry about it.

Before moving on, I’d like to call out one last thing. You might not be happy with how the usage looks. Again, this component is used like this:

<WcWrapper wcTag="counter-wc" increment={increment} color={color} />

Specifically, you might not like passing the web component tag name to the <WcWrapper> component and prefer instead the @lit-labs/react package above, which creates a new individual React component for each web component. That’s totally fair and I’d encourage you to use whatever you’re most comfortable with. But for me, one advantage with this approach is that it’s easy to delete. If by some miracle React merges proper web component handling from their experimental branch into main tomorrow, you’d be able to change the above code from this:

<WcWrapper wcTag="counter-wc" increment={increment} color={color} />

…to this:

<counter-wc ref={wcRef} increment={increment} color={color} />

You could probably even write a single codemod to do that everywhere, and then delete <WcWrapper> altogether. Actually, scratch that: a global search and replace with a RegEx would probably work.

The implementation

I know, it seems like it took a journey to get here. If you recall, our original goal was to take the image preview code we looked at in my last post, and move it to a web component so it can be used in any JavaScript framework. React’s lack of proper interop added a lot of detail to the mix. But now that we have a decent handle on how to create a web component, and use it, the implementation will almost be anti-climactic.

I’ll drop the entire web component here and call out some of the interesting bits. If you’d like to see it in action, here’s a working demo. It’ll switch between my three favorite books on my three favorite programming languages. The URL for each book will be unique each time, so you can see the preview, though you’ll likely want to throttle things in your DevTools Network tab to really see things taking place.

View entire code class BookCover extends HTMLElement { static observedAttributes = ['url']; attributeChangedCallback(name, oldValue, newValue) { if (name === 'url') { this.createMainImage(newValue); } } set preview(val) { this.previewEl = this.createPreview(val); this.render(); } createPreview(val) { if (typeof val === 'string') { return base64Preview(val); } else { return blurHashPreview(val); } } createMainImage(url) { this.loaded = false; const img = document.createElement('img'); img.alt = 'Book cover'; img.addEventListener('load', () =&gt; { if (img === this.imageEl) { this.loaded = true; this.render(); } }); img.src = url; this.imageEl = img; } connectedCallback() { this.render(); } render() { const elementMaybe = this.loaded ? this.imageEl : this.previewEl; syncSingleChild(this, elementMaybe); } }

First, we register the attribute we’re interested in and react when it changes:

static observedAttributes = ['url']; attributeChangedCallback(name, oldValue, newValue) { if (name === 'url') { this.createMainImage(newValue); } }

This causes our image component to be created, which will show only when loaded:

createMainImage(url) { this.loaded = false; const img = document.createElement('img'); img.alt = 'Book cover'; img.addEventListener('load', () => { if (img === this.imageEl) { this.loaded = true; this.render(); } }); img.src = url; this.imageEl = img; }

Next we have our preview property, which can either be our base64 preview string, or our blurhash packet:

set preview(val) { this.previewEl = this.createPreview(val); this.render(); } createPreview(val) { if (typeof val === 'string') { return base64Preview(val); } else { return blurHashPreview(val); } }

This defers to whichever helper function we need:

function base64Preview(val) { const img = document.createElement('img'); img.src = val; return img; } function blurHashPreview(preview) { const canvasEl = document.createElement('canvas'); const { w: width, h: height } = preview; canvasEl.width = width; canvasEl.height = height; const pixels = decode(preview.blurhash, width, height); const ctx = canvasEl.getContext('2d'); const imageData = ctx.createImageData(width, height); imageData.data.set(pixels); ctx.putImageData(imageData, 0, 0); return canvasEl; }

And, lastly, our render method:

connectedCallback() { this.render(); } render() { const elementMaybe = this.loaded ? this.imageEl : this.previewEl; syncSingleChild(this, elementMaybe); }

And a few helpers methods to tie everything together:

export function syncSingleChild(container, child) { const currentChild = container.firstElementChild; if (currentChild !== child) { clearContainer(container); if (child) { container.appendChild(child); } } } export function clearContainer(el) { let child; while ((child = el.firstElementChild)) { el.removeChild(child); } }

It’s a little bit more boilerplate than we’d need if we build this in a framework, but the upside is that we can re-use this in any framework we’d like — although React will need a wrapper for now, as we discussed.

Odds and ends

I’ve already mentioned Lit’s React wrapper. But if you find yourself using Stencil, it actually supports a separate output pipeline just for React. And the good folks at Microsoft have also created something similar to Lit’s wrapper, attached to the Fast web component library.

As I mentioned, all frameworks not named React will handle setting web component properties for you. Just note that some have some special flavors of syntax. For example, with Solid.js, <your-wc value={12}> always assumes that value is a property, which you can override with an attr prefix, like <your-wc attr:value={12}>.

Wrapping up

Web components are an interesting, often underused part of the web development landscape. They can help reduce your dependence on any single JavaScript framework by managing your UI, or “leaf” components. While creating these as web components — as opposed to Svelte or React components — won’t be as ergonomic, the upside is that they’ll be widely reusable.

Building Interoperable Web Components That Even Work With React originally published on CSS-Tricks. You should get the newsletter.

Please Give Me Some Space

Css Tricks - Fri, 06/03/2022 - 4:39am

There’s all kinds of ways to do that. Some more advisable and better-suited for certain situations than others, of course.

We could do it directly in HTML:

<p>We go from one line...<br><br> down a couple more.</p>

But that’s what CSS is really for:

<p>We go from one line...<span>down a couple more.</span></p> span { display: block; margin-block-start: 1.5rem; }

Line height can also give us extra breathing room between lines of text:

p { line-height: 1.35; }

Since we’re talking text, there’s also letter-spacing and word-spacing, not to mention text-indent:

CodePen Embed Fallback

But let’s talk boxes instead of text. Say we have two simple divs:

<div>Twiddle Dee</div> <div>Twiddle Dum</div>

Those are block-level so they’re already on different lines. We can reach for margin again. Or we could create the impression of space with padding. I suppose we could translate those suckers in either direction:

div:nth-child(2) { transform: translateY(100px); }

But maybe those elements are absolutely positioned so we can use physical offsets:

div { position: absolute; } div:nth-child(1) { inset: 0; } div:nth-child(2) { inset-inline-start: 100px; /* or top: 100px; */ }

If we’re working in a grid container, then we get gap-age:

<section> <div>Twiddle Dee</div> <div>Twiddle Dum</div> </section> section { display: grid; grid-template-columns: 1fr 1fr; gap: 100px; }

Same deal with a flexible container:

section { display: flex; gap: 100px; }

While we’re working in grid and flexible containers, we could call on any alignment property to generate space.

section { display: flex; align-items: space-between; justify-content: space-between; }

There are tables, of course:

<table cellspacing="100"> <!-- etc. --> <tbody> <tr> <td>Twiddle Dee</td> <td>Twiddle Dum</td> </tr> </tbody> </table>

Or the CSS-y approach:

/* We could use `display: table` if we're not working in a table element. */ table { border-spacing: 100px; }

Let’s go deeper into left field. We can make one element look like two using a linear gradient with a hard color stop:

div { background-image: linear-gradient( to right, rgb(255 105 0 / 1) 50%, rgb(207 46 46 / 1) 50%, rgb(207 46 46 / 1) 100% ); }

Then we do a head fake and insert a hard transparent color stop between the two colors:

CodePen Embed Fallback

As long as we’re fakin’ bacon here, might as well toss in the ol’ “transparent” border trick:

CodePen Embed Fallback

Let’s go back to text for a moment. Maybe we’re floating an element and want text to wrap around it… in the shape of the floated element while leaving some space between the two. We have shape-margin for that:

CodePen Embed Fallback

Dare I even mention the spacer.gif days?

<div>Twiddle Dee</div> <img src="spacer.gif"> <!-- &#x1f922; --> <div>Twiddle Dum</div> There’s gotta be more

You’re all a smart bunch with great ideas. Have at it!

Please Give Me Some Space originally published on CSS-Tricks. You should get the newsletter.

How to Create Block Theme Patterns in WordPress 6.0

Css Tricks - Wed, 06/01/2022 - 5:30am

Block patterns, also frequently referred to as sections, were introduced in WordPress 5.5 to allow users to build and share predefined block layouts in the pattern directory. The directory is the home of a wide range of curated patterns designed by the WordPress community. These patterns are available in simple copy and paste format, require no coding knowledge and thus are a big time saver for users.

Despite many articles on patterns, there is a lack of comprehensive and up-to-date articles on pattern creation covering the latest enhanced features. This article aims to fill the gap with a focus on the recent enhanced features like creating patterns without registration and offer an up-to-date step-by-step guide to create and use them in block themes for novices and experienced authors.

Since the launch of WordPress 5.9 and the Twenty Twenty-Two (TT2) default theme, the use of block patterns in block themes has proliferated. I have been a big fan of block patterns and have created and used them in my block themes.

The new WordPress 6.0 offers three major patterns feature enhancements to authors:

  • Allowing pattern registration through /patterns folder (similar to /parts, /templates, and /styles registration).
  • Registering patterns from the public patterns directory using the theme.json.
  • Adding patterns that can be offered to the user when creating a new page.

In an introductory Exploring WordPress 6.0 video, Automattic product liaison Ann McCathy highlights some newly enhanced patterns features (starting at 15:00) and discusses future patterns enhancement plans — which include patterns as sectioning elements, providing options to pick pattern on page creation, integrating pattern directory search, and more.


The article assumes that readers have basic knowledge of WordPress full site editing (FSE) interface and block themes. The Block Editor Handbook and Full Site Editing website provide the most up-to-date tutorial guides to learn all FSE features, including block themes and patterns discussed in this article.

Section 1: Evolving approaches to creating block patterns

The initial approach to creating block patterns required the use of block pattern API either as a custom plugin or directly registered in the functions.php file to bundle with a block theme. The newly launched WordPress 6.0 introduced several new and enhanced features working with patterns and themes, including pattern registration via a /patterns folder and a page creation pattern modal.

For background, let’s first briefly overview how the pattern registration workflow evolved from using the register pattern API to directly loading without registration.

Use case example 1: Twenty Twenty-One

The default Twenty Twenty-One theme (TT1) and TT1 Blocks theme (a sibling of TT1) showcase how block patterns can be registered in the theme’s functions.php. In the TT1 Blocks experimental-theme, this single block-pattern.php file containing eight block patterns is added to the functions.php as an include as shown here.

A custom block pattern needs to be registered using the register_block_pattern function, which receives two arguments — title (name of the patterns) and properties (an array describing properties of the pattern).

Here is an example of registering a simple “Hello World” paragraph pattern from this Theme Shaper article:

register_block_pattern( 'my-plugin/hello-world', array( 'title' => __( 'Hello World', 'my-plugin' ), 'content' => "<!-- wp:paragraph -->\n<p>Hello World</p>\n<!-- /wp:paragraph -->", ) );

After registration, the register_block_pattern() function should be called from a handler attached to the init hook as described here.

function my_plugin_register_my_patterns() { register_block_pattern( ... ); } add_action( 'init', 'my_plugin_register_my_patterns' );

Once block patterns are registered they are visible in the block editor. More detailed documentation is found in this Block Pattern Registration.

Block pattern properties

In addition to required title and content properties, the block editor handbook lists the following optional pattern properties:

  • title (required): A human-readable title for the pattern.
  • content (required): Block HTML Markup for the pattern.
  • description (optional): A visually hidden text used to describe the pattern in the inserter. A description is optional but it is strongly encouraged when the title does not fully describe what the pattern does. The description will help users discover the pattern while searching.
  • categories (optional): An array of registered pattern categories used to group block patterns. Block patterns can be shown on multiple categories. A category must be registered separately in order to be used here.
  • keywords (optional): An array of aliases or keywords that help users discover the pattern while searching.
  • viewportWidth (optional): An integer specifying the intended width of the pattern to allow for a scaled preview of the pattern in the inserter.
  • blockTypes (optional): An array of block types that the pattern is intended to be used with. Each value needs to be the declared block’s name.
  • inserter (optional): By default, all patterns will appear in the inserter. To hide a pattern so that it can only be inserted programmatically, set the inserter to false.

The following is an example of a quote pattern plugin code snippets taken from the WordPress blog.

/* Plugin Name: Quote Pattern Example Plugin */ register_block_pattern( 'my-plugin/my-quote-pattern', array( 'title' => __( 'Quote with Avatar', 'my-plugin' ), 'categories' => array( 'text' ), 'description' => _x( 'A big quote with an avatar".', 'Block pattern description', 'my-plugin' ), 'content' => '<!-- wp:group --><div class="wp-block-group"><div class="wp-block-group__inner-container"><!-- wp:separator {"className":"is-style-default"} --><hr class="wp-block-separator is-style-default"/><!-- /wp:separator --><!-- wp:image {"align":"center","id":553,"width":150,"height":150,"sizeSlug":"large","linkDestination":"none","className":"is-style-rounded"} --><div class="wp-block-image is-style-rounded"><figure class="aligncenter size-large is-resized"><img src="https://blockpatterndesigns.mystagingwebsite.com/wp-content/uploads/2021/02/StockSnap_HQR8BJFZID-1.jpg" alt="" class="wp-image-553" width="150" height="150"/></figure></div><!-- /wp:image --><!-- wp:quote {"align":"center","className":"is-style-large"} --><blockquote class="wp-block-quote has-text-align-center is-style-large"><p>"Contributing makes me feel like I\'m being useful to the planet."</p><cite>— Anna Wong, <em>Volunteer</em></cite></blockquote><!-- /wp:quote --><!-- wp:separator {"className":"is-style-default"} --><hr class="wp-block-separator is-style-default"/><!-- /wp:separator --></div></div><!-- /wp:group -->', ) );

Using patterns in a template file

Once patterns are created, they can be used in a theme template file with the following block markup:

<!-- wp:pattern {"slug":"prefix/pattern-slug"} /-->

An example from this GitHub repository shows the use of “footer-with-background” pattern slug with “tt2gopher” prefix in TT2 Gopher blocks theme.

Early adopters of block themes and Gutenberg plugin took advantage of patterns in classic themes as well. The default Twenty Twenty and my favorite Eksell themes (a demo site here) are good examples that showcase how pattern features can be added to classic themes.

Use case example 2: Twenty Twenty-Two

If a theme includes only a few patterns, the development and maintenance are fairly manageable. However, if a block theme includes many patterns, like in TT2 theme, then the pattern.php file becomes very large and hard to read. The default TT2 theme, which bundles more than 60 patterns, showcases a refactored pattern registration workflow structure that is easier to read and maintain.

Taking examples from the TT2 theme, let’s briefly discuss how this simplified workflow works.

2.1: Registering Patterns Categories

For demonstration purposes, I created a TT2 child theme and set it up on my local test site with some dummy content. Following TT2, I registered footer-with-background and added to the following pattern categories array list in its block-patterns.php file.

/** * Registers block patterns and categories. */ function twentytwentytwo_register_block_patterns() { $block_pattern_categories = array( 'footer' => array( 'label' => __( 'Footers', 'twentytwentytwo' ) ), 'header' => array( 'label' => __( 'Headers', 'twentytwentytwo' ) ), 'pages' => array( 'label' => __( 'Pages', 'twentytwentytwo' ) ), // ... ); /** * Filters the theme block pattern categories. */ $block_pattern_categories = apply_filters( 'twentytwentytwo_block_pattern_categories', $block_pattern_categories ); foreach ( $block_pattern_categories as $name => $properties ) { if ( ! WP_Block_Pattern_Categories_Registry::get_instance()->is_registered( $name ) ) { register_block_pattern_category( $name, $properties ); } } $block_patterns = array( 'footer-default', 'footer-dark', 'footer-with-background', //... 'header-default', 'header-large-dark', 'header-small-dark', 'hidden-404', 'hidden-bird', //... ); /** * Filters the theme block patterns. */ $block_patterns = apply_filters( 'twentytwentytwo_block_patterns', $block_patterns ); foreach ( $block_patterns as $block_pattern ) { $pattern_file = get_theme_file_path( '/inc/patterns/' . $block_pattern . '.php' ); register_block_pattern( 'twentytwentytwo/' . $block_pattern, require $pattern_file ); } } add_action( 'init', 'twentytwentytwo_register_block_patterns', 9 );

In this code example, each pattern listed in the $block_patterns = array() is called by foreach() function which requires a patterns directory file with the listed pattern name in the array which we will add in the next step.

2.2: Adding a pattern file to the /inc/patterns folder

Next, we should have all the listed patterns files in the $block_patterns = array(). Here is an example of one of the pattern files, footer-with-background.php:

/** * Dark footer wtih title and citation */ return array( 'title' => __( 'Footer with background', 'twentytwentytwo' ), 'categories' => array( 'footer' ), 'blockTypes' => array( 'core/template-part/footer' ), 'content' => '<!-- wp:group {"align":"full","style":{"elements":{"link":{"color":{"text":"var:preset|color|background"}}},"spacing":{"padding":{"top":"var(--wp--custom--spacing--small, 1.25rem)","bottom":"var(--wp--custom--spacing--small, 1.25rem)"}}},"backgroundColor":"background-header","textColor":"background","layout":{"inherit":true}} --> <div class="wp-block-group alignfull has-background-color has-background-header-background-color has-text-color has-background has-link-color" style="padding-top:var(--wp--custom--spacing--small, 1.25rem);padding-bottom:var(--wp--custom--spacing--small, 1.25rem)"><!-- wp:paragraph {"align":"center"} --> <p class="has-text-align-center">' . sprintf( /* Translators: WordPress link. */ esc_html__( 'Proudly powered by %s', 'twentytwentytwo' ), '<a href="' . esc_url( __( 'https://wordpress.org', 'twentytwentytwo' ) ) . '" rel="nofollow">WordPress</a> | a modified TT2 theme.' ) . '</p> <!-- /wp:paragraph --></div> <!-- /wp:group -->', );

Let’s reference the pattern in the footer.html template part:

<!-- wp:template-part {"slug":"footer"} /-->

This is similar to adding heading or footer parts in a template file.

The patterns can similarly be added to the parts/footer.html template by modifying it to refer to slug of the theme’s pattern file (footer-with-background):

<!-- wp:pattern {"slug":"twentytwentytwo/footer-with-background"} /-->

Now, if we visit the patterns inserter of the block editor, the Footer with background should be available for our use:

The following screenshot shows the newly created footer with background pattern on the front-end.

Now that patterns have become the integral part of block theme, many patterns are bundled in block themes — like Quadrat, Seedlet, Mayland, Zoologist, Geologist — following the workflow discussed above. Here is an example of the Quadrat theme /inc/patterns folder with a block-pattern registration file and list of files with content source and required pattern header within return array() function.

Section 2: Creating and loading patterns without registration

Please note that this feature requires the installation of WordPress 6.0 or Gutenberg plugin 13.0 or above in your site.

This new WordPress 6.0 feature allows pattern registration via standard files and folders – /patterns, bringing similar conventions like /parts, /templates, and /styles.

The process, as also described in this WP Tavern article, involves the following three steps:

  • creating a patterns folder at the theme’s root
  • adding plugin style pattern header
  • pattern source content

A typical pattern header markup, taken from the article is shown below:

<?php /** * Title: A Pattern Title * Slug: namespace/slug * Description: A human-friendly description. * Viewport Width: 1024 * Categories: comma, separated, values * Keywords: comma, separated, values * Block Types: comma, separated, values * Inserter: yes|no */ ?>

As described in the previous section, only Title and Slug fields are required and other fields are optional.

Referencing examples from recently released themes, I refactored pattern registration in this TT2 Gopher Blocks demo theme, prepared for a previous article on the CSS-Tricks.

In the following steps, let’s explore how a footer-with-background.php pattern registered with PHP and used in a footer.html template is refactored.

2.1: Create a /patterns folder at the root of the theme

The first step is to create a /patterns folder at TT2 Gopher theme’s root and move the footer-with-background.php pattern file to /patterns folder and refactor.

2.2: Add pattern data to the file header

Next, create the following pattern header registration fields.

<?php /** * Title: Footer with background * Slug: tt2gopher/footer-with-background * Categories: tt2gopher-footer * Viewport Width: 1280 * Block Types: core/parts/footer * Inserter: yes */ ?> <!-- some-block-content /-->

A pattern file has a top title field written as PHP comments. Followed by the block-content written in HTML format.

2.3: Add Pattern Content to the file

For the content section, let’s copy the code snippets within single quotes (e.g., '...') from the content section of the footer-with-background and replace the <!-- some-block-content /-->:

<!-- wp:group {"align":"full","style":{"elements":{"link":{"color":{"text":"var:preset|color|foreground"}}},"spacing":{"padding":{"top":"35px","bottom":"30px"}}},"backgroundColor":"background-header","textColor":"foreground","className":"has-foreground","layout":{"inherit":true}} --> <div class="wp-block-group alignfull has-foreground has-foreground-color has-background-header-background-color has-text-color has-background has-link-color" style="padding-top:35px;padding-bottom:30px"><!-- wp:paragraph {"align":"center","fontSize":"small"} --> <p class="has-text-align-center has-small-font-size">Powered by WordPress | TT2 Gopher, a modified TT2 theme</p> <!-- /wp:paragraph --></div> <!-- /wp:group -->

The entire code snippet of the patterns/footer-with-background.php file can be viewed here on the GitHub.

Please note that the /inc/patterns and block-patterns.php are extras, not required in WordPress 6.0, and included only for demo purposes.

2.4: Referencing the patterns slug in the template

Adding the above refactored footer-with-background.php pattern to footer.html template is exactly the same as described in the previous section (Section 1, 2.2).

Now, if we view the site’s footer part in a block editor or front-end of our site in a browser, the footer section is displayed.

Pattern categories and types Registration (optional)

To categorize block patterns, the pattern categories and types should be registered in theme’s functions.php file.

Let’s consider an example of registering block pattern categories from the TT2 Gopher theme.

After the registration, the patterns are displayed in the pattern inserter together with the core default patterns. To add theme specific category labels in the patterns inserter, we should modify the previous snippets by adding theme namespace:

/** * Registers block categories, and type. */ function tt2gopher_register_block_pattern_categories() { $block_pattern_categories = array( 'tt2gopher-header' => array( 'label' => __( 'TT2 Gopher - Headers', 'tt2gopher' ) ), 'tt2gopher-footer' => array( 'label' => __( 'TT2 Gopher - Footers', 'tt2gopher' ) ), 'tt2gopher-page' => array( 'label' => __( 'TT2 Gopher - Page', 'tt2gopher' ) ), // ... ); /** * Filters the theme block pattern categories. */ $block_pattern_categories = apply_filters( 'tt2gopher_block_pattern_categories', $block_pattern_categories ); foreach ( $block_pattern_categories as $name => $properties ) { if ( ! WP_Block_Pattern_Categories_Registry::get_instance()->is_registered( $name ) ) { register_block_pattern_category( $name, $properties ); } } add_action( 'init', 'tt2gopher_register_block_pattern_categories', 9 );

The footer-with-background pattern is visible in the patterns inserted with its preview (if selected):

This process greatly simplifies creating and displaying block patterns in block themes. It is available in WordPress 6.0 without using the Gutenberg plugin.

Examples of themes without patterns registration

Early adopters have already started using this feature in their block themes. A few examples of the themes, that are available from the theme directory, that load patterns without registration are listed below:

Section 3: Creating and using patterns with low-code

The official patterns directory contains community-contributed creative designs, which can be copied and customized as desired to create content. Using patterns with a block editor has never been so easier!

Any patterns from the ever-growing directory can also be added to block themes just by simple “copy and paste” or include in the theme.json file by referring to their directory pattern slug. Next, I will go through briefly how easily this can be accomplished with very limited coding.

Adding and customizing patterns from patterns directory

3.1: Copy pattern from directory into a page

Here, I am using this footer section pattern by FirstWebGeek from the patterns directory. Copied the pattern by selecting the “Copy Pattern” button and directly pasted it in a new page.

3.2: Make desired customizations

I made only a few changes to the color of the fonts and button background. Then copied the entire code from the code editor over to a clipboard.

If you are not familiar with using the code editor, go to options (with three dots, top right), click the Code editor button, and copy the entire code from here.

3.3: Create a new file in /patterns folder

First, let’s create a new /patterns/footer-pattern-test.php file and add the required pattern header section. Then paste the entire code (step 3, above). The pattern is categorized in the footer area (lines: 5), we can view the newly added in the pattern inserter.

<?php /** * Title: Footer pattern from patterns library * Slug: tt2gopher/footer-pattern-test * Categories: tt2gopher-footer * Viewport Width: 1280 * Block Types: core/template-part/footer * Inserter: yes */ ?> <!-- wp:group {"align":"full","style":{"spacing":{"padding":{"top":"100px","bottom":"70px","right":"30px","left":"30px"}}},"backgroundColor":"black","layout":{"contentSize":"1280px"}} --> <div class="wp-block-group alignfull has-black-background-color has-background" style="padding-top:100px;padding-right:30px;padding-bottom:70px;padding-left:30px"><!-- wp:columns --> <div class="wp-block-columns"><!-- wp:column --> <div class="wp-block-column"><!-- wp:heading {"style":{"typography":{"fontStyle":"normal","fontWeight":"700","textTransform":"uppercase"}},"textColor":"cyan-bluish-gray"} --> <h2 class="has-cyan-bluish-gray-color has-text-color" style="font-style:normal;font-weight:700;text-transform:uppercase">lorem</h2> <!-- /wp:heading --> <!-- wp:paragraph {"style":{"typography":{"fontSize":"16px"}},"textColor":"cyan-bluish-gray"} --> <p class="has-cyan-bluish-gray-color has-text-color" style="font-size:16px">One of the main benefits of using Lorem Ipsum is that it can be easily generated, and it takes the pressure off designers to create meaningful text. Instead, they can focus on crafting the best website data.</p> <!-- /wp:paragraph --> <!-- wp:social-links {"iconColor":"vivid-cyan-blue","iconColorValue":"#0693e3","openInNewTab":true,"className":"is-style-logos-only","style":{"spacing":{"blockGap":{"top":"15px","left":"15px"}}}} --> <ul class="wp-block-social-links has-icon-color is-style-logos-only"><!-- wp:social-link {"url":"#","service":"facebook"} /--> <!-- wp:social-link {"url":"#","service":"twitter"} /--> <!-- wp:social-link {"url":"#","service":"instagram"} /--> <!-- wp:social-link {"url":"#","service":"linkedin"} /--></ul> <!-- /wp:social-links --></div> <!-- /wp:column --> <!-- wp:column --> <div class="wp-block-column"><!-- wp:heading {"level":4,"style":{"typography":{"textTransform":"capitalize","fontStyle":"normal","fontWeight":"700","fontSize":"30px"}},"textColor":"cyan-bluish-gray"} --> <h4 class="has-cyan-bluish-gray-color has-text-color" style="font-size:30px;font-style:normal;font-weight:700;text-transform:capitalize">Contact Us</h4> <!-- /wp:heading --> <!-- wp:paragraph {"style":{"typography":{"fontSize":"16px","lineHeight":"1.2"}},"textColor":"cyan-bluish-gray"} --> <p class="has-cyan-bluish-gray-color has-text-color" style="font-size:16px;line-height:1.2">123 BD Lorem, Ipsum<br><br>+123-456-7890</p> <!-- /wp:paragraph --> <!-- wp:paragraph {"style":{"typography":{"fontSize":"16px","lineHeight":"1"}},"textColor":"cyan-bluish-gray"} --> <p class="has-cyan-bluish-gray-color has-text-color" style="font-size:16px;line-height:1">sample@gmail.com</p> <!-- /wp:paragraph --> <!-- wp:paragraph {"style":{"typography":{"fontSize":"16px","lineHeight":"1"}},"textColor":"cyan-bluish-gray"} --> <p class="has-cyan-bluish-gray-color has-text-color" style="font-size:16px;line-height:1">Opening Hours: 10:00 - 18:00</p> <!-- /wp:paragraph --></div> <!-- /wp:column --> <!-- wp:column --> <div class="wp-block-column"><!-- wp:heading {"level":4,"style":{"typography":{"fontSize":"30px","fontStyle":"normal","fontWeight":"700","textTransform":"capitalize"}},"textColor":"cyan-bluish-gray"} --> <h4 class="has-cyan-bluish-gray-color has-text-color" style="font-size:30px;font-style:normal;font-weight:700;text-transform:capitalize">Newsletter</h4> <!-- /wp:heading --> <!-- wp:paragraph {"style":{"typography":{"fontSize":"16px"}},"textColor":"cyan-bluish-gray"} --> <p class="has-cyan-bluish-gray-color has-text-color" style="font-size:16px">Lorem ipsum dolor sit amet, consectetur ut labore et dolore magna aliqua ipsum dolor sit</p> <!-- /wp:paragraph --> <!-- wp:search {"label":"","placeholder":"Enter Your Email...","buttonText":"Subscribe","buttonPosition":"button-inside","style":{"border":{"width":"1px"}},"borderColor":"tertiary","backgroundColor":"background-header","textColor":"background"} /--></div> <!-- /wp:column --></div> <!-- /wp:columns --></div> <!-- /wp:group -->

3.4: View the new pattern in the inserter

To view the newly added Footer pattern from patterns library pattern, go to any post or page and select the inserter icon (blue plus symbol, top left), and then select “TT2 Gopher – Footer” categories. The newly added pattern is shown on the left panel, together with other footer patterns and its preview on the right (if selected):

Registering patterns directly in theme.json file

In WordPress 6.0, it is possible to register any desired patterns from the pattern directory with theme.json file with the following syntax. The 6.0 dev note states, “the patterns field is an array of [pattern slugs] from the Pattern Directory. Pattern slugs can be extracted by the [URL] in single pattern view at the Pattern Directory.”

{ "version": 2, "patterns": ["short-text", "patterns-slug"] }

This short WordPress 6.0 features video demonstrates how patterns are registered in the /patterns folder (at 3:53) and registering the desired patterns from the pattern director in a theme.json file (at 3:13).

Then, the registered pattern is available in the patterns inserter search box, which is then available for use just like theme-bundled patterns library.

{ "version": 2, "patterns": [ "footer-from-directory", "footer-section-design-with-3-column-description-social-media-contact-and-newsletter" ] }

In this example, the pattern slug footer-section-design-with-3-column-description-social-media-contact-and-newsletter from the earlier example is registered via theme.json.

Page creation pattern model

As part of “building with patterns” initiatives, WordPress 6.0 offers a pattern modal option to theme authors to add page layout patterns into block theme, allowing site users to select page layout patterns (e.g., an about page, a contact page, a team page, etc.) while creating a page. The following is an example taken from the dev note:

register_block_pattern( 'my-plugin/about-page', array( 'title' => __( 'About page', 'my-plugin' ), 'blockTypes' => array( 'core/post-content' ), 'content' => '<!-- wp:paragraph {"backgroundColor":"black","textColor":"white"} --> <p class="has-white-color has-black-background-color has-text-color has-background">Write you about page here, feel free to use any block</p> <!-- /wp:paragraph -->', ) );

This feature is currently limited to Page Post Type only and not for “Posts Post Type”, yet.

The page creation pattern modal can also be disabled completely by removing the post-content block type of all the patterns. An example sample code is available here.

You can follow and participate in GitHub’s discussion from the links listed under the resource section below.

Using patterns directory to build page

Patterns from the directory can also be used to create the desired post or page layout, similar to page builders. The GutenbergHub team has created an experimental online page builder app using patterns directly from the directory (introductory video). Then the codes from the app can be copied and pasted in a site, which greatly simplifies the building complex page layout process without coding.

In this short video, Jamie Marsland demonstrates (at 1:30) how the app can be used to create an entire page layout similar to page builder using desired page sections of the directory.

Wrapping up

Patterns allow users to recreate their commonly used content layout (e.g., hero page, call out, etc.) in any page and lower the barriers to presenting content in styles, which were previously not possible without coding skills. Just like the plugins and themes directories, the new patterns directory offers users options to use a wide range of patterns of their choices from the pattern directory, and write and display content in style.

Indeed, block patterns will change everything and surely this is a game changer feature in the WordPress theme landscape. When the full potential of building with patterns effort becomes available, this is going to change the way we design block themes and create beautiful content even with low-code knowledge. For many creative designers, the patterns directory may also provide an appropriate avenue to showcase their creativity.

Resources WordPress 6.0 Creating patterns Patterns enhancement (GitHub) Blog articles

How to Create Block Theme Patterns in WordPress 6.0 originally published on CSS-Tricks. You should get the newsletter.

SPAs, Shared Element Transitions, and Re-Evaluating Technology

Css Tricks - Wed, 06/01/2022 - 4:12am

Nolan Lawson sparked some discussion when he described a noticeable shift away from single-page applications (SPAs):

Hip new frameworks like Astro, Qwik, and Elder.js are touting their MPA [multi-page application] with “0kB JavaScript by default.” Blog posts are making the rounds listing all the challenges with SPAs: history, focus management, scroll restoration, Cmd/Ctrl-click, memory leaks, etc. Gleeful potshots are being taken against SPAs.

I think what’s less discussed, though, is how the context has changed in recent years to give MPAs more of an upper hand against SPAs.

It seems a number of folks really clung to that first part because Nolan published a follow-up to clarify that SPAs are far from doomed:

[T]he point of my post wasn’t to bury SPAs and dance on their grave. I think SPAs are great, I’ve worked on many of them, and I think they have a bright future ahead of them. My main point was: if the only reason you’re using an SPA is because “it makes navigations faster,” then maybe it’s time to re-evaluate that.

And there’s good reason he says that. In fact, the first article specifically points to work being done on Shared Element Transitions. If they move forward, we’ll have an API for animating/transitioning/sizing/positioning elements on page entrance and exist. Jake Archibald demonstrated how it works at Google I/O 2022 and the video is a gem.

If you’re wondering how one page can transition into another, the browser takes screenshots of the outgoing page and the incoming page, then transitions between those. So, it’s not so much one page becoming another as much as it is the browser holding onto two images so it can animate one in while the other animates out. Jake says what’s happening behind the scene is a DOM structure is created out of pseudo-elements containing the page images:

<transition-container> <image-wrapper> <outgoing-image /> <incoming-image /> </> </>

We can “screenshot” a specific element if we want to isolate it and apply a different animation from the rest of the page:

.site-header { page-transition-tag: site-header; contain: paint; }

And we get pseudo-elements we can hook into and assign custom @keyframe animations:

<!-- ::page-transition=container(root) --> <transition-container> <!-- ::page-transition-image-wrapper(root) --> <image-wrapper> <!-- ::page-transition-outgoing-image(root) --> <outgoing-image /> <!-- ::page-transition-incoming-image(root) --> <incoming-image /> </> </>

Dang, that’s clever as heck!

It’s also proof in the pudding of just how much HTML, CSS, and JavaScript continue to evolve and improve. So much so that Jeremy Keith suggests it’s high time we re-evaluate our past judgment of some technologies:

If you weren’t aware of changes over the past few years, it would be easy to still think that single page apps offer some unique advantages that in fact no longer hold true. […] But developers remain suspicious, still prefering to trust third-party libraries over native browser features. They made a decision about those libraries in the past. They evaluated the state of browser support in the past. I wish they would re-evaluate those decisions.

The ingredients for SPAs specifically:

In recent years in particular it feels like the web has come on in leaps and bounds: service workers, native JavaScript APIs, and an astonishing boost in what you can do with CSS. Most important of all, the interoperability between browsers is getting better and better. Universal support for new web standards arrives at a faster rate than ever before.

HTML, CSS, and JavaScript: it’s still the best cocktail in town. Even if it takes a minute for it to catch up.

SPAs, Shared Element Transitions, and Re-Evaluating Technology originally published on CSS-Tricks. You should get the newsletter.

Just How Long Should Alt Text Be?

Css Tricks - Fri, 05/27/2022 - 4:25am

I teach a class over at the local college here in Long Beach and a majority of the content is hosted on the Canvas LMS so students can access it online. And, naturally, I want the content to be as accessible as possible, so thank goodness Canvas has a11y tooling built right into it.

But it ain’t all that rosy. It makes assumptions like all other a11y tooling and adheres to guidelines that were programmed into it. It’s not like the WCAG is baked right in and updated when it updates.

The reason this is even on my mind is that Jeremy yesterday described his love for writing image descriptions:

I enjoy writing alt text. I recently described how I updated my posting interface here on my own site to put a textarea for alt text front and centre for my notes with photos. Since then I’ve been enjoying the creative challenge of writing useful—but also evocative—alt text.

I buy into that! Writing alt text is a challenge that requires a delicate dance between the technical and the creative. It’s both an opportunity to make content more accessible and enhance the user experience.

One of those programmed guidelines in the Canvas tool is a cap of 120 characters on alt text. Why 120? I dunno, I couldn’t find any supporting guideline or rule for that exact number. One answer is that screen readers stop announcing text after 125 characters, but that’s apparently untrue, at least today. The general advice for how long alt text should be comes in varying degrees:

  • Jake Archibald talks of length in terms of emotion. Detail is great, but too much detail might distort the focal point, which makes total sense.
  • Dave sees them as short, succinct paragraphs.
  • Carrie Fisher suggests a 150-character limit not because screen readers will truncate them but more as a mental note that maybe things are getting too descriptive.
  • Daniel Göransson says in this 2017 guide that it comes down to context and knowing when certain details of an image are worth additional explanation. But he generally errs on the side of conciseness.

So, how long should alt text be? The general consensus here is that there is no hard limit, but more of a contextual awareness of what purpose the image serves and adapting to it accordingly.

Which gets me back to Jeremy’s article. He was writing alt text for a group of speaker headshots and realized the text was all starting to sound the same. He paused, thought about the experience, compared it to the experience of a sighted user, and created parity between them:

The more speakers were added to the line-up, the more I felt like I was repeating myself with the alt text. […] The experience of a sighted person looking at a page full of speakers is that after a while the images kind of blend together. So if the alt text also starts to sound a bit repetitive after a while, maybe that’s not such a bad thing. A screen reader user would be getting an equivalent experience.

I dig that. So if you’re looking for a hard and fast rule on character counts, sorry to disappoint. Like so many other things, context is king and that’s the sort of thing that can’t be codified, or even automated for that matter.

And while we’re on the topic, just noticed that Twitter has UI to display alt text:

Now if only there was more contrast between that text and the background… a11y is hard.

Just How Long Should Alt Text Be? originally published on CSS-Tricks. You should get the newsletter.

Beautify GitHub Profile

Css Tricks - Thu, 05/26/2022 - 8:13am

It wasn’t long ago that Nick Sypteras showed us how to make custom badges for a GitHub repo. Well, Reza Shakeri put Beautify GitHub Profile together and it’s a huuuuuuge repo of different badges that pulls lots of examples together with direct links to the repos you can use to create them.

And it doesn’t stop there! If you’re looking for some sort of embeddable widget, there’s everything from GitHub repo stats and contribution visualizations, all the way to embedded PageSpeed Insights and Spotify playlists. Basically, a big ol’ spot to get some inspiration.

Some things are simply wild!

I bet Jhey would like to get his hands on those cuboids!

Just scrolling through the repo gives me flashes of the GeoCities days, though. All it needs is a sparkly unicorn and a tiled background image to complete the outfit. &#x1f454;

To Shared LinkPermalink on CSS-Tricks

Beautify GitHub Profile originally published on CSS-Tricks. You should get the newsletter.

Syndicate content
©2003 - Present Akamai Design & Development.