Archive

Author Archive

CSS Functions and Mixins Module Notes

July 31st, 2024 No comments

Most days, I’m writing vanilla CSS. Thanks to CSS variables and nesting, I have fewer reasons to reach for Sass or any other preprocessor. The times I reach for Sass tend to be when I need a @mixin to loop through a list of items or help keep common styles DRY.

That could change for me in the not-so-distant future since a new CSS Functions and Mixins Module draft was published in late June after the CSSWG resolved to adopt the proposal back in February.

Notice the module’s name: Functions and Mixins. There’s a distinction between the two.

This is all new and incredibly unbaked at the moment with plenty of TODO notes in the draft and points to consider in future drafts. The draft spec doesn’t even have a definition for mixins yet. It’ll likely be some time before we get something real to work and experiment with, but I like trying to wrap my mind around these sorts of things while they’re still in early days, knowing things are bound to change.

In addition to the early draft spec, Miriam Suzanne published a thorough explainer that helps plug some of the information gaps. Miriam’s an editor on the spec, so I find anything she writes about this to be useful context.

There’s a lot to read! Here are my key takeaways…

Custom functions are advanced custom properties

We’re not talking about the single-purpose, built-in functions we’ve come to love in recent years — e.g., calc(), min(), max(), etc. Instead, we’re talking about custom functions defined with an @function at-rule that contains logic for returning an expected value.

That makes custom functions a lot like a custom property. A custom property is merely a placeholder for some expected value that we usually define up front:

:root {
  --primary-color: hsl(25 100% 50%);
}

Custom functions look pretty similar, only they’re defined with @function and take parameters. This is the syntax currently in the draft spec:

@function <function-name> [( <parameter-list> )]? {
  <function-rules>

  result: <result>;
}

The result is what the ultimate value of the custom function evaluates to. It’s a little confusing to me at the moment, but how I’m processing this is that a custom function returns a custom property. Here’s an example straight from the spec draft (slightly modified) that calculates the area of a circle:

@function --circle-area(--r) {
  --r2: var(--r) * var(--r);

  result: calc(pi * var(--r2));
}

Calling the function is sort of like declaring a custom property, only without var() and with arguments for the defined parameters:

.elenent {
  inline-size: --circle-area(--r, 1.5rem); /* = ~7.065rem */
}

Seems like we could achieve the same thing as a custom property with current CSS features:

:root {
  --r: 1rem;
  --r2: var(--r) * var(--r);
  --circle-area: calc(pi * var(--r2));
}

.element {
  inline-size: var(--circle-area, 1.5rem);
}

That said, the reasons we’d reach for a custom function over a custom property are that (1) they can return one of multiple values in a single stroke, and (2) they support conditional rules, such as @supports and @media to determine which value to return. Check out Miriam’s example of a custom function that returns one of multiple values based on the inline size of the viewport.

/* Function name */
@function --sizes(
  /* Array of possible values */
  --s type(length),
  --m type(length),
  --l type(length),
  /* The returned value with a default */
) returns type(length) {
  --min: 16px;

  /* Conditional rules */
  @media (inline-size < 20em) {
    result: max(var(--min), var(--s, 1em));
  }
  @media (20em < inline-size < 50em) {
    result: max(var(--min), var(--m, 1em + 0.5vw));
  }
  @media (50em < inline-size) {
    result: max(var(--min), var(--l, 1.2em + 1vw));
  }
}

Miriam goes on to explain how a comma-separated list of parameters like this requires additional CSSWG work because it could be mistaken as a compound selector.

Mixins help maintain DRY, reusable style blocks

Mixins feel more familiar to me than custom functions. Years of writing Sass mixins will do that to you, and indeed, is perhaps the primary reason I still reach for Sass every now and then.

Mixins sorta look like the new custom functions. Instead of @function we’re working with @mixin which is exactly how it works in Sass.

/* Custom function */
@function <function-name> [( <parameter-list> )]? {
  <function-rules>
  result: <result>;
}

/* CSS/Sass mixin */
@mixin <mixin-name> [( <parameter-list> )]? {
  <mixin-rules>
}

So, custom functions and mixins are fairly similar but they’re certainly different:

  • Functions are defined with @function; mixins are defined with @mixin but are both named with a dashed ident (e.g. --name).
  • Functions result in a value; mixins result in style rules.

This makes mixins ideal for abstracting styles that you might use as utility classes, say a class for hidden text that is read by screenreaders:

.sr-text {
  position: absolute;
  left: -10000px;
  top: auto;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

In true utility fashion, we can sprinkle this class on elements in the HTML to hide the text.

<a class="sr-text">Skip to main content</a>

Super handy! But as any Tailwind-hater will tell you, this can lead to ugly markup that’s difficult to interpret if we rely on many utility classes. Screereader text isn’t in too much danger of that, but a quick example from the Tailwind docs should illustrate that point:

<div class="origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg">

It’s a matter of preference, really. But back to mixins! The deal is that we can use utility classes almost as little CSS snippets to build out other style rules and maintain a clearer separation between markup and styles. If we take the same .sr-text styles from before and mixin-erize them (yep, I’m coining this):

@mixin --sr-text {
  position: absolute;
  left: -10000px;
  top: auto;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

Instead of jumping into HTML to apply the styles, we can embed them in other CSS style rules with a new @apply at-rule:

header a:first-child {
  @apply --sr-text;

  /* Results in: */
  position: absolute;
  left: -10000px;
  top: auto;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

Perhaps a better example is something every project seems to need: centering something!

@mixin --center-me {
  display: grid;
  place-items: center;
}

This can now be part of a bigger ruleset:

header {
  @apply --center-me;
  /*
    display: grid;
    place-items: center;
  */

  background-color: --c-blue-50;
  color: --c-white;
  /* etc. */
}

That’s different from Sass which uses @include to call the mixin instead of @apply. We can even return larger blocks of styles, such as styles for an element’s ::before and ::after pseudos:

@mixin --center-me {
  display: grid;
  place-items: center;
  position: relative;

  &::after {
    background-color: hsl(25 100% 50% / .25);
    content: "";
    height: 100%;
    position: absolute;
    width: 100%;
  }
}

And, of course, we saw that mixins accept argument parameters just like custom functions. You might use arguments if you want to loosen up the styles for variations, such as defining consistent gradients with different colors:

@mixin --gradient-linear(--color-1, --color-2, --angle) {
  /* etc. */
}

We’re able to specify the syntax for each parameter as a form of type checking:

@mixin --gradient-linear(
  --color-1 type(color),
  --color-2 type(color),
  --angle type(angle),
) {
  /* etc. */
}

We can abstract those variables further and set default values on them:

@mixin --gradient-linear(
  --color-1 type(color),
  --color-2 type(color),
  --angle type(angle),
) {
  --from: var(--color-1, orangered);
  --to: var(--from-color, goldenrod);
  --angle: var(--at-angle, to bottom right);

  /* etc. */
}

…then we write the mixin’s style rules with the parameters as variable placeholders.

@mixin --gradient-linear(
  --color-1 type(color),
  --color-2 type(color),
  --angle type(angle),
) {
  --from: var(--color-1, orangered);
  --to: var(--from-color, goldenrod);
  --angle: var(--at-angle, to bottom right);

  background: linear-gradient(var(--angle), var(--from), var(--to));
}

Sprinkle conditional logic in there if you’d like:

@mixin --gradient-linear(
  --color-1 type(color),
  --color-2 type(color),
  --angle type(angle),
) {
  --from: var(--color-1, orangered);
  --to: var(--from-color, goldenrod);
  --angle: var(--at-angle, to bottom right);

  background: linear-gradient(var(--angle), var(--from), var(--to));

  @media (prefers-contrast: more) {
    background: color-mix(var(--from), black);
    color: white;
  }
}

This is all set to @apply the mixin in any rulesets we want:

header {
  @apply --gradient-linear;
  /* etc. */
}

.some-class {
  @apply --gradient-linear;
  /* etc. */
}

…and combine them with other mixins:

header {
  @apply --gradient-linear;
  @apply --center-me;
  /* etc. */
}

This is all very high level. Miriam gets into the nuances of things like:

  • Applying mixins at the root level (i.e., not in a selector)
  • Working with Container Queries with the limitation of having to set global custom properties on another element than the one that is queried.
  • The possibility of conditionally setting mixin parameters with something like @when/@else in the mixin. (Which makes me wonder about the newly-proposed if() function and whether it would be used in place of @when.)
  • Why we might draw a line at supporting loops the same way Sass does. (CSS is a declarative language and loops are imperative flows.)
  • Scoping mixins (@layer? scope? Something else?)

Miriam has an excellent outline of the open questions and discussions happening around mixins.

That’s, um, it… at least for now.

Gah, this is a lot for my blonde brain! Anytime I’m neck-deep in CSS specification drafts, I have to remind myself that the dust is still settling. The spec authors and editors are wrestling with a lot of the same questions we have — and more! — so it’s not like a cursory read of the drafts is going to make experts out of anyone. And that’s before we get to the fact that things can, and likely will, change by the time it all becomes a recommended feature for browsers to implement.

This will be an interesting space to watch, which is something you can do with the following resources:


CSS Functions and Mixins Module Notes originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

Categories: Designing, Others Tags:

Where You Can Still Get A Book Apart Titles

July 31st, 2024 No comments

It’s been a few months out since A Book Apart closed shop. I’m sad about it, of course. You probably are, too, if you have one of their many brightly-colored paperbacks sitting on a bookshelf strategically placed as a backdrop for your video calls.

It looked for a bit like the books would still be available for purchase through third-party distributors who could print them on demand or whatever. And then a redaction on A Book Apart’s original announcement:

UPDATE: Ownership and publishing rights for all books have been given back to their respective authors. Many authors are continuing to offer their work for free or in new editions. Our hope is that these books will continue to live on forever. A Book Apart no longer sells or distributes books, please reach out to authors for information about availability.

Oh, snap. The books are on the loose and several authors are making sure they’re still available. Eric Meyer, for example, says he and co-author Sara Wachter-Boettcher still figuring out what’s next for their Design for Real Life title:

One of the things Sara and I have decided to do is to eventually put the entire text online for free, as a booksite. That isn’t ready yet, but it should be coming somewhere down the road.

In the meantime, we’ve decided to cut the price of print and e-book copies available through Ingram. [Design for Real Life] was the eighteenth book [A Book Apart] put out, so we’ve decided to make the price of both the print and e-book $18, regardless of whether those dollars are American, Canadian, or Australian.

Ethan Marcotte has followed suit by listing his three titles on his personal website and linking up where they can be purchased at a generous discount off the original price tag, including his latest, You Deserve a Tech Union.

Others have quickly responded with free online versions of their books. Mat Marquis has offered JavaScript for Web Designers free online for a long time. He helped Chris Coyier do the same with Practical SVG this past week. Jeremy Keith put out one of my personal ABA faves (and the first ever ABA-published book) for free, HTML5 for Web Designers.

What about all the other titles? I dunno. A Book Apart simply doesn’t sell or distribute them anymore. Rachel McConnell sells Leading Content Design directly. Every other book I checked seems to be a link back to A Book Apart. We’ll have to see where the proverbial dust settles. The authors now hold all the rights to their works and may or may not decide to re-offer them. Meanwhile, many of the titles are listed in places like Goodreads, Amazon, Barnes & Nobile, etc.

Thanks for all the great reads and years, A Book Apart! You’ve helped man, many people become better web citizens, present company included.


Where You Can Still Get A Book Apart Titles originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

Categories: Designing, Others Tags:

Smashing Hour With Dave Rupert

July 30th, 2024 No comments

Smashing Magazine invited me to sit down for a one-on-one with “Uncle” Dave Rupert to discuss web components, yes, but also check in on Dave’s new Microsoft gig and what the ShopTalk co-host is working on these days.

I first met Dave in 2015 when CSS Dev Conf took place in my backyard, Long Beach. It’s not like we’ve been in super close touch between then and now — we may have only chatted one-on-one like that a couple other times — but talking with Dave each time feels like hanging with a close friend ands this time was no different. Good, good vibes and web nerdery.

To Shared LinkPermalink on CSS-Tricks


Smashing Hour With Dave Rupert originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

Categories: Designing, Others Tags:

Letter Spacing is Broken and There’s Nothing We Can Do About It… Maybe

July 29th, 2024 No comments
Letter spacing on paper. The letter spacing is only applied between the letters "b"s

This post came up following a conversation I had with Emilio Cobos — a senior developer at Mozilla and member of the CSSWG — about the last CSSWG group meeting. I wanted to know what he thought were the most exciting and interesting topics discussed at their last meeting, and with 2024 packed with so many new or coming flashy things like masonry layout, if() conditionals, anchor positioning, view transitions, and whatnot, I thought his answers had to be among them.

He admitted that my list of highlights was accurate on what is mainstream in the community, especially from an author’s point of view. However, and to my surprise, his favorite discussion was on something completely different: an inaccuracy on how the letter-spacing property is rendered across browsers. It’s a flaw so ingrained on the web that browsers have been ignoring the CSS specification for years and that can’t be easily solved by a lack of better options and compatibility issues.

Emilios’s answer makes sense — he works on Gecko and rendering fonts is an art in itself. Still, I didn’t get what the problem is exactly, why he finds it so interesting, and even why it exists in the first place since letter-spacing is a property as old as CSS. It wasn’t until I went into the letter-spacing rabbit hole that I understood how amazingly complex the issue gets and I hope to get you as interested as I did in this (not so) simple property.

What’s letter spacing?

The question seems simple: letter spacing is the space between letters. Hooray! That was easy, for humans. For a computer, the question of how to render the space between letters has a lot more nuance. A human just writes the next letter without putting in much thought. Computers, on the other hand, need a strategy on how to render that space: should they add the full space at the beginning of the letter, at the end, or halve it and add it on both sides of the letter? Should it work differently from left-to-right (LTR) languages, like English, to right-to-left (RTL) like Hebrew? These questions are crucial since choosing one as a standard shapes how text measurement and line breaks work across the web.

Which of the three strategies is used on the web? Depends on who you ask. The implementation in the CSS specifications completely differs from what the browsers do, and there is even incompatibility between browsers rendering engines, like Gecko (Firefox), Blink (Chrome, Brave, Opera, etc.), and WebKit (Safari).

What the CSS spec says

Let’s backpedal a bit and first know how the spec says letter spacing should work. At the time of writing, letter-spacing:

Specifies additional spacing between typographic character units. Values may be negative, but there may be implementation-dependent limits.

The formal specification has more juice to it, but this one gives us enough to understand how the CSS spec wants letter-spacing to behave. The keyword is between, meaning that the letter spacing should only affect the space between characters. I know, sounds pretty obvious.

So, as the example given on the spec, the following HTML:

<p>a<span>bb</span>c</p>

…with this CSS:

p {
  letter-spacing: 1em;
}

span {
  letter-spacing: 2em;
}

…should give an equal space between the two “b” letters:

However, if we run the same code on any browser (e.g., Chrome, Firefox, or Safari), we’ll see the spacing isn’t contained between the “b” letters, but also at the end of the complete word.

Letter spacing on browsers. The letter spacing is applied between the letters "b"s and on the right-hand side of the last letter "b"

What browsers do

I thought it was normal for letter-spacing to attach spacing at the end of a character and didn’t know the spec said otherwise. However, if you think about it, the current behavior does seem off… it’s just that we’re simply used to it.

Why would browsers not follow the spec on this one?

As we saw before, letter spacing isn’t straightforward for computers since they must stick to a strategy for where spacing is applied. In the case of browsers, the standard has been to apply an individual space at the end of each character, ignoring if that space goes beyond the full word. It may have not been the best choice, but it’s what the web has leaned into, and changing it now would result in all kinds of text and layout shifts across the web.

This leaves a space at the end of elements with bigger letter spacing, which is somewhat acceptable for LTR text, but it leaves a hole at the beginning of the text in an RTL writing mode.

CodePen Embed Fallback

The issue is more obvious with centered text, where the ending space pushes the text away from the element’s dead center. You’ve probably had to add padding on the opposite side of an element to make up for any letter-spacing you’ve applied to the text at least one time, like on a button.

CodePen Embed Fallback

As you can see, the blue highlight creates a symmetrical pyramid which our text sadly doesn’t follow.

What’s worse, the “end of each character” means something different to browsers, particularly when working in an RTL writing mode. Chrome and Safari (Blink/WebKit) say the end of a character is always on the right-hand side. Firefox (Gecko), on the other hand, adds space to the “reading” end — which in Hebrew and Arabic is the left-hand side. See the difference yourself:

Side-by-side comparison of letter spacing on Gecko and Blink/Webkit

Can this be fixed?

The first thought that comes to mind is to simply follow what the spec says and trim the unnecessary space at the ending character, but this (anti) solution brings compatibility risks that are simply too big to even consider; text measurement and line breaks would change, possibly causing breakage on lots of websites. Pages that have removed that extra space with workarounds probably did it by offsetting the element’s padding/margin, which means changing the behavior as it currently stands makes those offsets obsolete or breaking.

There are two real options for how letter-spacing can be fixed: reworking how the space is distributed around the character or allowing developers an option to choose where we want the ending space.

Option 1: Reworking the space distribution

The first option would be to change the current letter-spacing definition so it says something like this:

Specifies additional spacing applied to each typographic character unit except those with zero advance. The additional spacing is divided equally between the inline-start and -end sides of the typographic character unit. Values may be negative, but there may be implementation-dependent limits.

Simply put, instead of browsers applying the additional space at the end of the character, they would divide it equally at the start and end, and the result is symmetrical text. This would also change text measurements and line breaks, albeit to a lesser degree.

Letter spacing with the symmetrical fix. The letter spacing is equally applied around the letters "b"s

Now text that is center-aligned text is correctly aligned to the center:

Different examples of letter spacing being distributed between letters and achieving a symmetrical look

Option 2: Allowing developers an option to choose

Even if the offset is halved, it could still bring breaking layout shifts to pages which to some is still (rightfully) unacceptable. It’s a dilemma: most pages need, or at least would benefit, from leaving letter-spacing as-is, while new pages would enjoy symmetrical letter spacing. Luckily, we could do both by giving developers the option to choose how the space is applied to characters. The syntax is anybody’s guess, but we could have a new property to choose where to place the spacing:

letter-spacing-justify: [ before | after | left | right | between | around];

Each value represents where the space should be added, taking into account the text direction:

  • before: the spacing is added at the beginning of the letter, following the direction of the language.
  • after: the spacing is added at the end of the letter, following the direction of the language.
  • left: the spacing is added at the left of the letter, ignoring the direction of the language.
  • right: the spacing is added at the right of the letter, ignoring the direction of the language.
  • between: the spacing is added between characters, following the spec.
  • around: the spacing is divided around the letter.

Logically, the current behavior would be the default to not break anything and letter-spacing would become a shorthand for both properties (length and placing).

letter-spacing: 1px before;
letter-spacing: 1px right;
letter-spacing: 1px around;

letter-spacing: 1px;
/* same as: */
letter-spacing: 1px before;

What about a third option?

And, of course, the third option is to leave things as they are. I’d say this is unlikely since the CSSWG resolved to take action on the issue, and they’ll probably choose the second option if I had to bet the nickel in my pocket on it.

Now you know letter-spacing is broken… and we have to live with it, at least for the time being. But there are options that may help correct the problem down the road.


Letter Spacing is Broken and There’s Nothing We Can Do About It… Maybe originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

Categories: Designing, Others Tags:

3 Essential Design Trends, August 2024

July 29th, 2024 No comments

There’s something new to learn with each of this month’s featured website design trends. Let’s dig in!

Categories: Designing, Others Tags:

How to Start a Creative Venture With No Money

July 25th, 2024 No comments

Starting a creative venture with no money can be challenging, but it’s definitely possible with the right approach and mindset.

Categories: Designing, Others Tags:

Sarah Joy: Everybody’s Free (To Write Websites)

July 17th, 2024 No comments

Sarah Joy’s adaptation of the song “Everybody’s Free (To Wear Sunscreen)” (YouTube) originally by Baz Luhrman with lyrics pulled directly from Mary Schmich‘s classic essay, “Wear Sunscreen”. Anyone who has graduated high school since 1999 doesn’t even have to look up the song since it’s become an unofficial-official commencement ceremony staple. If you graduated in ’99, then I’m sorry. You might still be receiving ongoing treatment for the earworm infection from that catchy tune spinning endlessly on radio (yes, radio). Then again, those of us from those late-90’s classes came down with more serious earworm cases from the “I Will Remember You” and “Time of Your Life” outbreaks.

Some choice pieces of Sarah’s “web version”:

Don’t feel guilty if you don’t know what you want to do with your site. The most interesting websites don’t even have an introduction, never mind any blog posts. Some of the most interesting web sites I enjoy just are.

Add plenty of semantic HTML.

Clever play on words and selectors:

Enjoy your . Style it every way you can. Don’t be afraid of CSS, or what other people think of it. It’s the greatest design tool you’ll ever learn.

The time’s they are a-changin’:

Accept certain inalienable truths: connection speeds will rise, techbros will grift, you too will get old— and when you do, you’ll fantasize that when you were young websites were light-weight, tech founders were noble and fonts used to be bigger.

And, of course:

Respect the W3C.

Oh, and remember: Just build websites.

To Shared LinkPermalink on CSS-Tricks


Sarah Joy: Everybody’s Free (To Write Websites) originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

Categories: Designing, Others Tags:

Sara Joy: Everybody’s Free (To Write Websites)

July 17th, 2024 No comments

Sara Joy’s adaptation of the song “Everybody’s Free (To Wear Sunscreen)” (YouTube) originally by Baz Luhrman with lyrics pulled directly from Mary Schmich‘s classic essay, “Wear Sunscreen”. Anyone who has graduated high school since 1999 doesn’t even have to look up the song since it’s become an unofficial-official commencement ceremony staple. If you graduated in ’99, then I’m sorry. You might still be receiving ongoing treatment for the earworm infection from that catchy tune spinning endlessly on radio (yes, radio). Then again, those of us from those late-90’s classes came down with more serious earworm cases from the “I Will Remember You” and “Time of Your Life” outbreaks.

Some choice pieces of Sara’s “web version”:

Don’t feel guilty if you don’t know what you want to do with your site. The most interesting websites don’t even have an introduction, never mind any blog posts. Some of the most interesting web sites I enjoy just are.

Add plenty of semantic HTML.

Clever play on words and selectors:

Enjoy your . Style it every way you can. Don’t be afraid of CSS, or what other people think of it. It’s the greatest design tool you’ll ever learn.

The time’s they are a-changin’:

Accept certain inalienable truths: connection speeds will rise, techbros will grift, you too will get old— and when you do, you’ll fantasize that when you were young websites were light-weight, tech founders were noble and fonts used to be bigger.

And, of course:

Respect the W3C.

Oh, and remember: Just build websites.

To Shared LinkPermalink on CSS-Tricks


Sara Joy: Everybody’s Free (To Write Websites) originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

Categories: Designing, Others Tags:

15 Best New Fonts, July 2024

July 15th, 2024 No comments

Welcome to our monthly roundup of the best fonts we’ve found online in the last four weeks. This month, there are fewer sans serifs, and a lot more display faces. Retro is as popular as ever, and the recent trend for organic shapes continues. Enjoy!

Categories: Designing, Others Tags:

The Power of the Human Face in Web Design

July 10th, 2024 No comments

First impressions online are made in just a few seconds, so nailing your web design is crucial. Among the many elements to play with, one stands out for its universal appeal and psychological impact: human faces.

Categories: Designing, Others Tags: