Web Standards

Using SVG in WordPress (2 Helpful Plugin Recommendations)

Css Tricks - Fri, 01/21/2022 - 9:35am

There is a little legwork to do if you plan on using SVG in WordPress. For fair-enough reasons, WordPress doesn’t allow SVG out of the box. SVG is a markup syntax that has lots of power, including the ability to load other resources and run JavaScript. So, if WordPress were to blanket-ly allow SVG by default, users even with quite limited roles could upload SVG and cause problems, like XSS vulnerabilities.

But say that’s not a problem for your site and you just use SVG gosh darn it. First, let’s be clear what we mean by using SVG in WordPress: uploading SVG through the media uploader and using the SVG images within post content and as featured images.

There is nothing stopping you from, say, using SVG in your templates. Meaning inline <svg> or SVG files you link up as images in your template from your CSS or whatnot. That’s completely fine and you don’t need to do anything special for that to work in WordPress.

Taking matters into your own hands

What prevents you from using SVG in WordPress is that the Media Library Uploader rejects the file’s MIME type. To allow SVG in WordPress, you really just need this filter. This would go in your functions.php or a functionality plugin:

function cc_mime_types($mimes) { $mimes['svg'] = 'image/svg+xml'; return $mimes; } add_filter('upload_mimes', 'cc_mime_types');

But the problem after that is that the SVG file usually won’t display correctly in the various places it needs to, like the Media Library’s image previews, the Featured Image widget, and possibly even the classic or Block Editor. I have a snippet of CSS that can be injected to fix this. But — and this is kinda why I’m writing this new post — that doesn’t seem to work for me anymore, which has got me thinking.

Plugins for using SVG in WordPress

I used to think, eh, why bother, it’s so little code to allow this might that I may as well just do it myself with the function. But WordPress, of course, has a way of shifting over time, and since supporting SVG isn’t something WordPress is going to do out of the box, this is actually a great idea for a plugin to handle. That way, the SVG plugin can evolve to handle quirks as WordPress evolves and, theoretically, if enough people use the SVG plugin, it will be maintained.

So, with that, here are a couple of plugin recommendations for using SVG in WordPress.

SVG Support

This is the one I’ve been using lately and it seems to work great for me.

I just install it, activate it, and do nothing else. It does have a settings screen, but I don’t need any of those things. I really like how it asks you if it’s OK to load additional CSS on the front-end (for me, it’s not OK, so I leave it off) — although even better would be for the plugin to show you what it’s going to load so you can add it to your own CSS if you want.

The setting to restrict uploading SVG in WordPress to admins is smart, although if you want to be more serious about SVG safety, you could use this next plugin instead…

Safe SVG

This one hasn’t been updated in years, but it goes the extra mile for SVG safety in that it literally sanitizes SVG files as you upload them, and even optimizes them while it adds the SVG in WordPress.

We have fairly tight editorial control over authors and such here on this site, so the security aspects of this SVG plugin aren’t a big worry to me. Plus, I like to be in charge of my own SVG optimization, so this one isn’t as perfect for me, though I’d probably recommend it to a site with less technical expertise at the site owner level.

Looks like there is Easy SVG Support as well, but it doesn’t seem to be as nice as the Support SVG plugin and hasn’t been updated recently, so I can’t recommend that.

What plugins have you successfully tried for using SVG in WordPress? Any recommendations you’d like to add?

Using SVG in WordPress (2 Helpful Plugin Recommendations) originally published on CSS-Tricks. You should get the newsletter and become a supporter.

Context-Aware Web Components Are Easier Than You Think

Css Tricks - Fri, 01/21/2022 - 4:08am

Another aspect of web components that we haven’t talked about yet is that a JavaScript function is called whenever a web component is added or removed from a page. These lifecycle callbacks can be used for many things, including making an element aware of its context.

Article series The four lifecycle callbacks of web components

There are four lifecycle callbacks that can be used with web components:

  • connectedCallback: This callback fires when the custom element is attached to the element.
  • disconnectedCallback: This callback fires when the element is removed from the document.
  • adoptedCallback: This callback fires when the element is added to a new document.
  • attributeChangedCallback: This callback fires when an attribute is changed, added or removed, as long as that attribute is being observed.

Let’s look at each of these in action.

Our post-apocalyptic person component

We’ll start by creating a web component called <postapocalyptic-person>. Every person after the apocalypse is either a human or a zombie and we’ll know which one based on a class — either .human or .zombie — that’s applied to the parent element of the <postapocalyptic-person> component. We won’t do anything fancy with it (yet), but we’ll add a shadowRoot we can use to attach a corresponding image based on that classification.

customElements.define( "postapocalyptic-person", class extends HTMLElement { constructor() { super(); const shadowRoot = this.attachShadow({ mode: "open" }); } }

Our HTML looks like this:

<div class="humans"> <postapocalyptic-person></postapocalyptic-person> </div> <div class="zombies"> <postapocalyptic-person></postapocalyptic-person> </div> Inserting people with connectedCallback

When a <postapocalyptic-person> is loaded on the page, the connectedCallback() function is called.

connectedCallback() { let image = document.createElement("img"); if (this.parentNode.classList.contains("humans")) { image.src = "https://assets.codepen.io/1804713/lady.png"; this.shadowRoot.appendChild(image); } else if (this.parentNode.classList.contains("zombies")) { image.src = "https://assets.codepen.io/1804713/ladyz.png"; this.shadowRoot.appendChild(image); } }

This makes sure that an image of a human is output when the <postapocalyptic-person> is a human, and a zombie image when the component is a zombie.

CodePen Embed Fallback

Be careful working with connectedCallback. It runs more often than you might realize, firing any time the element is moved and could (baffling-ly) even run after the node is no longer connected — which can be an expensive performance cost. You can use this.isConnected to know whether the element is connected or not.

Counting people with connectedCallback() when they are added

Let’s get a little more complex by adding a couple of buttons to the mix. One will add a <postapocalyptic-person>, using a “coin flip” approach to decide whether it’s a human or a zombie. The other button will do the opposite, removing a <postapocalyptic-person> at random. We’ll keep track of how many humans and zombies are in view while we’re at it.

<div class="btns"> <button id="addbtn">Add Person</button> <button id="rmvbtn">Remove Person</button> <span class="counts"> Humans: <span id="human-count">0</span> Zombies: <span id="zombie-count">0</span> </span> </div>

Here’s what our buttons will do:

let zombienest = document.querySelector(".zombies"), humancamp = document.querySelector(".humans"); document.getElementById("addbtn").addEventListener("click", function () { // Flips a "coin" and adds either a zombie or a human if (Math.random() > 0.5) { zombienest.appendChild(document.createElement("postapocalyptic-person")); } else { humancamp.appendChild(document.createElement("postapocalyptic-person")); } }); document.getElementById("rmvbtn").addEventListener("click", function () { // Flips a "coin" and removes either a zombie or a human // A console message is logged if no more are available to remove. if (Math.random() > 0.5) { if (zombienest.lastElementChild) { zombienest.lastElementChild.remove(); } else { console.log("No more zombies to remove"); } } else { if (humancamp.lastElementChild) { humancamp.lastElementChild.remove(); } else { console.log("No more humans to remove"); } } });

Here’s the code in connectedCallback() that counts the humans and zombies as they are added:

connectedCallback() { let image = document.createElement("img"); if (this.parentNode.classList.contains("humans")) { image.src = "https://assets.codepen.io/1804713/lady.png"; this.shadowRoot.appendChild(image); // Get the existing human count. let humancount = document.getElementById("human-count"); // Increment it humancount.innerHTML = parseInt(humancount.textContent) + 1; } else if (this.parentNode.classList.contains("zombies")) { image.src = "https://assets.codepen.io/1804713/ladyz.png"; this.shadowRoot.appendChild(image); // Get the existing zombie count. let zombiecount = document.getElementById("zombie-count"); // Increment it zombiecount.innerHTML = parseInt(zombiecount.textContent) + 1; } } Updating counts with disconnectedCallback

Next, we can use disconnectedCallback() to decrement the number as a humans and zombies are removed. However, we are unable to check the class of the parent element because the parent element with the corresponding class is already gone by the time disconnectedCallback is called. We could set an attribute on the element, or add a property to the object, but since the image’s src attribute is already determined by its parent element, we can use that as a proxy for knowing whether the web component being removed is a human or zombie.

disconnectedCallback() { let image = this.shadowRoot.querySelector('img'); // Test for the human image if (image.src == "https://assets.codepen.io/1804713/lady.png") { let humancount = document.getElementById("human-count"); humancount.innerHTML = parseInt(humancount.textContent) - 1; // Decrement count // Test for the zombie image } else if (image.src == "https://assets.codepen.io/1804713/ladyz.png") { let zombiecount = document.getElementById("zombie-count"); zombiecount.innerHTML = parseInt(zombiecount.textContent) - 1; // Decrement count } } CodePen Embed Fallback Beware of clowns!

Now (and I’m speaking from experience here, of course) the only thing scarier than a horde of zombies bearing down on your position is a clown — all it takes is one! So, even though we’re already dealing with frightening post-apocalyptic zombies, let’s add the possibility of a clown entering the scene for even more horror. In fact, we’ll do it in such a way that there’s a possibility any human or zombie on the screen is secretly a clown in disguise!

I take back what I said earlier: a single zombie clown is scarier than even a group of “normal” clowns. Let’s say that if any sort of clown is found — be it human or zombie — we separate them from the human and zombie populations by sending them to a whole different document — an <iframe> jail, if you will. (I hear that “clowning” may be even more contagious than zombie contagion.)

And when we move a suspected clown from the current document to an <iframe>, it doesn’t destroy and recreate the original node; rather it adopts and connects said node, first calling adoptedCallback then connectedCallback.

We don’t need anything in the <iframe> document except a body with a .clowns class. As long as this document is in the iframe of the main document — not viewed separately — we don’t even need the <postapocalyptic-person> instantiation code. We’ll include one space for humans, another space for zombies, and yes, the clowns’s jail… errr… <iframe> of… fun.

<div class="btns"> <button id="addbtn">Add Person</button> <button id="jailbtn">Jail Potential Clown</button> </div> <div class="humans"> <postapocalyptic-person></postapocalyptic-person> </div> <div class="zombies"> <postapocalyptic-person></postapocalyptic-person> </div> <iframe class="clowniframeoffun” src="adoptedCallback-iframe.html"> </iframe>

Our “Add Person” button works the same as it did in the last example: it flips a digital coin to randomly insert either a human or a zombie. When we hit the “Jail Potential Clown” button another coin is flipped and takes either a zombie or a human, handing them over to <iframe> jail.

document.getElementById("jailbtn").addEventListener("click", function () { if (Math.random() > 0.5) { let human = humancamp.querySelector('postapocalyptic-person'); if (human) { clowncollege.contentDocument.querySelector('body').appendChild(document.adoptNode(human)); } else { console.log("No more potential clowns at the human camp"); } } else { let zombie = zombienest.querySelector('postapocalyptic-person'); if (zombie) { clowncollege.contentDocument.querySelector('body').appendChild(document.adoptNode(zombie)); } else { console.log("No more potential clowns at the zombie nest"); } } }); Revealing clowns with adoptedCallback

In the adoptedCallback we’ll determine whether the clown is of the zombie human variety based on their corresponding image and then change the image accordingly. connectedCallback will be called after that, but we don’t have anything it needs to do, and what it does won’t interfere with our changes. So we can leave it as is.

adoptedCallback() { let image = this.shadowRoot.querySelector("img"); if (this.parentNode.dataset.type == "clowns") { if (image.src.indexOf("lady.png") != -1) { // Sometimes, the full URL path including the domain is saved in `image.src`. // Using `indexOf` allows us to skip the unnecessary bits. image.src = "ladyc.png"; this.shadowRoot.appendChild(image); } else if (image.src.indexOf("ladyz.png") != -1) { image.src = "ladyzc.png"; this.shadowRoot.appendChild(image); } } } Detecting hidden clowns with attributeChangedCallback

Finally, we have the attributeChangedCallback. Unlike the the other three lifecycle callbacks, we need to observe the attributes of our web component in order for the the callback to fire. We can do this by adding an observedAttributes() function to the custom element’s class and have that function return an array of attribute names.

static get observedAttributes() { return [“attribute-name”]; }

Then, if that attribute changes — including being added or removed — the attributeChangedCallback fires.

Now, the thing you have to worry about with clowns is that some of the humans you know and love (or the ones that you knew and loved before they turned into zombies) could secretly be clowns in disguise. I’ve set up a clown detector that looks at a group of humans and zombies and, when you click the “Reveal Clowns” button, the detector will (through completely scientific and totally trustworthy means that are not based on random numbers choosing an index) apply data-clown="true" to the component. And when this attribute is applied, attributeChangedCallback fires and updates the component’s image to uncover their clownish colors.

I should also note that the attributeChangedCallback takes three parameters:

  • the name of the attribute
  • the previous value of the attribute
  • the new value of the attribute

Further, the callback lets you make changes based on how much the attribute has changed, or based on the transition between two states.

Here’s our attributeChangedCallback code:

attributeChangedCallback(name, oldValue, newValue) { let image = this.shadowRoot.querySelector("img"); // Ensures that `data-clown` was the attribute that changed, // that its value is true, and that it had an image in its `shadowRoot` if (name="data-clown" && this.dataset.clown && image) { // Setting and updating the counts of humans, zombies, // and clowns on the page let clowncount = document.getElementById("clown-count"), humancount = document.getElementById("human-count"), zombiecount = document.getElementById("zombie-count"); if (image.src.indexOf("lady.png") != -1) { image.src = "https://assets.codepen.io/1804713/ladyc.png"; this.shadowRoot.appendChild(image); // Update counts clowncount.innerHTML = parseInt(clowncount.textContent) + 1; humancount.innerHTML = parseInt(humancount.textContent) - 1; } else if (image.src.indexOf("ladyz.png") != -1) { image.src = "https://assets.codepen.io/1804713/ladyzc.png"; this.shadowRoot.appendChild(image); // Update counts clowncount.innerHTML = parseInt(clowncount.textContent) + 1; zombiecount.innerHTML = parseInt(zombiecount.textContent) - 1; } } } CodePen Embed Fallback

And there you have it! Not only have we found out that web component callbacks and creating context-aware custom elements are easier than you may have thought, but detecting post-apocalyptic clowns, though terrifying, is also easier that you thought. What kind of devious, post-apocalyptic clowns can you detect with these web component callback functions?

Context-Aware Web Components Are Easier Than You Think originally published on CSS-Tricks. You should get the newsletter and become a supporter.

A Serene CSS Dappled Light Effect

Css Tricks - Wed, 01/19/2022 - 12:46pm

There’s a serene warmth to the early evening sunlight peaking through rustling leaves. Artists use dappled light to create a soft, hypnotic effect.

Bedford Dwellings by Ron Donoughe (2013)

We can create the same sort of dappled light effect in web design, using it on photos and illustrations to add that magic touch to what might otherwise be drab walls of content to bring them back to life.

I’ll give you one easy, quick way to add this effect… with just CSS.

Before we get into the code, it’s important to know the composition of dappled light. It’s made up of large spots — circular or elliptical — of light that are intercepted by the shadows cast by the foliage. Basically the light that slips past leaves, branches and so forth. Sometimes the shadows create crisp edges, but are more often blurred since we’re talking about light that passes though many, less defined spaces that diffuse and distort the light as it casts shadows from a further distance than, say, your own stark shadow on a nearby wall from direct sunlight.

Here’s the difference in the appearance of a white wall with and without lit by dappled light:

The effect creates splashes of light and shadow.

I’m going to recreate the dappled light effect with both plain text and fun emojis, applying CSS shadows and blends to mimic nature. I’ll cover alternative methods too.

Setting the scene

We’ll use text — letters from the alphabet, special characters, emojis, etc. — to create the shapes of light. And by light, I mean pale, translucent colors. Again, we’re for a dappled light effect rather than something that’s sharp, crisp, or stark.

It’s best to choose characters that are elliptical or oblong in some way — the spots produced by dappled light comes in a variety of shapes. You’ll have to go with your best judgement here to get exactly what you’re going for. Me? I’m using &#x1f343;, &#x1f342;, \ because they are elliptical, oblong, and slanted — a bit of chaos and unpredictability for an otherwise serene effect.

I’m wrapping those in paragraphs that are contained in a .backdrop parent element:

<div class="backdrop"> <p class="shapes">&#x1f343;</p> <p class="shapes">&#x1f342;</p> <p class="shapes">\</p> </div>

I’m using the parent element as the surface where the dappled light and shadows are cast, applying a background image for its texture. And not only am I giving the surface an explicit width and height, but also setting hidden overflow on it so I’m able to cast shadows that go beyond the surface without revealing them. The objects that cast the dappled light effect are aligned in the middle of the backdrop’s surface, thanks to CSS grid:

.backdrop { background: center / cover no-repeat url('image.jpeg'); width: 400px; height: 240px; overflow: hidden; display: grid; } .backdrop > * { grid-area: 1/1; }

I find that it’s OK if the shapes aren’t aligned exactly on top of one another as long as they overlap in a way that gets the dappled light effect you want. So no pressure to do exactly what I’m doing here to position things in CSS. In fact, I encourage you to try playing with the values to get different patterns of dappled light!

Styling the dappled light in CSS

These are the key properties the emojis should have — transparent color, black semi-transparent background (using the alpha channel in rgba()), blurry white text-shadow with a nice large font-size, and finally, a mix-blend-mode to smooth things out.

.shapes { color: transparent; background-color: rgba(0, 0, 0, 0.3); // Use alpha transparency text-shadow: 0 0 40px #fff; // Blurry white shadow font: bolder 320pt/320pt monospace; mix-blend-mode: multiply; } CodePen Embed Fallback

mix-blend-mode sets how an element’s colors blend with that of its container element’s content. The multiply value causes the backdrop of an element to show through the element’s light colors and keeps dark colors the same, making for a nicer and more natural dappled light effect.

Refining colors and contrast

I wanted the background-image on the backdrop to be a bit brighter, so I also added filter: brightness(1.6). Another way to do this is with background-blend-mode instead, where all the different backgrounds of an element are blended and, instead of adding the emojis as separate elements, we add them as background images.

CodePen Embed Fallback

Notice that I used a different emoji in that last example as well as floralwhite for some color that’s less intense than pure white for the light. Here’s one of the emoji background images unwrapped:

<svg xmlns='http://www.w3.org/2000/svg'> <foreignObject width='400px' height='240px'> <div xmlns='http://www.w3.org/1999/xhtml' style= 'font: bolder 720pt/220pt monospace; color: transparent; text-shadow: 0 0 40px floralwhite; background: rgba(0, 0, 0, 0.3);' > &#x1f33e; </div> </foreignObject> </svg>

If you want to use your own images for the shapes, ensure the borders are blurred to create a soft light. The CSS blur() filter can be handy for the same sort of thing. I also used CSS @supports to adjust the shadow blur value for certain browsers as a fallback.

Now let’s circle back to the first example and add a few things:

<div class="backdrop"> <p class="shapes">&#x1f343;</p> <p class="shapes">&#x1f342;</p> <p class="shapes">\</p> </div> <p class="content"> <img width="70px" style="float: left; margin-right: 10px;" src="image.jpeg" alt=""> Top ten tourists spots for the summer vacation <br><br><i style="font-weight: normal;">Here are the most popular places...</i> </p>

.backdrop and .shapes are basically the same styles as before. As for the .content, which also sits on top of the .backdrop, I added isolation: isolate to form a new stacking context, excluding the element from the blending as a refining touch.

Animating the light source

I also decided to add a simple CSS animation with @keyframes that get applied to the .backdrop on :hover:

.backdrop:hover > .shapes:nth-of-type(1){ animation: 2s ease-in-out infinite alternate move; } .backdrop:hover > .shapes:nth-of-type(2):hover{ animation: 4s ease-in-out infinite alternate move-1; } @keyframes move { from { text-indent: -20px; } to { text-indent: 20px; } } @keyframes move-1 { from { text-indent: -60px; } to { text-indent: 40px; } } CodePen Embed Fallback

Animating the text-indent property on the emojis products a super subtle bit of movement — the kind you might expect from clouds moving overhead that change the direction of the light. Just a touch of class, you know.

Wrapping up

There we have it! We drew some inspiration from nature and art to mimic one of those partly cloudy days where the sun shines through trees and bushes, projecting dappled light and shadow spots against a surface. And we did all of it with a small handful of CSS and a few emoji.

The key was how we applied color on the emoji. Using an extra blurry text-shadow in a light color sets the light, and a semi-transparent background-color defines the shadow spots. From there, all we had to do was ensure the backdrop for the light and shadows used a realistic texture with enough contrast to see the dappled light effect in action.

A Serene CSS Dappled Light Effect originally published on CSS-Tricks. You should get the newsletter and become a supporter.

What should someone learn about CSS if they last boned up during CSS3?

Css Tricks - Wed, 01/19/2022 - 4:25am

“CSS3” was a massive success for CSS. A whole bunch of stuff dropped essentially at once that was all very terrific to get our hands on in CSS. Gradients, animation/transition, border-radius, box-shadow, transformwoot! And better, the banner name CSS3 (and the spiritual umbrella “HTML5”) took off and the industry was just saturated in learning material about it all. Just look at all the “CSS3”-dubbed material that’s been published around here at CSS-Tricks over the years.

No doubt loads of people boned up on these technologies during that time. I also think there is no doubt there are lots of people that haven’t learned much CSS since then.

So what would we tell them?

Some other folks have speculated similarly. Scott Vandehey in “Modern CSS in a Nutshell” wrote about his friend who hasn’t kept up with CSS since about 2015 and doesn’t really know what to learn. I’ll attempt to paraphrase Scott’s list and what’s changed since the days of CSS3.

Preprocessors are still widely used since the day of CSS3, but the reasons to use them have dwindled, so maybe don’t even bother. This includes more newfangled approaches like polyfilling future features. This also includes Autoprefixer. CSS-in-JS is common, but only on projects where the entire workflow is already in JavaScript. You’ll know when you’re on a relevant project and can learn the syntax then if you need to. You should learn Custom Properties, Flexbox, and Grid for sure.

Sounds about right to me. But allow me to make my own list of post-CSS3 goodies that expands upon that list a smidge.

What’s new since CSS3?

And by “CSS3” let’s say 2015 or so.

.card { display: grid; grid-template-columns: 150px 1fr; gap: 1rem; } .card .nav { display: flex; gap: 0.5rem; } Layout

You really gotta learn Flexbox and Grid if you haven’t — they are really cornerstones of CSS development these days. Even more so than any feature we got in CSS3.

Grid is extra powerful when you factor in subgrid and masonry, neither of which is reliable cross-browser yet but probably will be before too long.

html { --bgColor: #70f1d9; --font-size-base: clamp(1.833rem, 2vw + 1rem, 3rem); --font-size-lrg: clamp(1.375rem, 2vw + 1rem, 2.25rem); } html.dark { --bgColor: #2d283e; } CSS Custom Properties

Custom properties are also a big deal for several reasons. They can be your home for design tokens on your project, making a project easier to maintain and keep consistent. Color theming is a big use case, like dark mode.

You can go so far as designing entire sites using mostly custom properties. And along those lines, you can’t ignore Tailwind these days. The approach of styling an entire site with classes in HTML strikes the right chord with a lot of people (and the wrong chord with a lot of people, so no worries if it doesn’t jive with you).

@media (prefers-reduced-motion: reduce) { * { animation-duration: 0.001s !important; } } @media (prefers-color-scheme: dark) { :root { --bg: #222; } } Preference Queries

Preference queries are generally @media queries like we’ve been using to respond to different browsers sizes for year, but now include ways to detect specific user preferences at the OS level. Two examples are prefers-reduced-motion and prefers-color-scheme. These allow us to build interfaces that more closely respect a user’s ideal experience. Read Una’s post.

.block { background: hsl(0 33% 53% / 0.5); background: rgb(255 0 0); background: /* can display colors no other format can */ color(display-p3 0.9176 0.2003 0.1386) background: lab(52.2345% 40.1645 59.9971 / .5);} background: hwb(194 0% 0% / .5); } Color Changes

The color syntax is moving to functions that accept alpha (transparency) without having the change the function name. For example, if you wanted pure blue in the CSS3 days, you might do rgb(0, 0, 255). Today, however, you can do it no-comma style (both work): rgb(0 0 255), and then add alpha without using a different function: rgb(0 0 255 / 0.5). Same exact situation for hsl(). Just a small nicety, and how future color functions will only work.

Speaking of future color syntaxes:

body { font-family: 'Recursive', sans-serif; font-weight: 950; font-variation-settings: 'MONO' 1, 'CASL' 1; } Variable Fonts

Web fonts became a big thing in CSS3. Now there are variable fonts. You might as well know they exist. They both unlock some cool design possibilities and can sometimes be good for performance (like no longer needing to load different font files for bold and italic versions of the same font, for example). There is a such thing as color fonts too, but I’d say they haven’t seen much popularity on the web, despite the support.

.cut-out { clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%); } .mask { mask: url(mask.png) right bottom / 100px repeat-y; } .move-me { offset-path: path('M 5 5 m -4, 0 a 4,4 0 1,0 8,0 a 4,4 0 1,0 -8,0'); animation: move 3s linear infinite; } @keyframes move { 100% { offset-distance: 100%; } } Paths

SVG has also exploded since CSS3. You can straight up crop any element into shapes via clip-path, bringing SVG-like qualities to CSS. Not only that, but you can animate elements along paths, float elements along paths, and even update the paths of SVG elements.

These all feel kind of spirtually connected to me:

  • clip-path — allows us to literally crop elements into shapes.
  • masks — similar to clipping, but a mask can have other qualities like being based on the alpha channel of the mask.
  • offset-path — provides a path that an element can be placed on, generally for the purpose of animating it along that path.
  • shape-outside — provides a path on a floated element that other elements wrap around.
  • d — an SVG’s d attribute on a <path> can be updated via CSS.
.disable { filter: blur(1px) grayscale(1); } .site-header { backdrop-filter: blur(10px); } .styled-quote { mix-blend-mode: exclusion; } CSS Filters

There is a lot of image manipulation (not to mention other DOM elements) that is possible these days directly in CSS. There is quite literally filter, but its got friends and they all have different uses.

These all feel kind of spirtually connected to me:

  • filter — all sorts of useful Photoshop-like effects like brightness, contrast, grayscale, sautration, etc. Blurring is a really unique power.
  • background-blend-mode — again, evocative of Photoshop in how you can blend layers. Multiply the layers to darken and combine. Overlay to mix the background and color. Lighten and darken are classic effects that have real utility in web design, and you never know when a more esoteric lighting effect will create a cool look.
  • backdrop-filter — the same abilities you have with filter, but they only apply to the background and not the entire element. Blurring just the background is a particularly useful effect.
  • mix-blend-mode — the same abilities you have with background-blend-mode, but for the entire element rather than bring limited to backgrounds.
import "https://unpkg.com/extra.css/confetti.js"; body { background: paint(extra-confetti); height: 100vh; margin: 0; } Houdini

Houdini is really a collection of technologies that are all essentially based around extending CSS with JavaScript, or at least at the intersection of CSS and JavaScript.

  • Paint API — returns an image that is built from <canvas> APIs and can be controlled through custom properties.
  • Properties & Values API / Typed OM — gives types to values (e.g. 10px) that would have otherwise been strings.
  • Layout API — create your own display properties.
  • Animation API

Combined, these make for some really awesome demos, though browser support is scattered. Part of the magic of Houdini is that it ships as Worklets that are pretty easy to import and use, so it has the potential to modularize powerful functionality while making it trivially easy to use.

my-component { --bg: lightgreen; } :host(.dark) { background: black; } my-component:part(foo) { border-bottom: 2px solid black; } Shadow DOM

The Shadow DOM comes up a bit if you’ve played with <svg> and the <use> element. The “cloned” element that comes through has a shadow DOM that has limitations on how you can select “through” it. Then, when you get into <web-components>, it’s the same ball of wax.

If you find yourself needing to style web components, know there are essentially four options from the “outside.” And you might be interested in knowing about native CSS modules and constructible stylesheets.

The CSS Working Group

It’s notable that the CSS working group has its own way of drawing lines in the sand year-to-year, noting where certain specs are at a given point in time:

These are pretty dense though. Sure, they’re great references and document things where we can see what’s changed since CSS3. But no way I’d send a casual front-end developer to these to choose what to learn.

Yeah — but what’s coming?

I’d say probably don’t worry about it. ;)

The point of this is catching up to useful things to know now since the CSS3 era. But if you’re curious about what the future of CSS holds in store…

  • Container queries will be a huge deal. You’ll be able to make styling choices based on the size of a container element rather than the browser size alone. And it’s polyfillable today.
  • Container units will be useful for sizing things based on the size of a container element.
  • Independant transforms, e.g. scale: 1.2;, will feel more logical to use than always having to use transform.
  • Nesting is a feature that all CSS preprocessor have had forever and that developers clearly like using, particularly for media queries. It’s likely we’ll get it in native CSS soon.
  • Scoping will be a way to tell a block of CSS to only apply to a certain area (the same way CSS-in-JS libraries do), and helps with the tricky concept of proximity.
  • Cascade layers open up an entirely new concept of what styles “win” on elements. Styles on higher layers will beat styles on lower layers, regardless of specificity.
  • Viewport units will greatly improve with the introduction of “relative” viewport lengths. The super useful ones will be dvh and dvw, as they factor in the actual usable space in a browser window, preventing terrible issues like the browser UI overlapping a site’s UI.

Bramus Van Damme has a pretty good article covering these things and more in his “CSS in 2022” roundup. It looks like 2022 should be a real banner year for CSS. Perhaps more of a banner year than the CSS3 of 2015.

What should someone learn about CSS if they last boned up during CSS3? originally published on CSS-Tricks. You should get the newsletter and become a supporter.

4 Quality Options for a Table of Contents Block in WordPress

Css Tricks - Tue, 01/18/2022 - 1:22pm

Offering a table of contents block in WordPress for blog posts (or really any other type of long-ish written content) is a good idea for two reasons:

  • It helps users jump around in the post for what they need (and hopefully doesn’t get in the way).
  • It’s provides SEO value.

The RankMath SEO plugin factors it in as part of your page score (suggesting you should have one), because of that second point. See what Google likely gives you if you do it right:

It makes sense that other WordPress SEO Plugins like Yoast offer a table of contents block as a baked-in additional feature of the plugin. If you’re committed to using Yoast, then I think it’s fine to just use that. But I admit it’s not my favorite to feel locked to a plugin because it offers a microfeature that you then depend on.

So what are the options?

Table of Contents What to look for in a WordPress Table of Contents Block

Here are some things to look for and think about when choosing a table of contents block:

  • Customizable header — Many options chuck a “Table of Contents” header above the actual Table of Contents, which makes sense. Can you turn it off or customize it? What level header is it? Having the ability to disable the heading might be necessary for layout, and having a choice of heading levels can help ensure proper HTML semantics.
  • Collapsible — In the spirit of making the Table of Contents less annoying, many offer a feature to toggle the Table of Contents block between open and closed states. Do you want that? Are you OK with the fact it likely requires some JavaScript to work? Is it doing toggling accessibly? Can it default to the state that you want?
  • Choose which headings to include — Perhaps you only want all the <h2> elements to form the Table of Contents. Can you do that? Do sub-headers create a “nested’ list? Do you want that? Can you turn off certain levels of headers? Can you tell the block to only include <h2> through <h4>? Are there things other than headers you want to be part of the Table of Contents?
  • Editable links — Many Table of Contents plugins in WordPress typically grab all the headings verbatim. Maybe you want to shorten, lengthen, or otherwise change a specific link in the Table of Contents; as in, not have it be the exact text of the header it links to. Can you do that?
  • Include additional links — Perhaps you want to link to something that isn’t a content heading. Perhaps it’s added to the template with a WordPress custom field, or it’s part of the overall template like the comments section. Can you add (or remove) those as headings in the block?
  • Block Editor support — That’s kind of the point of this blog post. I didn’t include many options that don’t have a block. But surely there are old school versions of this that are [shortcode]-based or that implement it some other way. I’m mostly concerned about blocks, although I could easily see a situation where your goal is to put the Table of Contents elsewhere in a template (sidebar, perhaps?). So, having multiple options and modularity could be useful.
  • Styling options — Personally, I like to bring my own styling (surprise!) and even dequeue any stylesheets (or scripts) that a plugin tries to bring along for the ride. But I can imagine more folks want the Table of Contents to look good and be able to aesthetically control it right from the editor. This means it’d be nice to have block options for colors, fonts, spacing, etc.
  • Semantic markup — Might be worth a peek at the HTML that the Table of Contents block you choose generates to make if it’s sensible. I’ve seen plugins generate HTML lists that don’t actually nest lists, for example, but instead add classes to list items to make them look nested. No, thanks. I’m not sure there is an official HTML format that’s best for SEO, so sematic markup is about the best you can do.
  • Heading IDs — In order for a linked Table of Contents to work, all the headers need to have IDs so there’s something to anchor to. I would think any plugin here that’s worth its salt would add them to headings only in the case that they don’t already have one, but you might wanna veryify that; otherwise, you run the risk of breaking existing links or perhaps even styling and functionality. Also think about what IDs are being generated. For example, I use the Add Anchor Links plugin, which adds a link (&#x1f517;) icon beside all headings to offer access to the IDs. The IDs it generates were idential to the Table of Contents-generated IDs, causing a duplicate ID problem. Fixable, but just be aware of things like that.
Option 1: Use a Dedicated Table of Contents Plugin

A dedicated Table of Contents plugin is a plugin that focuses on nothing but a Table of Contents. Nothing else. Here are some solid options where that’s the case.

Heroic Table of Contents

The ability to edit/add/remove headers from the table of contents — even after it’s been automatically generated — is pretty powerful and unique to this plugin. It allows you to open and close it (optionally) as well, which is nice as a goal for these, as they should make the links useful rather than content that gets in the way. But beware that this puts you in the territory of enqueuing additional scripts as well as styles which may or may not be ideal or something you’re comfortable doing.

(Recommended by Deborah Edwards-Onoro) Easy Table of Contents

This is not a Block Editor block! Instead, it only automatically inserts itself, either by content type or through an opt-in checkbox in a metabox.

I find it a little awkward that you can’t control where the Table of Contents goes with this plugin. Looks like it inserts itself near the top of posts, likely right after where the <!-- more --> is located.

SimpleTOC

This is my favorite one.

I like this one because it doesn’t add any scripts or styles by default. It just makes a semantic HTML list out of the headers, links them up, and that’s it. That’s how I like to roll.

LuckyWP Table of Contents

Lots of features, but I find it a bit awkward how it doesn’t have regular block controls. Instead, you get this entirely custom UI for changing the settings — and you can’t preview what it looks like in the block itself.

GutenTOC

Feels like this Table of Contents plugin embraces the spirit of the WordPress Block Editor quite well, but I find the settings a little awkward. The choices it offers don’t feel terrifically useful (like square bullets for the list? “15” space left?).

Option 2: Wait for a Table of Contents feature to be baked into Core WordPress

As I write, there is an open pull request to enable a Table of Contents block in the Gutenberg plugin. Presumably, should that go well, it ultimately makes its way to core. That would be great if you ask me, but it doesn’t help solve the problem of needing a Table of Contents block right this second.

If this feature does drop, I’d lean heavily toward using it. Hopefully, I can do a search or query to find existing Table of Contents blocks on all posts, switch them over to use the native block, and remove whatever plugin I have in place.

Option 3: Use a Table of Contents Block that’s a sub-feature of another WordPress plugin

I would recommend against using a plugin that does a whole slew of things just because you want to use some small part of it. But hey, if it turns out you could use lots of things from the big plugin, it could be a bonus as far as managing fewer plugins overall.

Yoast SEO Premium

The free version of the Yoast SEO plugin doesn’t have it, but for only $99 per year, the Yoast SEO Premium plugin does. It has almost no features at all. You just add it as a block, and it pops in. You can edit the title or remove it — it’s almost like a “sub block.”

The list of links isn’t editable, but it does update in real-time as you change headings in the content, which is something most of the others I tested didn’t do. Super basic, no styling or features, but I kinda like that. I wouldn’t run Yoast for this one feature, especially for a paid premium, but if you’re using Yoast anyway (for the long haul), then you might as well go this route.

Ultimate Addons for Gutenberg

This one is probably the classiest Table of Contents block I’ve come across. Again, I’m weary of using an all-in-one plugin for one specific feature, but the other features that are baked into this plugin are things you can use, then it’s a solid option.

Option 4: Roll your own DIY Table of Contents Block

Making blocks yourself isn’t out of the question! I’ve done it a few times with create-guten-block, though I’d probably reach for @wordpress/create-block these days. This puts you in JavaScript-land, so you’ll be parsing the content of the post with JavaScript, finding headings in the post content, and building things out from there. Kind of intermediate-to-advanced territory, I’d say. On one hand, it’s extra technical debt, and on the other, at least you have complete control since it’s your own code.

Since we’re focusing on building blocks, Advanced Custom Fields has a very powerful way of building custom blocks that brings that power back to PHP-land. That way, if you’re only concerned with building a Table of Contents from other heading blocks, the code gets a lot easier.

Bill Erickson has a post — “Access block data with PHP using parse_blocks() and render_block() — that ultimately gets into literally building a Table of Contents block. This gist he provides is a pretty useful reference for how to loop through blocks on a post and produce an HTML list.

Favorite?

If I was using Yoast SEO Premium on a site, I’d just use that one. If not, I’d go for SimpleTOC. That’s what we’ve done here on CSS-Tricks. Once the core feature drops (&#x1f91e;), I’d make a rainy day project of moving all posts that currently use the Table of Contents plugin over to using the core WordPress block (assuming it turns out nice).

4 Quality Options for a Table of Contents Block in WordPress originally published on CSS-Tricks. You should get the newsletter and become a supporter.

Making a Site Work Offline Using the VitePWA Plugin

Css Tricks - Tue, 01/18/2022 - 4:30am

The VitePWA plugin from Anthony Fu is a fantastic tool for your Vite-powered sites. It helps you add a service worker that handles:

  • offline support
  • caching assets and content
  • prompting the user when new content is available
  • …and other goodies!

We’ll walk through the concept of service workers together, then jump right into making one with the VitePWA plugin.

New to Vite? Check out my prior post for an introduction.

Table of Contents
  1. Service workers, introduced
  2. Versioning and manifests
  3. Our first service worker
  4. What about offline functionality?
  5. How service workers update
  6. A better way to update content
  7. Runtime caching
  8. Adding your own service worker content
  9. Wrapping up
Service workers, introduced

Before getting into the VitePWA plugin, let’s briefly talk about the Service Worker itself.

A service worker is a background process that runs on a separate thread in your web application. Service workers have the ability to intercept network requests and do… anything. The possibilities are surprisingly wide. For example, you could intercept requests for TypeScript files and compile them on the fly. Or you could intercept requests for video files and perform an advanced transcoding that the browser doesn’t currently support. More commonly though, a service worker is used to cache assets, both to improve a site’s performance and enable it to do something when it’s offline.

When someone first lands on your site, the service worker the VitePWA plugin creates installs, and caches all of your HTML, CSS, and JavaScript files by leveraging the Cache Storage API. The result is that, on subsequent visits to your site, the browser will load those resources from cache, rather than needing to make network requests. And even on the first visit to your site, since the service worker just pre-cached everything, the next place your user clicks will probably be pre-cached already, allowing the browser to completely bypass a network request.

Versioning and manifests

You might be wondering what happens with a service worker when your code is updated. If your service worker is caching, say, a foo.js file, and you modify that file, you want the service worker to pull down the updated version, the next time a user visits the site.

But in practice you don’t have a foo.js file. Usually, a build system will create something like foo-ABC123.js, where “ABC123” is a hash of the file. If you update foo.js, the next deployment of your site may send over foo-XYZ987.js. How does the service worker handle this?

It turns out the Service Worker API is an extremely low-level primitive. If you’re looking for a native turnkey solution between it and the cache API, you’ll be disappointed. Basically, the creation of your service worker needs to be automated, in part, and connected to the build system. You’d need to see all the assets your build created, hard-code those file names into the service worker, have code to pre-cache them, and more importantly, keep track of the files that are cached.

If code updates, the service worker file also changes, containing the new filenames, complete with hashes. When a user makes their next visit to the app, the new service worker will need to install, and compare the new file manifest with the manifest that’s currently in cache, ejecting files that are no longer needed, while caching the new content.

This is an absurd amount of work and incredibly difficult to get right. While it can be a fun project, in practice you’ll want to use an established product to generate your service worker — and the best product around is Workbox, which is from the folks at Google.

Even Workbox is a bit of a low-level primitive. It needs detailed information about the files you’re pre-caching, which are buried in your build tool. This is why we use the VitePWA plugin. It uses Workbox under the hood, and configures it with all the info it needs about the bundles that Vite creates. Unsurprisingly, there are also webpack and Rollup plugins if you happen to prefer working with those bundlers.

Our first service worker

I’ll assume you already have a Vite-based site. If not, feel free to create one from any of the available templates.

First, we install the VitePWA plugin:

npm i vite-plugin-pwa

We’ll import the plugin in our Vite config:

import { VitePWA } from "vite-plugin-pwa"

Then we put it to use in the config as well:

plugins: [ VitePWA()

We’ll add more options in a bit, but that’s all we need to create a surprisingly useful service worker. Now let’s register it somewhere in the entry of our application with this code:

import { registerSW } from "virtual:pwa-register"; if ("serviceWorker" in navigator) { // && !/localhost/.test(window.location)) { registerSW(); }

Don’t let the code that’s commented out throw you for a loop. It’s extremely important, in fact, as it prevents the service worker from running in development. We only want to install the service worker anywhere that’s not on the localhost where we’re developing, that is, unless we’re developing the service worker itself, in which case we can comment out that check (and revert before pushing code to the main branch).

Let’s go ahead and open a fresh browser, launch DevTools, navigate to the Network tab, and run the web app. Everything should load as you’d normally expect. The difference is that you should see a whole slew of network requests in DevTools.

That’s Workbox pre-caching the bundles. Things are working!

What about offline functionality?

So, our service worker is pre-caching all of our bundled assets. That means it will serve those assets from cache without even needing to hit the network. Does that mean our service worker could serve assets even when the user has no network access? Indeed, it does!

And, believe it or not, it’s already done. Give it a try by opening the Network tab in DevTools and telling Chrome to simulate offline mode, like this.

The “No throttling” option is the default selection. Click that and select the “Offline” option to simulate an offline connection.

Let’s refresh the page. You should see everything load. Of course, if you’re running any network requests, you’ll see them hang forever since you’re offline. Even here, though, there are things you can do. Modern browsers ship with their own internal, persistent database called IndexedDB. There’s nothing stopping you from writing your own code to sync some data to there, then write some custom service worker code to intercept network requests, determine if the user is offline, and then serve equivalent content from IndexedDB if it’s in there.

But a much simpler option is to detect if the user is offline, show a message about being offline, and then bypass the data requests. This is a topic unto itself, which I’ve written about in much greater detail.

Before showing you how to write, and integrate your own service worker content, let’s take a closer look at our existing service worker. In particular, let’s see how it manages updating/changing content. This is surprisingly tricky and easy to mess up, even with the VitePWA plugin.

Before moving on, make sure you tell Chrome DevTools to put you back online.

How service workers update

Take a closer look at what happens to our site when we change the content. We’ll go ahead and remove our existing service worker, which we can do in the Application tab of DevTools, under Storage.

Click the “Clear site data” button to get a clean slate. While I’m at it, I’m going to remove most of the routes of my own site so there’s fewer resources, then let Vite rebuild the app.

Look in the generated sw.js to see the generated Workbox service worker. There should be a pre-cache manifest inside of it. Mine looks like this:

If sw.js is minified, run it through Prettier to make it easier to read.

Now let’s run the site and see what’s in our cache:

Let’s focus on the settings.js file. Vite generated assets/settings.ccb080c2.js based on the hash of its contents. Workbox, being independent of Vite, generated its own hash of the same file. If that same file name were to be generated with different content, then a new service worker would be re-generated, with a different pre-cache manifest (same file, but different revision) and Workbox would know to cache the new version, and remove the old when it’s no longer needed.

Again, the filenames will always be different since we’re using a bundler that injects hash codes into our file names, but Workbox supports dev environments which don’t do that.

Since the time writing, the VitePWA plugin has been updated and no longer injects these revision hashes. If you’re attempting to follow along with the steps in this article, this specific step might be slightly different from your actual experience. See this GitHub issue for more context.

If we update our settings.js file, then Vite will create a new file in our build, with a new hash code, which Workbox will treat as a new file. Let’s see this in action. After changing the file and re-running the Vite build, our pre-cache manifest looks like this:

Now, when we refresh the page, the prior service worker is still running and loading the prior file. Then, the new service worker, with the new pre-cache manifest is downloaded and pre-cached.

The new pre-cached manifest is displayed in the list of cached assets. Notice that both versions of our settings file are there (and both versions of a few other assets were affected as well): the old version, since that’s what’s still being run, and the new version, since the new service worker has pre-cached it.

Note the corollary here: our old content is still being served to the user since the old service worker is still running. The user is unable to see the change we just made, even if they refresh because the service worker, by default, guarantees any and all tabs with this web app are running the same version. If you want the browser to show the updated version, close your tab (and any other tabs with the site), and re-open it.

The cache should now only contain the new assets.

Workbox did all the legwork of making this all come out right! We did very little to get this going.

A better way to update content

It’s unlikely that you can get away with serving stale content to your users until they happen to close all their browser tabs. Fortunately, the VitePWA plugin offers a better way. The registerSW function accepts an object with an onNeedRefresh method. This method is called whenever there’s a new service worker waiting to take over. registerSW also returns a function that you can call to reload the page, activating the new service worker in the process.

That’s a lot, so let’s see some code:

if ("serviceWorker" in navigator) { // && !/localhost/.test(window.location) && !/lvh.me/.test(window.location)) { const updateSW = registerSW({ onNeedRefresh() { Toastify({ text: `<h4 style='display: inline'>An update is available!</h4> <br><br> <a class='do-sw-update'>Click to update and reload</a>  `, escapeMarkup: false, gravity: "bottom", onClick() { updateSW(true); } }).showToast(); } }); }

I’m using the toastify-js library to show a toast UI component to let users know when a new version of the service worker is available and waiting. If the user clicks the toast, I call the function VitePWA gives me to reload the page, with the new service worker running.

Now when we have pending updates, a nice toast component pops up on the front end. Clicking it reloads the page with the new content in there.

One thing to remember here is that, after you deploy the code to show the toast, the toast component won’t show up the next time you load your site. That’s because the old service worker (the one before we added the toast component) is still running. That requires manually closing all tabs and re-opening the web app for the new service worker to take over. Then, the next time you update some code, the service worker should show the toast, prompting you to update.

Why doesn’t the service worker update when the page is refreshed? I mentioned earlier that refreshing the page does not update or activate the waiting service worker, so why does this work? Calling this method doesn’t only refresh the page, but it calls some low-level Service Worker APIs (in particular skipWaiting) as well, giving us the outcome we want.

Runtime caching

We’ve seen the bundle pre-caching we get for free with VitePWA for our build assets. What about caching any other content we might request at runtime? Workbox supports this via its runtimeCaching feature.

Here’s how. The VitePWA plugin can take an object, one property of which is workbox, which takes Workbox properties.

const getCache = ({ name, pattern }: any) => ({ urlPattern: pattern, handler: "CacheFirst" as const, options: { cacheName: name, expiration: { maxEntries: 500, maxAgeSeconds: 60 * 60 * 24 * 365 * 2 // 2 years }, cacheableResponse: { statuses: [200] } } }); // ... plugins: [ VitePWA({ workbox: { runtimeCaching: [ getCache({ pattern: /^https:\/\/s3.amazonaws.com\/my-library-cover-uploads/, name: "local-images1" }), getCache({ pattern: /^https:\/\/my-library-cover-uploads.s3.amazonaws.com/, name: "local-images2" }) ] } }) ], // ...

I know, that’s a lot of code. But all it’s really doing is telling Workbox to cache anything it sees matching those URL patterns. The docs provide much more info if you want to get deep into specifics.

Now, after that update takes effect, we can see those resources being served by our service worker.

And we can see the corresponding cache that was created.

Adding your own service worker content

Let’s say you want to get advanced with your service worker. You want to add some code to sync data with IndexedDB, add fetch handlers, and respond with IndexedDB data when the user is offline (again, my prior post walks through the ins and outs of IndexedDB). But how do you put your own code into the service worker that Vite creates for us?

There’s another Workbox option we can use for this: importScripts.

VitePWA({ workbox: { importScripts: ["sw-code.js"],

Here, the service worker will request sw-code.js at runtime. In that case, make sure there’s an sw-code.js file that can be served by your application. The easiest way to achieve that is to put it in the public folder (see the Vite docs for detailed instructions).

If this file starts to grow to a size such that you need to break things up with JavaScript imports, make sure you bundle it to prevent your service worker from trying to execute import statements (which it may or may not be able to do). You can create a separate Vite build instead.

Wrapping up

At the end of 2021, CSS-Tricks asked a bunch of front-end folks what one thing someone cans do to make their website better. Chris Ferdinandi suggested a service worker. Well, that’s exactly what we accomplished in this article and it was relatively simple, wasn’t it? That’s thanks to the VitePWA with hat tips to Workbox and the Cache API.

Service workers that leverage the Cache API are capable of greatly improving the perf of your web app. And while it might seem a little scary or confusing at first, it’s nice to know we have tools like the VitePWA plugin to simplify things a great deal. Install the plugin and let it do the heavy lifting. Sure, there are more advanced things that a service worker can do, and VitePWA can be used for more complex functionality, but an offline site is a fantastic starting point!

Making a Site Work Offline Using the VitePWA Plugin originally published on CSS-Tricks. You should get the newsletter and become a supporter.

What Were the Hottest Front-End Tools in 2021?

Css Tricks - Mon, 01/17/2022 - 5:13am

Another year has passed and once again I’ve had the privilege of going through the Web Tools Weekly newsletter archives from the past 12 months to hunt down the front-end tools that readers found to be the most interesting during 2021. So, to kick off 2022, I’ve compiled a list of the 60 most popular tools. I’m sure there are at least one or two listed here that you can start using in your front-end projects today.

Some of these front-end tools are super-practical, while others probably only made this list due to curiosity (which I base on the number of unique clicks). And since many of the tools that make my year-end lists are pretty new, I think this is a good indicator of the kinds of front-end tools that will be popular in the coming year.

Counting down from the top!

Table of contents 60. Open Props

Open Props provides a set of hand-crafted design tokens made up of CSS custom properties. I can see this sort of thing being much more common due to the use of this particular CSS feature. These allow you to drop in small collections of useful groups of custom properties, like animations.css, borders.css, fonts.css, zindex.css, etc, with more coming soon. Or you can just use the main Open Props file to grab everything at once.

This is definitely one front-end tool to keep an eye on and maybe even a good one to contribute to if you want to help build the library of tokens available.

59. NextUI

A modern React library that uses Stitches, a popular CSS-in-JS solution, and includes light and dark UI components out-of-the-box along with a default color palette that might be good for quickly building landing pages or other content that’s not initially tied to any branding.

It’s currently listed as being in Alpha stage of development, so this is another one worth keeping tabs on in the coming year.

58. Dopefolio

If you’re looking for an easy way to put together your own developer portfolio, Dopefolio is a quick solution that’s optimized for SEO and has strong Lighthouse scores out-of-the-box.

The live demo gives you an idea of what it looks like (responsive and all) and it includes a color picker component so you can live-test your own preferred primary color for the template.

57. Vizzu

This is a unique one that made this year’s list of front-end tools. Vizzu an open-source JavaScript library for creating animated data stories and visualizations. Maybe this is popular due the apparent need for creating and embedding medical data nowadays.

This library allows you to easily build static data charts, animated charts, and data stories. You can see some live examples of the animated charts or data stories, which include a data story showing which guest character had the most lines throughout the run of the TV series Friends.

56. 10015 Tools

I seem to find a handful of these types of front-end tools every year. 10015 Tools is a collection of front-end tools rather than one single tool. It includes text tools, image tools, CSS tools, coding tools (e.g. minifiers), color tools, social media tools, and a few others under a miscellaneous category.

This is definitely one of the more comprehensive all-in-one solutions I’ve seen, so I’m sure you’ll find a few useful front-end tools here you can come back to.

55. Snoweb

Icon sets are always popular and I come across at least a dozen new ones every year. This one includes optimized SVG icons, many of which have a built-in animated effect when you hover over the icon (like the open/close envelope icon).

Like many icon websites, you can search by keyword or filter by category, one of which is a “brand” category with icons for Twitter, Facebook, Vimeo, YouTube, Snapchat, etc.

54. Tails

Here’s the first Tailwind-based tool to make the list; something that’s been a trend the past few years as Tailwind continues to grow in popularity. This front-end tool a drag-and-drop page builder for projects using Tailwind CSS.

It includes two free “blocks” for each of the 15 categories, so there’s a decent amount of free stuff here and you can unlock the rest for a monthly fee.

53. MapLibre

This open-source mapping library launched in March and has grown in popularity throughout the year. It includes a JavaScript library as well as an SDK for displaying maps inside of iOS and Android apps.

The docs include a bunch of examples that use JavaScript, if you want to see what’s possible with the web-based front-end tools.

52. SVG Repo

SVG Repo makes the list based on sheer numbers alone. It’s a repository of more than 300,000 free, optimized, SVG-based graphics and icons most of which are licensed for commercial use.

Each icon you select tells you what type of license it falls under. You can search by keyword and “save” icons to your favorites for later use (no login required).

51. Animated Backgrounds

This one made the top 60 this year but probably isn’t the most practical front-end tool of the bunch. Like I said at the outset, some stuff gets clicked on just out of sheer curiosity. It’s a gallery of animated backgrounds, sourced from various CodePen demos.

The gallery is useful in that it displays the backgrounds as pre-recorded videos so you don’t have to worry about all the demos loading and crashing your browser tab. Use these sparingly, if ever, as they often use heavy amounts of JavaScript and CSS.

50. Pico.css

This is a different type of CSS framework compared to what’s popular nowadays. It’s kind of like an anti-Tailwind tool and more of a starter CSS file (like a reset) than a full-fledged framework.

Pico.css provides elegant default styles on all native HTML elements (which you can preview here) without the need to add swaths of classes to your markup — and the whole thing is less than 10kb minified and gzipped.

49. Coding Fonts

Coding fonts seem to be an exciting new trend of late, and CSS-Tricks has taken advantage of that with this little interactive info app.

Select a font on the left to display example code, typeface info (ligatures, italics, etc.), cost (most are free), along with options to display example code for HTML, CSS, or JavaScript.

48. UI-Neumorphism

This React library is based on the old skeumorphism trend that apparently went out of style a number of years ago. Is this trend making a comeback? Probably not. In fact, this React library is about two years old even though I shared it for the first time this past year.

The library includes a slew of different components that all implement “neumorphism” look. Interesting to look at, but might not fit many projects.

47. Beautiful CSS Buttons

Just about every app or website needs buttons, so a collection like this always seems to do well. Many of these are different from what you probably have seen elsewhere.

A lot of the buttons include interesting hover effects and you can easily copy and paste the HTML and CSS for any single button directly on the page.

46. Shaper

This interactive tool lets you fiddle with various UI settings live on the page to build different page elements. Once you’ve tweaked things as you like, you can grab the code, which uses CSS custom properties.

You can switch between demo view and “specs” view (i.e. the code along with other useful info). This tool has a particular focus on typography along with the rest of the UI styles, which is an important part of getting a layout looking right.

45. Prestige

This is a text-based HTTP client in the browser — like Postman but without an interface. It allows you to define requests in plain text, which you can optionally save as a Gist. It includes isolated cookie management, and has both dark and light modes.

As the author explains, “I built Prestige because I needed an app like this when working […] and playing with external APIs.”

44. HTML.cafe

This is probably the simplest tool in the entire list. HTML.cafe is more or less a poor-man’s CodePen, for lack of a better term. I wouldn’t think people would be interested in this sort of thing, since there are already powerful tools that already do what it does. Nonetheless, it’s a really simple HTML editor with live preview.

There are no separate CSS or JavaScript windows like there are CodePen, but you can easily include those in <style> or <script> elements if you wish. I think the best use of this tool might be for teachers helping students who are completely unfamiliar with HTML, as this gets all the complexities out of the way.

43. Charts.css

This front-end tool is sort of like a cross between Tailwind CSS and Chart.js. In short, Charts.css is a CSS framework that lets you use utility classes to build charts using HTML and CSS.

You can create bar charts, line charts, multi-dataset charts, percentage columns, and 3D bar charts. And best of all, the charts are accessible, responsive, and easy to customize to your branding needs.

42. Buttons Generator

“Buttons Generator” is probably a bit of a misnomer, since the page doesn’t exactly let you “generate” buttons. Like the previous buttons resource, this is a gallery of buttons built with HTML and CSS.

They’re divided up by category, include some neat hover or click effects, and you can click any button to copy the code to your clipboard.

41. Doodad Pattern Generator

This interactive tool allows you to build your own patterned backgrounds that you can export in a variety of formats. You can use the “shuffle” button to generate a random pattern, or select from various category styles. You can also edit colors, filters, and various transforms.

The export dialog lets you save patterns and load previously-saved ones via Local Storage. Export your patterns as JPEG, PNG, inline SVG, SVG file, or CSS background.

40. Kaboom

Every year I come across at least one or two new JavaScript game libraries, and this is the one that made this year’s list. It looks to have a fairly elegant and easy-to-use API and includes a healthy set of components, events, and other built-in functions.

There’s a handy playground to get your feet wet with using it and an introductory tutorial to get started.

39. Skuawk

If you want an alternative to Unsplash, which is likely one of your go-to sources for free stock images, this collection of beautiful public domain images might be a good option with some gorgeous photos.

There are 16 categories of images from various photographers that have all allowed their images to be used under a CC0 license (i.e. do whatever you want).

38. Glassmorphism CSS Generator

This is an online generator that lets you build a “glassmorphism” effect on a page element — kind of like frosted glass. This tool is apparently supposed to be part of a larger UI library that will incorporate this sort of effect on a number of different UI components.

Whatever the case, I like this effect more than the “neumorphism” one and apparently my audience agrees.

37. Kalia

This is one of three VS Code tools that made the list. It’s an attractive color scheme you can use for your VS Code setup.

The extension lists only about 800 installs so far, which is surprising, but it has a nice pastel color look that I think many will enjoy.

36. AdminJS

If you’re a Node developer, this is an open-source admin panel that can be added to a Node.js app. It will generate a UI for you, based on data you’ve added from almost any database, allowing you and your team to manage your app’s content.

You can try it out using this example app, which is based on MongoDB and Postgres.

35. Pancake

Here’s another game engine to build cross-platform HTML5-based 2D games. This one got a lot of traction when I first shared it. While it made the list,it seems to require Python during the build step after you write the game.

The basic API uses plain JavaScript and you can view lots of neat little examples here.

34. Mosaic Lite

I find lots of dashboard templates built with different front-end technologies. This one is made with Tailwind and React and includes optional chart components built with Chart.js.

Like other similar templates, this can be used for SaaS products, admin dashboards, and more. You can view a live demo.

33. Iconduck

Here’s another great source for open-source icons, this one offering well over 100,000 icons that are searchable by keyword and are all available for use in commercial projects.

The site includes ability to like and save icons and icon collections for later use (requires cookies, but no login).

32. Luxa CSS

This is a CSS library that was actually released in mid-to late 2020, but I shared it for the first time in 2021. It’s described as a “minimalist” CSS framework.

Luxa CSS includes some base styles, along with various components, helpers, and layout styles, which you can view in the docs or by checking out this CodePen collection.

31. Glitter

Glitter was definitely one of the strangest — yet coolest — front-end tools I came across over the past year and it seems to have drawn a lot of interest even though it’s as simple as any tool gets.

It’s a generator that produces text in a glitter-like style, which you can save as SVG. Definitely not for 99% of your projects, but a pretty cool text effect.

30. Components AI

When I originally shared this one, I was sharing the theme builder alone, which is what got it on this list. But it’s worth sharing the entire set of 15+ tools.

In addition to the theme builder, there’s a syntax highlighter builder, gradient and shadow tools, SVG pattern generators, animated backgrounds, and lots more.

29. Unicode Arrows

This is pretty straightforward. Unicode Arrows a one-stop location to copy and paste — you guessed it — Unicode arrows along with each arrow’s associated hex code.

Not much else to say about this one except that the site lets you buy Unicode arrow jewellery. Not that a bunch of coding nerds would be interested in that, no way.

28. Type Scale Clamp Generator

This is not the first tool to attempt to generate a type scale for you, but it’s a relatively new one that incorporates CSS’s clamp() function.

The front-end tool allows you to select a range, font, preview text, and you can even test the responsiveness (though I don’t see how useful that latter feature is, considering this is just text).

27. AnimXYZ

This one is described as “the first composable CSS animation toolkit” with support for Vue and React. What that means exactly is that you don’t have to write any keyframes. It seems to be kind of like Tailwind for animations, since you’re only using HTML classes.

In addition to adding classes, the values are built entirely using CSS variables. That means you can customize the values as you wish by modifying the variables themselves.

26. Frontend Toolkit

Here’s another all-in-one tools solution that includes more than 20 tools for doing various coding and image-related tasks.

It includes tools for CSS, JSON, favicons, SVG, image compression, npm, regex, and more.

25. colorpalettes.earth

Here’s one that’s unique in the list and may inspire some cool designs. This tool displays color palettes sourced from images of nature (taken from Unsplash) that are included on the site, with new palettes added regularly.

Click any image and you’ll get a modal with access to the hex value for each of the colors that make up the image-derived palette.

24. Uncut

Adding to the diversity of this list, here’s a typeface catalogue that currently features 90 typefaces with a focus on contemporary, or modern, type.

All fonts included are open-source, so you’re free to use them in personal and commercial projects.

23. Lowdefy

Building internal tools seems to be a hot thing nowadays and this is one solution you might want to look into that lets you build your tools by writing YAML.

It’s described as an “open-source low-code framework to build web apps, admin panels, BI dashboards, workflows, and CRUD apps with ease.”

22. JavaScript Booster

This is a VS Code extension that aims to help you, as the it says on the tin, boost your JavaScript, TypeScript, and React coding productivity. The extension adds a light bulb icon at certain points in your code, indicating that you can instantly trigger predefined code refactorings.

Some examples include converting a regular function to an arrow function, flip an if-else construct, along with some React-specific refactorings.

21. Layout Patterns

This is one of the most recent additions to Google Developers’ web.dev resource that I’m assuming will continue to grow in the coming year.

It includes a number of UI patterns “built using modern CSS APIs.” In other words, it’s a very forward-thinking collection of CSS examples, but should be used with caution since some of the technologies incorporated may not have full browser support yet.

20. Baseline Background Remover

Admittedly, AI-based background remover tools have been a dime-a-dozen recently. This one is free and works really well from my brief testing with it.

You can upload an image of up to 5MB and it will accept JPEG and PNG files. The resulting image is downloaded a transparent PNG, which you can use to add your own background or leave as transparent.

19. Theatre.js

Here’s another animation library, but this time a JavaScript solution that allows you to animate DOM elements or WebGL using a convenient visual editor that works along with the code you write.

This is a really powerful tool that’s hard to encapsulate in just a few paragraphs. There’s a lenghty chapter-based video used throughout the docs that really helps if you want to get familiar with it.

18. Transition.css

Drop-in CSS libraries are always popular and I’ll usually find at least one or two good ones each year. This one includes some neat CSS transitions you probably haven’t seen elsewhere.

You can try them out right on the page. My favourites are the ones that incorporate some hesitation in the animation, for an added uniqueness.

17. The Component Gallery

This is sort of a catch-all for design systems as it features component examples sourced from real design systems built in various technologies — React, CSS, Angular, Vue, etc. — by various brands, including eBay, Goldman Sachs, GOV.UK, and lots more.

It works as a handy reference for anyone building their own design system, as you can compare the same components across the existing systems included here.

16. party.js

This is a fun and unique JavaScript library that lets you add particle effects to a web page, specifically confetti and sparkles.

You’ll only use this in very specific circumstances, but it’s nice that you can customize the particle shapes, number of particles, spread, and so on.

15. Headless UI

In the words of Nacho Libre, now we’re really getting down to the nitty gritty. This UI component library was released in late 2020 and has already amassed more than 12,000 stars on GitHub.

The components (dropdown menu, tabs, popover, etc.) are “headless.” That doesn’t mean their capa was detated; it means they’re unstyled so that you can brand them as you please. They’re also fully accessible, designed to integrate with Tailwind CSS, and are compatible with React and Vue. That’s right — this one hits almost every front-end buzzword for 2022.

14. Turbo

This is another one that did well throughout 2021 after a late 2020 release. It’s billed as “the speed of a single-page web application without having to write any JavaScript.”

In brief, Turbo is a library that lets you take advantage of four main features: Turbo Drive, Turbo Frames, Turbo Streams, and Turbo Native. These use web components to add single-page app-like performance and interactivity to your pages without the need to reinvent the wheel with heavy custom scripts.

13. tidy.js

This is a library of data-related JavaScript functions specifically for “tidying up” your data.

It includes 70+ functions under different categories (tidying, grouping, math, sequencing, etc.) and you can mess around with the different features using this playground.

12. Tail-Kit

This is the first Tailwind UI kit on the list of top front-end tools, and it’s a doozy. It has more than 250 open-source components that are compatible with React, Vue, and Angular.

There are components categorized under Elements, Forms, Commerce, Navigation, Sections, and Lists, or you can use from a number of templates, categorized under Dashboards, Landing Pages, and Error Pages.

11. Tailwind Components

And here’s another Tailwind UI kit, again featuring open-source components and templates under 13 more refined categories, along with an “awesome” category that includes free but premium components.

This site is more or less a directory of various community-contributed Tailwind components, rather than a cohesive set of UI elements like other kits.

10. Pikaday

A JavaScript date picker cracks the top 10 tools of the year in 2021 — who would have thunk it? It seems to check all the boxes necessary for a date picker component: No dependencies, lightweight, and uses modular CSS for styling.

Like a few other front-end tools on this list, this isn’t a new tool. It’s been around for a while, but I first shared it in 2021 and it amazingly ended up in this year’s top 10.

9. HTML Boilerplates

This is a practical little online HTML generator that lets you customize the type of HTML starter template you want to generate, providing toggle options for what to include. This is probably most useful for generating a quick template for a landing page or demo.

In all honesty, I think it would be good if the tool was updated to use a few more modern options, but for a simple HTML starting point this gets the job done.

8. Whirl

Here’s another CSS animation library, this time specifically a collection of animations for use as loading spinners. It includes 100+ animated loaders, some of which are really neat and unique.

I like how the animations in the list (which you can try right on the page) are categorized as pseudo-element, single element, and multi-element. The best one by far is the “pong” animation, though I question whether anyone would correctly classify that as indicative of “content loading”!

7. Riju

Imagine if CodePen and JSFiddle had a baby, then you chopped that baby into 224 pieces. That’s what Riju is — a fast online playground for just about every programming language.

I can’t imagine there’s any coding language you’d want to play around with that’s missing here and most of it is stuff that you don’t normally associate with running in the browser.

6. DevUI

This is an Angular toolkit that’s suitable for enterprise-level apps and includes components, icons, an admin dashboard template, and a design system for styling and branding.

I’m guessing this made the top 10 list of front-end tools because I didn’t specifically mention at first that it is for Angular apps (which isn’t clear on the home page either). Nonetheless, I did specify that it’s for enterprise-level projects, and that seemed to grab the attention of many.

5. Pollen

This library works as a foundation for your own design system, and its practicality is evident in its use of CSS custom properties.

It provides you with low-level design tokens that you can easily customize and extend. Modules include Typography, Layout, UI, Grid, and Colors. I’m guessing there will be more added to this, so it’s one to keep an eye on in the coming year.

4. AlterNight

Developers love VS Code, dark mode, and plugins. Combine those three things, and you have a great little front-end tool.

AlterNight is a beautiful VS Code theme and has a modest ~3,000 installs so far, but it was able to crack the top five in this year’s list.

3. UIsual

Here’s a collection of front-end templates, but with a bit of a twist that I think many seemed to appreciate: they’re greyscale.

The set currently includes eight templates with diverse layouts. With the lack of any color-based branding, these are a good option to customize to your own needs without looking like every other landing page out there.

2. Supabase UI

Here’s yet another open-source component library, this one for React and designed specifically for the Supabase product (an open-source Firebase alternative).

It’s Tailwind-ready and I should also point out that it’s still in early development. Nonetheless, it was popular enough to make it to number 2 on this list.

1. CSS Layout Generator

This was the most-clicked tool in my newsletter over the past year. It’s a full-featured CSS and JSX generator for producing different kinds of layouts using the CSS Grid Layout syntax.

Click on any of the five layout styles, and you’ll come to an interactive online editor that lets you mess around with various CSS Grid features like rows, columns, row gap, column gap, direction, grid alignment, and lots more. There’s quite a bit to play around with here, and apparently the tool will later include the Flexbox syntax for some of the examples.

What were your favorite front-end tools of 2021?

That wraps up this year’s list of most interesting front-end tools. I hope you found something here you can bookmark or start using in a new project. It’s pretty cool that this list contained such a variety of tools — there were UI kits, animation libraries, a stock photo site, image tools, and more.

Are there front-end tools not mentioned in this list that you enjoyed discovering over the past year? Feel free to drop it in the comments. You can also subscribe to my newsletter for more front-end tools in 2022 and feel free to hit me up if you’ve built something yourself that you’d like to share in a future issue.

What Were the Hottest Front-End Tools in 2021? originally published on CSS-Tricks. You should get the newsletter and become a supporter.

Using the CSS Me Not Bookmarklet to See (and Disable) CSS Files

Css Tricks - Fri, 01/14/2022 - 2:06pm

Stoyan is absolutely correct. As much as we all love CSS, it’s still an important player in how websites load and using less of it is a good thing. He has a neat new bookmarklet called CSS Me Not to help diagnose unnecessary CSS files, but we’ll get to that in a moment.

The [problem] is that CSS is in the critical path, it blocks rendering and often even JavaScript execution. We love CSS, it’s magic, it can do unbelievable feats and fix broken UIs and manipulate images and draw amazing pictures. We love CSS. We just want… less of it, because of its inherently blocking nature.

Sometimes our sites use entire stylesheets that are simply unnecessary. I hate to admit it, but WordPress is a notorious offender here, loading stylesheets for plugins and blocks that you might not even really be using. I’m in that position on this site as I write. I just haven’t found the time to root out a couple of little stylesheets I don’t need from loading.

Stoyan created a quick bookmarklet called CSS Me Not to see all those CSS files. The big benefit, of course, is that it lets you know what you’re up against.

You could find these stylesheets in DevTools as well, but the CSS Me Not bookmarklet makes it extra easy and has a killer bonus feature: turning off those stylesheets. Testing the bookmarklet here on CSS-Tricks, I can see four stylesheets that WordPress loads (because of settings and plugins) that I know I don’t need.

If you wanted to do this in DevTools instead, you could filter your Network requests by CSS, find the stylesheet that you want to turn off, right-click and block it, and re-load.

I’ve been fighting this fight for ages, dequeuing scripts and styles in WordPress that I don’t want.

Removing totally unused stylesheets is an obvious win, but there is the more squirrely issue of removing unused CSS. I mention in that post the one-true-way of really knowing if any particular CSS is unused, which is attaching a background-image to every selector and then checking the server logs after a decent amount of production time to see which of those images were never requested. Stoyan corroborates my story here:

UnCSS is sort of a “lab”. The “real world” may surprise you. So a trick we did at SomeCompany Inc. was to instrument all the CSS declarations at build time, where each selector gets a 1×1 transparent background image. Then rummage through the server logs after a week or so to see what is actually used.

Using the CSS Me Not Bookmarklet to See (and Disable) CSS Files originally published on CSS-Tricks. You should get the newsletter and become a supporter.

Mondrian Art in CSS From 5 Code Artists

Css Tricks - Fri, 01/14/2022 - 8:15am

Mondrian is famous for paintings with big thick black lines forming a grid, where each cell is white, red, yellow, or blue. This aesthetic pairs well with the notoriously rectangular web, and that hasn’t gone unnoticed over the years with CSS developers. I saw some Mondrian Art in CSS going around the other day and figured I’d go looking for others I’ve seen over the years and round them up.

Vasilis van Gemert:
What if Mondrian used CSS instead of paint?

Many people have tried to recreate a work of art by Mondriaan with CSS. It seems like a nice and simple exercise: rectangles are easy with CSS, and now with grid, it is easy to recreate most of his works. I tried it as well, and it turned out to be a bit more complicated than I thought. And the results are, well, surprising.

Jen Simmons Lab:
Mondrian Art in CSS Grid

I love how Jen went the extra mile with the texture. Like most of these examples, CSS grid is used heavily.

CodePen Embed Fallback Jen Schiffer:
var t;: Piet Mondrian

I started with Mondrian not because he is my favorite artist (he is not), or that his work is very recognizeable (it is), but because I thought it would be a fun (yes) and easy start (lol nope) to this project.

CodePen Embed Fallback Riley Wong:
Make Your Own Mondrian-Style Painting with Code

There is a 12-step tutorial on GitHub.

CodePen Embed Fallback
Adam Fuhrer:
CSS Mondrian

Generative Piet Mondrian style art using CSS grid.

John Broers:
CSS Mondriaan Grid

Mondrian Art in CSS From 5 Code Artists originally published on CSS-Tricks. You should get the newsletter and become a supporter.

How to Build Your First Custom Svelte Transition

Css Tricks - Fri, 01/14/2022 - 5:24am

The Svelte transition API provides a first-class way to animate your components when they enter or leave the document, including custom Svelte transitions. By default, the transition directive uses CSS animations, which generally offer better performance and allow the browser’s main thread to remain unblocked. The API is as simple as this: <element transition:transitionFunction />. You can also specify in or out directives which are uni-directional transitions, only running when the element is mounted or unmounted.

Example of a working Svelte transition (jump to demo)

Svelte offers a runtime svelte/transition package that ships with seven prepackaged Svelte transition functions, all of which can be dropped in and tweaked to your heart’s desire. Pairing this with the svelte/easing package, allows for a wide swath of interactions, without writing any of the transition code yourself. Play around with different transitions and easing functions to get a feel for what is possible.

Looking for instructions on how to get started with Svelte? We have a solid overview for you to check out.

The Svelte Custom Transition API

If you need even more control than what the Svelte Transition API offers out of the box, Svelte permits you to specify your own custom transition function, as long as you adhere to a few conventions. From the docs, here’s what the custom transition API looks like:

transition = (node: HTMLElement, params: any) => { delay?: number, duration?: number, easing?: (t: number) => number, css?: (t: number, u: number) => string, tick?: (t: number, u: number) => void }

Let’s break it down. A transition function takes a reference to the DOM node where the transition directive is used and returns an object with some parameters that control the animation and, most importantly, a css or tick function.

The css function’s job is to return a string of CSS that describes the animation, typically including some kind of transform or opacity change. Alternatively, you can opt to return a tick function, which lets you control every aspect of the animation with the power JavaScript, but pays a performance penalty since this type of transition does not use CSS animations.

Both the css and tick functions take two parameters called (t, u) by convention. t is a decimal number that travels from 0.00 to 1.00 while the element is entering the DOM and from 1.00 back to 0.00 when the element is leaving. The u parameter is the inverse of t or 1 - t at any given moment. For example, if you return a string of transform: scale(${t}), your element would smoothly animate from 0 to 1 on enter, and vice versa on exit.

These concepts may seem a bit abstract, so let’s solidify them by building our own custom Svelte transition!

Building your first custom Svelte transition

First, let’s set up some boilerplate that allows us to toggle an element’s existence in the DOM using a Svelte #if block. Remember, Svelte transitions only run when an element is actually leaving or entering the DOM.

<script> let showing = true </script> <label for="showing"> Showing </label> <input id="showing" type="checkbox" bind:checked={showing} /> {#if showing} <h1>Hello custom transition!</h1> {/if}

You should be able to toggle the checkbox and see our element starkly appear and disappear in place.

Next, let’s set up our custom Svelte transition function and get it wired up to our element.

<script> let showing = true // Custom transition function function whoosh(node) { console.log(node) } </script> <label for="showing"> Showing </label> <input id="showing" type="checkbox" bind:checked={showing} /> {#if showing} <h1 transition:whoosh>Hello custom transition!</h1> {/if}

Now, if you toggle the checkbox, you will see the <h1> element logged to the console. This proves we have the custom transition connected properly! We won’t actually use the DOM node in our example, but it’s often useful to have access to the element to reference its current styles or dimensions.

For our element to do any animation at all, we need to return an object that contains a css (or tick) function. Let’s have our css function return a single line of CSS that scales our element. We’ll also return a duration property that controls how long the animation takes.

<script> function swoop() { return { duration: 1000, css: () => `transform: scale(.5)` } } let showing = true </script> <!-- markup -->

We’ve got something moving! You will notice our element jumps straight to .5 scale when toggling the checkbox. This is something, but it would feel much better if it smoothly transitioned. That’s where the (t, u) parameters come in.

<script> function swoop() { return { duration: 1000, css: (t) => `transform: scale(${t})` } } let showing = true </script> <!-- markup -->

Now we are talking! Remember, t rolls smoothly from 0.00 to 1.00 when an element enters, and vice versa when it leaves. This allows us to achieve the smooth effect we want. In fact, what we just wrote is essentially the built-in scale transition from the svelte/transition package.

Let’s get a little bit fancier. To live up to our custom Svelte transition’s namesake, swoop, let’s add a translateX to our transform, so that our element zooms in and out from the side.

I want to challenge you to attempt the implementation first before we continue. Trust me, it will be fun! Assume that we want to translate to 100% when the element is leaving and back to 0% when it enters.

[waiting…]

How did it go? Want to compare answers?

Here’s what I got:

css: (t, u) => `transform: scale(${t}) translateX(${u * 100}%);`

It’s okay if you have something different! Let me break down what I did.

The key thing here is the usage of the second parameter in the css function. If we think about our animation while the element is entering the screen, we want to end up at scale(1) translateX(0%), so we can’t use unaltered t for both the scale and the transform. This is the convenience behind the u parameter — it is the inverse of t at any given moment, so we know it will be 0 when t is 1! I then multiplied u by 100 to get the percentage value and tacked on the % sign at the end.

Learning the interplay between t and u is an important piece of the custom transition puzzle in Svelte. These two parameters enable a world of dynamism for your animations; they can be divided, multiplied, twisted, or contorted into whatever needs you have.

Let’s slap my favorite svelte/easing function on our transition and call it a day:

<script> import { elasticOut } from 'svelte/easing' function swoop() { return { duration: 1000, easing: elasticOut, css: (t, u) => `transform: scale(${t}) translateX(${u * 100}%)` } } let showing = true </script> <label for="showing"> Showing </label> <input id="showing" type="checkbox" bind:checked={showing} /> {#if showing} <h1 transition:swoop>Hello custom transition!</h1> {/if} Wrapping up

Congratulations! You can now build a custom Svelte transition function. We have only scratched the surface of what is possible but I hope you feel equipped with the tools to explore even further. I would highly recommend reading the docs and going through the official tutorial to gain even more familiarity.

How to Build Your First Custom Svelte Transition originally published on CSS-Tricks. You should get the newsletter and become a supporter.

8 Helpful Accessibility Links for January 2022

Css Tricks - Thu, 01/13/2022 - 10:57am

Every now and then, I find that I’ve accumulated a bunch of links about various things I find interesting. Accessibility is one of those things! Here’s a list of related links to other articles that I’ve been saving up and think are worth sharing.

8 Helpful Accessibility Links for January 2022 originally published on CSS-Tricks. You should get the newsletter and become a supporter.

A Practical Tip For Using Sass Default Parameters

Css Tricks - Thu, 01/13/2022 - 5:17am

Sass offers functions and mixins that accept parameters. You can use Sass default parameters, that is, parameters that have a value even if you don’t provide them when the function or mixin is called.

Let’s focus on mixins here. Here’s the syntax of a mixin:

@mixin foo($a, $b, $c) { // I can use $a, $b, and $c in here, but there is a risk they are null } .el { @include foo(1, 2, 3); // if I tried to do `@include foo;` // ... which is valid syntax... // I'd get `Error: Missing argument $a.` from Sass }

It’s safer and more useful to set up default parameters in this Sass mixin:

@mixin foo($a: 1, $b: 2, $c: 3) { } .el { // Now this is fine @include foo; // AND I can send in params as well @include foo("three", "little", "pigs"); }

But what if I wanted to send in $b and $c, but leave $a as the Sass default parameter? The trick is that you send in named parameters:

@mixin foo($a: 1, $b: 2, $c: 3) { } .el { // Only sending in the second two params, $a will be the default. @include foo($b: 2, $c: 3); } A real-life example using Sass default parameters

Here’s a quick-y mixin that outputs what you need for very basic styled scrollbars (Kitty has one as well):

@mixin scrollbars( $size: 10px, $foreground-color: #eee, $background-color: #333 ) { // For Google Chrome &::-webkit-scrollbar { width: $size; height: $size; } &::-webkit-scrollbar-thumb { background: $foreground-color; } &::-webkit-scrollbar-track { background: $background-color; } // Standard version (Firefox only for now) scrollbar-color: $foreground-color $background-color; }

Now I can call it like this:

.scrollable { @include scrollbars; } .thick-but-otherwise-default-scrollable { // I can skip $b and $c because they are second and third @include scrollbars(30px); } .custom-colors-scrollable { // I can skip the first param if all the others are named. @include scrollbars($foreground-color: orange, $background-color: black); } .totally-custom-scrollable { @include scrollbars(20px, red, black); }

I’m just noting this as I had to search around a bit to figure this out. I was trying stuff like sending empty strings or null as the first parameter in order to “skip” it, but that doesn’t work. Gotta do the named parameter approach.

A Practical Tip For Using Sass Default Parameters originally published on CSS-Tricks. You should get the newsletter and become a supporter.

Parcel CSS: A New CSS Parser, Transformer, and Minifier

Css Tricks - Wed, 01/12/2022 - 11:10am

Hot off the presses from Devon Govett, creator of Parcel, is Parcel CSS:

A CSS parser, transformer, and minifier written in Rust.

Nice. The CSS world could use a little processing shake up like this.

I just wrote a few weeks ago:

Ya know how esbuild has seriously shaken things up for the JavaScript processing world? Maybe we need a cssbuild? It would process imports and do bundling (something we generally rely on Sass for). The point would be extreme speed. Maybe it would be plugin-based and compatible with the PostCSS API so that existing PostCSS plugins would work on it. Maybe it could make sourcemaps and do modification. Maybe it would run your Sass, too, I dunno. But something to spark the CSS ecosystem like that could be cool.

Close! It looks like it doesn’t do bundling (standalone anyway). I suppose it would have to just invent a syntax for that, as I think Sass somewhat regrets the ambiguity of how it uses @import just like native CSS does and I wouldn’t blame anyone for not wanting to go down that road. It’s tricky territory, for sure, as inventing syntax kinda puts it into a different category of tool. I think it would be worth it though, as breaking up CSS into smaller files but bundling them in development is like… a thing people do, and I could see really wanting to use this without having to necessarily commit to Parcel (which can bundle).

So why run your CSS through this thing? From the docs, it looks like you’d wanna do that because…

(Originally, I thought it leveraged other tools for these tasks as tools like Autoprefixer and cssnano appeared in the project’s package.json file, but as the comment below from Devon confirms, Parcel CSS is a replacement for these, it doesn’t use them.)

But there is one more! Seems to me the killer Parcel CSS feature is what they are calling “Syntax lowering” meaning you can use “future” CSS today (like, say, nesting) by having it processed down to things that browsers understand, like Babel does in JavaScript. It feels similar in spirit to postcss-preset-env.

And crucially, it’s fast:

Parcel CSS is fast and outputs small files. (Source: @devongovett) Will Parcel CSS become an ecosystem?

So I guess the big question is: If Parcel CSS becomes the CSS parser of choice, will we get plugins? And if we do, will it become a robust ecosystem like PostCSS plugins?

Parcel CSS: A New CSS Parser, Transformer, and Minifier originally published on CSS-Tricks. You should get the newsletter and become a supporter.

Open Source & Sustainability

Css Tricks - Wed, 01/12/2022 - 10:51am

It’s a god-damned miracle to me that open source is as robust as it is in tech. Consider the options. You could have a job (or be entrepreneurial) with your coding skills and likely be paid quite well. Or, you could write code for free and have strangers yell at you every day at all hours. I like being a contributing kinda guy, but I don’t have the stomach for the latter.

Fair enough, in reality, most developers do a bit of coding work on both sides. And clearly, they find some value in doing open-source work; otherwise, they wouldn’t do it. But we’ve all heard the stories. It leads to developer burnout, depression, and countless abandoned projects. It’s like we know how to contribute to an open-source project (and even have some ground rules on etiquette), but lack an understanding of how to maintain it.

Dave, in “Sustaining Maintaining,” thinks it might be a lack of education on how to manage open source:

There’s plenty of write-ups on GitHub about how to start a new open source project, or how to add tooling, but almost no information or best practices on how to maintain a project over years. I think there’s a big education gap and opportunity here. GitHub has an obvious incentive to increase num_developers and num_repos, but I think it’s worthwhile to ease the burden of existing developers and increase the quality and security of existing repos. Open source maintenance needs a manual.

That’s a wonderful idea. I’ve been around tech a hot minute, but I don’t feel particularly knowledgeable about how to operate an open-source project. And frankly, that makes me scared of it, and my fear makes me avoid doing it at all.

I know how to set up the basics, but what if the project blows up in popularity? How do I manage my time commitment do it? How do I handle community disputes? Do I need a request for comments workflow? Who can I trust to help? What are the monetization strategies? What are the security concerns? What do I do when there starts to be dozens, then hundreds, then thousands of open issues? What do I do when I stop caring about this project? How do I stop myself from burning it to the ground?

If there was more education around how to do this well, more examples out there of people doing it well and benefitting from it, and some attempts at guardrails from the places that host them, that would go a long way.

Money is a key factor. Whenever I see success in open source, I see actually usable amounts of money coming in. I see big donations appropriately coming into Vue. I see Automattic building an empire around their core open-source products. I see Greensock having an open-source library but offering membership and a license for certain use cases and having that sustain a team long-term.

If you’re interested in monetizing open-source, Nicholas C. Zakas has been writing about it lately. It’s a three-parter so far, but starts here in “Making your open source project sponsor-ready, Part 1: Companies and trust”:

While it’s possible to bring in a decent amount of money through individual sponsorships, the real path to open source sustainability is to get larger donations from the companies that depend on your project. Getting $5 to $10 each month from a bunch of individuals is nice, but not as nice as getting $1,000 each month from a bunch of companies.

I think it would be cool to see a lot more developers making a proper healthy living on open source. If nothing else it would make me feel like this whole ecosystem is more stable.

Update: I wrote this before the whole Marak Squire kerfuffle, but I feel that just underscores all this.

Open Source & Sustainability originally published on CSS-Tricks. You should get the newsletter and become a supporter.

Netlify Identity, a Key Aspect to Jamstack Development

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

(This is a sponsored post.)

Netlify is amazing at static file hosting, but it’s really so much more than that. You can build any sort of website, even highly dynamic apps, with the Jamstack approach and static file hosting at the core.

Say you want to build a TODO app with users. Those users will need to sign up and log in. Can’t do that with a static site, right? You can, actually. Netlify helps with Netlify Identity, a robust offering they’ve had for years. Enabling it is just a few clicks in the admin UI, and they even provide auth widgets so you have to build precious little to get this working.

Now you’ve got a website with authentication, great! But how do you keep going with your TODO app? You’ll need some kind of cloud storage for the data on your user’s lists. For that, you’ll have to reach outside of Netlify to find a cloud storage provider you like. Netlify has had a first-class integration with Fauna for years, so that’s a good choice.

You’ll need to communicate with Fauna, of course, and being a static site, JavaScript is how that’s going to work. Fortunately, your client-side JavaScript can communicate with your own server-side JavaScript that Netlify helps with, which is called Netlify Functions. That’s right, Netlify helps you build/deploy Lambda functions. This means you can actually have the Lambda functions do the communicating with Faunda, keeping your API keys safe.

Those are the building blocks. This is a well-worn approach, and really at the heart of Jamstack. Need a head start? Netlify has templates for this kind of thing. Here are some examples with this approach in mind: netlify-fauna-todo-app and netlify-faunadb-example. We even have a tutorial that covers that. And there’s a one-minute video demo:

There you have it, a website that is every bit as dynamic as something you’d build with a traditional server. Only now, you’re building with Netlify meaning you get so many other advantages, like the fact that you’re deploying from commits to a Git repository and getting build previews, and every other amazing feature Netlify offers.

Netlify Identity, a Key Aspect to Jamstack Development originally published on CSS-Tricks. You should get the newsletter and become a supporter.

What Would it Take to Prevent CSS Tooltips From Overflowing?

Css Tricks - Tue, 01/11/2022 - 1:18pm

Say you have an elements with CSS tooltips and you’re going to position those tooltips such that it opens up next to the element on hover (or probably better: when clicked/tapped). Next to it where? Above it? What if the element is already really close to the top of the screen? In that case, it should probably open below it. Or vice versa — and the same goes for the left and right edges of the screen. You definitely want it to be visible rather than overflowing the viewport.

Sometimes when you open new UI elements, they need to be edge-aware to prevent the content inside from triggering weird scrollbars, or worse, cutting off content.

Very important what?!

This is an age-old problem on the web. I remember using jQuery UI tooltips on purpose because it had this special ability to be edge-aware. You can imagine the JavaScript behind it. You figure out where the element is going to be and use positioning math to figure out if it will be within the viewport. If it won’t be, try a different position that does fit.

As ever, everything old is new again. Check out Floating UI, designed just for this problem.

Floating UI is a low-level toolkit to position floating elements while intelligently keeping them in view. Tooltips, popovers, dropdowns, menus, and more.

It looks super well done. I like the focus, the demos are super well done, and it’s a pretty tiny dependency.

But ya know what would be even cooler? If CSS could do this all by itself. That’s the vibe with CSS Anchored Positioning — for now just an “explainer” document:

When building interactive components or applications, authors frequently want to leverage UI elements that can render in a “top-layer”. Examples of such UI elements include content pickers, teaching UI, tooltips, and menus. “Enabling Popups” introduced a new popup element to make many of these top-layer elements easier to author.

Authors frequently wish to “pin” or “anchor” such top-layer UI to a point on another element, referred to here as an “anchor element”. How the top-layer UI is positioned with respect to its anchor element is further influenced or constrained by the edges of the layout viewport.

I love it. The web platform at its best. Seeing what authors are needing to do and reaching for libraries to do, and trying to step in and do it natively (and hopefully better).

What Would it Take to Prevent CSS Tooltips From Overflowing? originally published on CSS-Tricks. You should get the newsletter and become a supporter.

Adding Vite to Your Existing Web App

Css Tricks - Tue, 01/11/2022 - 5:38am

Vite (pronounced “veet”) is a newish JavaScript bundler. It comes batteries-included, requires almost no configuration to be useful, and includes plenty of configuration options. Oh—and it’s fast. Incredibly fast.

This post will walk through the process of converting an existing project to Vite. We’ll cover things like aliases, shimming webpack’s dotenv handling, and server proxying. In other words, we’re looking at how to move a project from its existing bundler to Vite. If you’re looking instead to start a fresh project, you’ll want to jump to their documentation.

Long story, short: the CLI will ask for your framework of choice—React, Preact, Svelte, Vue, Vanilla, or even lit-html—and whether you want TypeScript, then give you a fully functioning project.

Scaffold first! If you are interested in learning about integrating Vite into a legacy project, I’d still recommend scaffolding an empty project and poking around it a bit. At times, I’ll be pasting some clumps of code, but most of that comes straight from the default Vite template.

Our use case

What we’re looking at is based on my own experience migrating the webpack build of my booklist project (repo). There isn’t anything particularly special about this project, but it’s fairly big and old, and leaned hard on webpack. So, in that sense, it’s a good opportunity to see some of Vite’s more useful configuration options in action as we migrate to it.

What we won’t need

One of the most compelling reasons to reach for Vite is that it already does a lot right out of the box, incorporating many of the responsibilities from other frameworks so there are fewer dependencies and a more established baseline for configurations and conventions.

So, instead of starting by calling out what we need to get started, let’s go over all the common webpack things we don’t need because Vite gives them to us for free.

Static asset loading

We usually need to add something like this in webpack:

{ test: /\.(png|jpg|gif|svg|eot|woff|woff2|ttf)$/, use: [ { loader: "file-loader" } ] }

This takes any references to font files, images, SVG files, etc., and copies them over to your dist folder so they can be referenced from your new bundles. This comes standard in Vite.

Styles

I say “styles” as opposed to “css” intentionally here because, with webpack, you might have something like this:

{ test: /\.s?css$/, use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"] }, // later new MiniCssExtractPlugin({ filename: "[name]-[contenthash].css" }),

…which allows the application to import CSS or SCSS files. You’ll grow tired of hearing me say this, but Vite supports this out of the box. Just be sure to install Sass itself into your project, and Vite will handle the rest.

Transpilation / TypeScript

It’s likely your code is using TypeScript, and or non-standard JavaScript features, like JSX. If that’s the case, you’ll need to transpile your code to remove those things and produce plain old JavaScript that a browser (or JavaScript parser) can understand. In webpack that would look something like this:

{ test: /\.(t|j)sx?$/, exclude: /node_modules/, loader: "babel-loader" },

…with a corresponding Babel configuration to specify the appropriate plugins which, for me, looked like this:

{ "presets": ["@babel/preset-typescript"], "plugins": [ "@babel/plugin-proposal-class-properties", "@babel/plugin-syntax-dynamic-import", "@babel/plugin-proposal-optional-chaining", "@babel/plugin-proposal-nullish-coalescing-operator" ] }

While I could have probably stopped using those first two plugins years ago, it doesn’t really matter since, as I’m sure you’ve guessed, Vite does this all for us. It takes your code, removes any TypeScript and JSX, and produces code supported by modern browsers.

If you’d like to support older browsers (and I’m not saying you should), then there’s a plugin for that.

node_modules

Surprisingly, webpack requires you to tell it to resolve imports from node_modules, which we do with this:

resolve: { modules: [path.resolve("./node_modules")] }

As expected, Vite already does this.

Production mode

One of the common things we do in webpack is distinguish between production and development environments by manually passing a mode property, like this:

mode: isProd ? "production" : "development",

…which we normally surmise with something like this:

const isProd = process.env.NODE_ENV == "production";

And, of course, we set that environment variable via our build process.

Vite handles this a bit differently and gives us different commands to run for development builds versus those for production, which we’ll get into shortly.

File extensions

At the risk of belaboring the point, I’ll quickly note that Vite also doesn’t require you to specify every file extension you’re using.

resolve: { extensions: [".ts", ".tsx", ".js"], }

Just set up the right kind of Vite project, and you’re good to go.

Rollup plugins are compatible!

This is such a key point I wanted to call it out in its own section. If you still wind up with some webpack plugins you need to replace in your Vite app when you finish this blog post, then try to find an equivalent Rollup plugin and use that. You read that correctly: Rollup plugins are already (or usually, at least) compatible with Vite. Some Rollup plugins, of course, do things that are incompatible with how Vite works—but in general, they should just work.

For more info, check out the docs.

Your first Vite project

Remember, we’re moving an existing legacy webpack project to Vite. If you’re building something new, it’s better to start a new Vite project and go from there. That said, the initial code I’m showing you is basically copied right from what Vite scaffolds from a fresh project anyway, so taking a moment to scaffold a new project might also a good idea for you to compare processes.

The HTML entry point

Yeah, you read that right. Rather than putting HTML integration behind a plugin, like webpack does, Vite is HTML first. It expects an HTML file with a script tag to your JavaScript entrypoint, and generates everything from there.

Here’s the HTML file (which Vite expects to be called index.html) we’re starting with:

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>The GOAT of web apps</title> </head> <body> <div id="home"></div> <script type="module" src="/reactStartup.tsx"></script> </body> </html>

Note that the <script> tag points to /reactStartup.tsx. Adjust that to your own entry as needed.

Let’s install a few things, like a React plugin:

npm i vite @vitejs/plugin-react @types/node

We also create the following vite.config.ts right next to the index.html file in the project directory.

import { defineConfig } from "vite"; import react from "@vitejs/plugin-react"; export default defineConfig({ plugins: [react()] });

Lastly, let’s add a few new npm scripts:

"dev": "vite", "build": "vite build", "preview": "vite preview",

Now, let’s start Vite’s development server with npm run dev. It’s incredibly fast, and incrementally builds whatever it needs to, based on what’s requested.

But, unfortunately, it fails. At least for right now.

We’ll get to how to set up aliases in a moment, but for now, let’s instead modify our reactStartup file (or whatever your entry file is called) as follows:

import React from "react"; import { render } from "react-dom"; render( <div> <h1>Hi there</h1> </div>, document.getElementById("home") );

Now we can run it our npm run dev command and browse to localhost:3000.

Hot module reloading (HMR)

Now that the development server is running, try modifying your source code. The output should update almost immediately via Vite’s HMR. This is one of Vite’s nicest features. It makes the development experience so much nicer when changes seem to reflect immediately rather than having to wait, or even trigger them ourselves.

The rest of this post will go over all the things I had to do to get my own app to build and run with Vite. I hope some of them are relevant for you!

Aliases

It’s not uncommon for webpack-based projects to have some config like this:

resolve: { alias: { jscolor: "util/jscolor.js" }, modules: [path.resolve("./"), path.resolve("./node_modules")] }

This sets up an alias to jscolor at the provided path, and tells webpack to look both in the root folder (./) and in node_modules when resolving imports. This allows us to have imports like this:

import { thing } from "util/helpers/foo"

…anywhere in our component tree, assuming there’s a util folder at the very top.

Vite doesn’t allow you to provide an entire folder for resolution like this, but it does allow you to specify aliases, which follow the same rules as the @rollup/plugin-alias:

import { defineConfig } from "vite"; import react from "@vitejs/plugin-react"; import path from "path"; export default defineConfig({ resolve: { alias: { jscolor: path.resolve("./util/jscolor.js"), app: path.resolve("./app"), css: path.resolve("./css"), util: path.resolve("./util") } }, plugins: [react()] });

We’ve added a resolve.alias section, including entries for everything we need to alias. Our jscolor util is set to the relevant module, and we have aliases for our top-level directories. Now we can import from app/, css*/*, and util/ from any component, anywhere.

Note that these aliases only apply to the root of the import, e.g. util/foo. If you have some other util folder deeper in your tree, and you reference it with this:

import { thing } from "./helpers/util";

…then the alias above will not mess that up. This distinction is not well documented, but you can see it in the Rollup alias plugin. Vite’s alias matches that same behavior.

Environment variables

Vite, of course, supports environment variables. It reads config values out of your .env files in development, or process.env, and injects them into your code. Unfortunately, things work a bit differently than what you might be used to. First, it does not replace process.env.FOO but rather import.meta.env.FOO. Not only that, but it only replaces variables prefixed with VITE_ by default. So, import.meta.env.VITE_FOO would actually be replaced, but not my original FOO. This prefix can be configured, but not set to empty string.

For a legacy project, you could grep and replace all your environment variables to use import.meta.env, then add a VITE_ prefix, update your .env files, and update the environment variables in whatever CI/CD system you use. Or you can configure the more classic behavior of replacing process.env.ANYTHING with values from a .env file in development, or the real process.env value in production.

Here’s how. Vite’s define feature is basically what we need. This registers global variables during development, and does raw text replacement for production. We need to set things up so that we manually read our .env file in development mode, and the process.env object in production mode, and then add the appropriate define entries.

Let’s build that all into a Vite plugin. First, run npm i dotenv.

Now let’s look at the code for the plugin:

import dotenv from "dotenv"; const isProd = process.env.NODE_ENV === "production"; const envVarSource = isProd ? process.env : dotenv.config().parsed; export const dotEnvReplacement = () => { const replacements = Object.entries(envVarSource).reduce((obj, [key, val]) => { obj[`process.env.${key}`] = `"${val}"`; return obj; }, {}); return { name: "dotenv-replacement", config(obj) { obj.define = obj.define || {}; Object.assign(obj.define, replacements); } }; };

Vite sets process.env.NODE_ENV for us, so all we need to do is check that to see which mode we’re in.

Now we get the actual environment variables. If we’re in production, we grab process.env itself. If we’re in dev, we ask dotenv to grab our .env file, parse it, and get back an object with all the values.

Our plugin is a function that returns a Vite plugin object. We inject our environment values into a new object that has process.env. in front of the value, and then we return our actual plugin object. There is a number of hooks available to use. Here, though, we only need the config hook, which allows us to modify the current config object. We add a define entry if none exists, then add all our values.

But before moving forward, I want to note that the Vite’s environment variables limitations we are working around exist for a reason. The code above is how bundlers are frequently configured, but that still means any random value in process.env is stuck into your source code if that key exists. There are potential security concerns there, so please keep that in mind.

Server proxy

What does your deployed web application look like? If all it’s doing is serving JavaScript/CSS/HTML—with literally everything happening via separate services located elsewhere—then good! You’re effectively done. What I’ve shown you should be all you need. Vite’s development server will serve your assets as needed, which pings all your services just like they did before.

But what if your web app is small enough that you have some services running right on your web server? For the project I’m converting, I have a GraphQL endpoint running on my web server. For development, I start my Express server, which previously knew how to serve the assets that webpack generated. I also start a webpack watch task to generate those assets.

But with Vite shipping its own dev server, we need to start that Express server (on a separate port than what Vite uses) and then proxy calls to /graphql over to there:

server: { proxy: { "/graphql": "http://localhost:3001" } }

This tells Vite that any requests for /graphql should be sent to http://localhost:3001/graphql.

Note that we do not set the proxy to http://localhost:3001/graphql in the config. Instead, we set it to http://localhost:3001 and rely on Vite to add the /graphql part (as well any any query arguments) to the path.

Building libs

As a quick bonus section, let’s briefly discuss building libraries. For example, what if all you want to build is a JavaScript file, e.g. a library like Redux. There’s no associated HTML file, so you’ll first need to tell Vite what to make:

build: { outDir: "./public", lib: { entry: "./src/index.ts", formats: ["cjs"], fileName: "my-bundle.js" } }

Tell Vite where to put the generated bundle, what to call it, and what formats to build. Note that I’m using CommonJS here instead of ES modules since the ES modules do not minify (as of this writing) due to concerns that it could break tree-shaking.

You’d run this build with vite build. To start a watch and have the library rebuild on change, you’d run

vite build --watch.

Wrapping up

Vite is an incredibly exciting tool. Not only does it take the pain, and tears out of bundling web apps, but it greatly improves the performance of doing so in the process. It ships with a blazingly fast development server that ships with hot module reloading and supports all major JavaScript frameworks. If you do web development—whether it’s for fun, it’s your job, or both!—I can’t recommend it strongly enough.

Adding Vite to Your Existing Web App originally published on CSS-Tricks. You should get the newsletter and become a supporter.

What is Chromium Without Chrome on Top?

Css Tricks - Mon, 01/10/2022 - 12:02pm

Raw Chromium, perhaps?

So, Chrome is based on Chromium which is open-source. Chrome is Chromium with Google’s extra stuff on top of it. What extra stuff? Kinda lots! A few years ago, The Verge published “Microsoft reveals all the Google things it removed in its Chromium Edge browser” with this image from Microsoft listing out all the stuff:

That suggests all this stuff is actually in Chromium, not added later to Chrome in some additional process. That means if you wanna build your own Chromium fork and de-couple yourself from Google, you’ve got some work to do.

Several big players have done that work. Clearly, Microsoft has done it with Edge. Vivaldi and Brave are other big Chromium-based browsers with presumably similar de-Googleification.

Dan Abramov was asking around about this the other day:

is there a regularly updated mod of chrome that’s basically chromium (so chrome minus google-specific stuff except search) but also without experimental features and always based on a stable revision

— Dan (@dan_abramov) December 28, 2021

Sounds like Dan (and by extension: me) learned through this thread that Chromium isn’t actually just the core browser stuff where Chrome then adds stuff on top of it. It’s that if you want to base another browser on Chromium, you have to yank stuff out of Chromium.

Seems a smidge weird to me, but hey, it’s open-source, so if you don’t like it, fork it. And obviously many have. Perhaps most notable is ungoogled-chromium. It lists this as the philosophy:

  1. Remove all remaining background requests to any web services while building and running the browser
  2. Remove all code specific to Google web services
  3. Remove all uses of pre-made binaries from the source code, and replace them with user-provided alternatives when possible.
  4. Disable features that inhibit control and transparency, and add or modify features that promote them (these changes will almost always require manual activation or enabling).

I have zero doubt that the browser world is converging on Chromium. You can imagine Apple hanging onto their own thing with WebKit forever, but things don’t seem to be going terribly well at Mozilla, and they haven’t for a while. Mozilla’s money seems to come from Google anyway so it’s tough to imagine Mozilla’s browser engines hanging on for that much longer. Y’all can call me an ignorant asshole in January 2032 if Mozilla still has a competitive browser engine.

The health of the browser ecosystem would benefit from a cleaner, company-agnostic version of Chromium (and maybe call it something else). If most browsers are based on it, so be it, but let the innovation happen from a level playing field.

What is Chromium Without Chrome on Top? originally published on CSS-Tricks. You should get the newsletter and become a supporter.

Don’t Fight the Cascade, Control It!

Css Tricks - Mon, 01/10/2022 - 5:22am

If you’re disciplined and make use of the inheritance that the CSS cascade provides, you’ll end up writing less CSS. But because our styles often comes from all kinds of sources — and can be a pain to structure and maintain—the cascade can be a source of frustration, and the reason we end up with more CSS than necessary.

Some years ago, Harry Roberts came up with ITCSS and it’s a clever way of structuring CSS.

Mixed with BEM, ITCSS has become a popular way that people write and organize CSS.

However, even with ITCSS and BEM, there are still times where we still struggle with the cascade. For example, I’m sure you’ve had to @import external CSS components at a specific location to prevent breaking things, or reach for the dreaded !important at some point in time.

Recently, some new tools were added to our CSS toolbox, and they allow us to finally control the cascade. Let’s look at them.

O cascade, :where art thou?

Using the :where pseudo-selector allows us to remove specificity to “just after the user-agent default styles,” no matter where or when the CSS is loaded into the document. That means the specificity of the whole thing is literally zero — totally wiped out. This is handy for generic components, which we’ll look into in a moment.

First, imagine some generic <table> styles, using :where:

:where(table) { background-color: tan; }

Now, if you add some other table styles before the :where selector, like this:

table { background-color: hotpink; } :where(table) { background-color: tan; }

…the table background becomes hotpink, even though the table selector is specified before the :where selector in the cascade. That’s the beauty of :where, and why it’s already being used for CSS resets.

:where has a sibling, which has almost the exact opposite effect: the :is selector.

The specificity of the :is() pseudo-class is replaced by the specificity of its most specific argument. Thus, a selector written with :is() does not necessarily have equivalent specificity to the equivalent selector written without :is(). Selectors Level 4 specification

Expanding on our previous example:

:is(table) { --tbl-bgc: orange; } table { --tbl-bgc: tan; } :where(table) { --tbl-bgc: hotpink; background-color: var(--tbl-bgc); }

The <table class="c-tbl"> background color will be tan because the specificity of :is is the same as table, but table is placed after.

CodePen Embed Fallback

However, if we were to change it to this:

:is(table, .c-tbl) { --tbl-bgc: orange; }

…the background color will be orange, since :is has the weight of it’s heaviest selector, which is .c-tbl.

CodePen Embed Fallback Example: A configurable table component

Now, let’s see how we can use :where in our components. We’ll be building a table component, starting with the HTML:

CodePen Embed Fallback

Let’s wrap .c-tbl in a :where-selector and, just for fun, add rounded corners to the table. That means we need border-collapse: separate, as we can’t use border-radius on table cells when the table is using border-collapse: collapse:

:where(.c-tbl) { border-collapse: separate; border-spacing: 0; table-layout: auto; width: 99.9%; }

The cells use different styling for the <thead> and <tbody>-cells:

:where(.c-tbl thead th) { background-color: hsl(200, 60%, 40%); border-style: solid; border-block-start-width: 0; border-inline-end-width: 1px; border-block-end-width: 0; border-inline-start-width: 0; color: hsl(200, 60%, 99%); padding-block: 1.25ch; padding-inline: 2ch; text-transform: uppercase; } :where(.c-tbl tbody td) { background-color: #FFF; border-color: hsl(200, 60%, 80%); border-style: solid; border-block-start-width: 0; border-inline-end-width: 1px; border-block-end-width: 1px; border-inline-start-width: 0; padding-block: 1.25ch; padding-inline: 2ch; }

And, because of our rounded corners and the missing border-collapse: collapse, we need to add some extra styles, specifically for the table borders and a hover state on the cells:

:where(.c-tbl tr td:first-of-type) { border-inline-start-width: 1px; } :where(.c-tbl tr th:last-of-type) { border-inline-color: hsl(200, 60%, 40%); } :where(.c-tbl tr th:first-of-type) { border-inline-start-color: hsl(200, 60%, 40%); } :where(.c-tbl thead th:first-of-type) { border-start-start-radius: 0.5rem; } :where(.c-tbl thead th:last-of-type) { border-start-end-radius: 0.5rem; } :where(.c-tbl tbody tr:last-of-type td:first-of-type) { border-end-start-radius: 0.5rem; } :where(.c-tbl tr:last-of-type td:last-of-type) { border-end-end-radius: 0.5rem; } /* hover */ @media (hover: hover) { :where(.c-tbl) tr:hover td { background-color: hsl(200, 60%, 95%); } } CodePen Embed Fallback

Now we can create variations of our table component by injecting other styles before or after our generic styles (courtesy of the specificity-stripping powers of :where), either by overwriting the .c-tbl element or by adding a BEM-style modifier-class (e.g. c-tbl--purple):

<table class="c-tbl c-tbl--purple"> .c-tbl--purple th { background-color: hsl(330, 50%, 40%) } .c-tbl--purple td { border-color: hsl(330, 40%, 80%); } .c-tbl--purple tr th:last-of-type { border-inline-color: hsl(330, 50%, 40%); } .c-tbl--purple tr th:first-of-type { border-inline-start-color: hsl(330, 50%, 40%); } CodePen Embed Fallback

Cool! But notice how we keep repeating colors? And what if we want to change the border-radius or the border-width? That would end up with a lot of repeated CSS.

Let’s move all of these to CSS custom properties and, while we’re at it, we can move all configurable properties to the top of the component’s “scope“ — which is the table element itself — so we can easily play around with them later.

CSS Custom Properties

I’m going to switch things up in the HTML and use a data-component attribute on the table element that can be targeted for styling.

<table data-component="table" id="table">

That data-component will hold the generic styles that we can use on any instance of the component, i.e. the styles the table needs no matter what color variation we apply. The styles for a specific table component instance will be contained in a regular class, using custom properties from the generic component.

[data-component="table"] { /* Styles needed for all table variations */ } .c-tbl--purple { /* Styles for the purple variation */ }

If we place all the generic styles in a data-attribute, we can use whatever naming convention we want. This way, we don’t have to worry if your boss insists on naming the table’s classes something like .BIGCORP__TABLE, .table-component or something else.

In the generic component, each CSS property points to a custom property. Properties, that have to work on child-elements, like border-color, are specified at the root of the generic component:

:where([data-component="table"]) { /* These will will be used multiple times, and in other selectors */ --tbl-hue: 200; --tbl-sat: 50%; --tbl-bdc: hsl(var(--tbl-hue), var(--tbl-sat), 80%); } /* Here, it's used on a child-node: */ :where([data-component="table"] td) { border-color: var(--tbl-bdc); }

For other properties, decide whether it should have a static value, or be configurable with its own custom property. If you’re using custom properties, remember to define a default value that the table can fall back to in the event that a variation class is missing.

:where([data-component="table"]) { /* These are optional, with fallbacks */ background-color: var(--tbl-bgc, transparent); border-collapse: var(--tbl-bdcl, separate); }

If you’re wondering how I’m naming the custom properties, I’m using a component-prefix (e.g. --tbl) followed by an Emmett-abbreviation (e.g. -bgc). In this case, --tbl is the component-prefix, -bgc is the background color, and -bdcl is the border collapse. So, for example, --tbl-bgc is the table component’s background color. I only use this naming convention when working with component properties, as opposed to global properties which I tend to keep more general.

CodePen Embed Fallback

Now, if we open up DevTools, we can play around with the custom properties. For example, We can change --tbl-hue to a different hue value in the HSL color, set --tbl-bdrs: 0 to remove border-radius, and so on.

When working with your own components, this is the point in time you’ll discover which parameters (i.e. the custom property values) the component needs to make things look just right.

We can also use custom properties to control column alignment and width:

:where[data-component="table"] tr > *:nth-of-type(1)) { text-align: var(--ca1, initial); width: var(--cw1, initial); /* repeat for column 2 and 3, or use a SCSS-loop ... */ }

In DevTools, select the table and add these to the element.styles selector:

element.style { --ca2: center; /* Align second column center */ --ca3: right; /* Align third column right */ }

Now, let’s create our specific component styles, using a regular class, .c-tbl (which stands for “component-table” in BEM parlance). Let’s toss that class in the table markup.

<table class="c-tbl" data-component="table" id="table">

Now, let’s change the --tbl-hue value in the CSS just to see how this works before we start messing around with all of the property values:

.c-tbl { --tbl-hue: 330; }

Notice, that we only need to update properties rather than writing entirely new CSS! Changing one little property updates the table’s color — no new classes or overriding properties lower in the cascade.

Notice how the border colors change as well. That’s because all the colors in the table inherit from the --tbl-hue variable

We can write a more complex selector, but still update a single property, to get something like zebra-striping:

.c-tbl tr:nth-child(even) td { --tbl-td-bgc: hsl(var(--tbl-hue), var(--tbl-sat), 95%); }

And remember: It doesn’t matter where you load the class. Because our generic styles are using :where, the specificity is wiped out, and any custom styles for a specific variation will be applied no matter where they are used. That’s the beauty of using :where to take control of the cascade!

And best of all, we can create all kinds of table components from the generic styles with a few lines of CSS.

Purple table with zebra-striped columns Light table with a “noinlineborder” parameter… which we’ll cover next Adding parameters with another data-attribute

So far, so good! The generic table component is very simple. But what if it requires something more akin to real parameters? Perhaps for things like:

  • zebra-striped rows and columns
  • a sticky header and sticky column
  • hover-state options, such as hover row, hover cell, hover column

We could simply add BEM-style modifier classes, but we can actually accomplish it more efficiently by adding another data-attribute to the mix. Perhaps a data-param that holds the parameters like this:

<table data-component="table" data-param="zebrarow stickyrow">

Then, in our CSS, we can use an attribute-selector to match a whole word in a list of parameters. For example, zebra-striped rows:

[data-component="table"][data-param~="zebrarow"] tr:nth-child(even) td { --tbl-td-bgc: var(--tbl-zebra-bgc); }

Or zebra-striping columns:

[data-component="table"][data-param~="zebracol"] td:nth-of-type(odd) { --tbl-td-bgc: var(--tbl-zebra-bgc); }

Let’s go nuts and make both the table header and the first column sticky:

[data-component="table"][data-param~="stickycol"] thead tr th:first-child,[data-component="table"][data-param~="stickycol"] tbody tr td:first-child { --tbl-td-bgc: var(--tbl-zebra-bgc); inset-inline-start: 0; position: sticky; } [data-component="table"][data-param~="stickyrow"] thead th { inset-block-start: -1px; position: sticky; }

Here’s a demo that allows you to change one parameter at a time:

CodePen Embed Fallback

The default light theme in the demo is this:

.c-tbl--light { --tbl-bdrs: 0; --tbl-sat: 15%; --tbl-th-bgc: #eee; --tbl-th-bdc: #eee; --tbl-th-c: #555; --tbl-th-tt: normal; }

…where data-param is set to noinlineborder which corresponds to these styles:

[data-param~="noinlineborder"] thead tr > th { border-block-start-width: 0; border-inline-end-width: 0; border-block-end-width: var(--tbl-bdw); border-inline-start-width: 0; }

I know my data-attribute way of styling and configuring generic components is very opinionated. That’s just how I roll, so please feel free to stick with whatever method you’re most comfortable working with, whether it’s a BEM modifier class or something else.

The bottom line is this: embrace :where and :is and the cascade-controlling powers they provide. And, if possible, construct the CSS in such a way that you wind up writing as little new CSS as possible when creating new component variations!

Cascade Layers

The last cascade-busting tool I want to look at is “Cascade Layers.” At the time of this writing, it’s an experimental feature defined in the CSS Cascading and Inheritance Level 5 specification that you can access in Safari or Chrome by enabling the #enable-cascade-layers flag.

Bramus Van Damme sums up the concept nicely:

The true power of Cascade Layers comes from its unique position in the Cascade: before Selector Specificity and Order Of Appearance. Because of that we don’t need to worry about the Selector Specificity of the CSS that is used in other Layers, nor about the order in which we load CSS into these Layers — something that will come in very handy for larger teams or when loading in third-party CSS.

Perhaps even nicer is his illustration showing where Cascade Layers fall in the cascade:

Credit: Bramus Van Damme

At the beginning of this article, I mentioned ITCSS — a way of taming the cascade by specifying the load-order of generic styles, components etc. Cascade Layers allow us to inject a stylesheet at a given location. So a simplified version of this structure in Cascade Layers looks like this:

@layer generic, components;

With this single line, we’ve decided the order of our layers. First come the generic styles, followed by the component-specific ones.

Let’s pretend that we’re loading our generic styles somewhere much later than our component styles:

@layer components { body { background-color: lightseagreen; } } /* MUCH, much later... */ @layer generic { body { background-color: tomato; } }

The background-color will be lightseagreen because our component styles layer is set after the generic styles layer. So, the styles in the components layer “win” even if they are written before the generic layer styles.

Again, just another tool for controlling how the CSS cascade applies styles, allowing us more flexibility to organize things logically rather than wrestling with specificity.

Now you’re in control!

The whole point here is that the CSS cascade is becoming a lot easier to wrangle, thanks to new features. We saw how the :where and :is pseudo-selectors allows us to control specificity, either by stripping out the specificity of an entire ruleset or taking on the specificity of the most specific argument, respectively. Then we used CSS Custom Properties to override styles without writing a new class to override another. From there, we took a slight detour down data-attribute lane to help us add more flexibility to create component variations merely by adding arguments to the HTML. And, finally, we poked at Cascade Layers which should prove handy for specifying the loading order or styles using @layer.

If you leave with only one takeaway from this article, I hope it’s that the CSS cascade is no longer the enemy it’s often made to be. We are gaining the tools to stop fighting it and start leaning into even more.

Header photo by Stephen Leonardi on Unsplash

Don’t Fight the Cascade, Control It! originally published on CSS-Tricks. You should get the newsletter and become a supporter.

8 Interesting Typography Links for January 2022

Css Tricks - Fri, 01/07/2022 - 12:31pm

Every now and then, I find that I’ve accumulated a bunch of links about various things I find interesting. Typography is one of those things! Here’s a list of typography links to other articles that I’ve been saving up and think are worth sharing.

An awesome new font from OH no Type Company

Do you have any interesting typography links from the past month worth sharing? Drop ’em in the comments!

8 Interesting Typography Links for January 2022 originally published on CSS-Tricks. You should get the newsletter and become a supporter.

Syndicate content
©2003 - Present Akamai Design & Development.