https://www.brycewray.com/posts/2023/02/some-future-now-css/
[ ]
*
* About
* Newest post
* All posts
* Search
* Privacy
* Contact/RSS
Some of the future is now for CSS
Intrigued by news from the WebKit team, I adopt styling that
could work natively in your browser in the near future.
2023-02-13
Reading time: 5:06 * 1,145 words
As usual, my timing was less than stellar.
No sooner had I finished revamping this site's styling setup with the
sass package than I learned that truly native CSS nesting -- as
opposed to the non-native version which had long compelled my use of
Sass in the first place -- might be arriving sooner than I'd thought
likely. In essence: "the future is now" may not be accurate where CSS
nesting is concerned; but "some of the future is now" likely either
is, or will be, before too long.
Thus, I spent a good part of this past weekend getting comfortable
with how native CSS nesting will work. In the process, I also learned
a few interesting (and occasionally annoying) facts about fully
native CSS, both as it exists now and as it may soon exist.
Word from the WebKit team
A few days ago, a post on the WebKit blog urged web developers to
give CSS nesting a try on Safari Technology Preview 162. The post,
written by long-time CSS guru Jen Simmons of the Apple/WebKit team,
explained that the feature's availability within both STP162 and
Google Chrome 112+ provided a perfect opportunity to perform such
tests.
(By the way: at this writing, the folks at Firefox would seem, based
on this bug report, to be nowhere near ready to add CSS nesting;
indeed, the feature doesn't even appear on Mozilla's Specification
Positions page.)
Update, 2023-07-15: It now appears Firefox will soon add native CSS
nesting. This capability will be available behind a flag in Firefox
115 and Firefox 116, and available by default in Firefox 117, to be
released 2023-08-29.
To provide some perspective, here's a brief example of how nesting in
Sass makes things easier. Instead of this in vanilla CSS:
body {
color: black;
background-color: white;
}
@media (prefers-color-scheme: dark) {
body {
color: white;
background-color: black;
}
}
. . . Sass lets you write it this way:
body {
color: black;
background-color: white;
@media (prefers-color-scheme: dark) {
color: white;
background-color: black;
}
}
. . . and then produces the earlier CSS when you run it through Sass.
When you're editing CSS elements and classes with many rules,
especially if many of those rules change depending on the results of
media queries like the one shown here, nesting enables you to do a
lot less typing and (if you don't go overboard with it) makes your
final code more readable. Nesting in vanilla CSS without the need for
tools like Sass and PostCSS is something web developers have long
wanted, and which has been the subject of much discussion and debate
over the years; but now, perhaps, it's crossing the line from Real
Soon Now^(tm) to reality.
The two primary reasons why I've mainly used Sass here on this site
have been nesting and variables. Although the latter feature, part of
CSS custom properties, has received good browser support for years
now, CSS nesting was the one biggie still hanging out there. With its
seeming approach, Simmons's post made me decide to check it out.
However, I decided to implement it in a way that would work in pretty
much any current browser: by using PostCSS along with the
postcss-nesting plugin, which mirrors how the official CSS nesting
specification works. I also took this opportunity to begin using
native CSS variables, too.
From Sass to (kinda) native
For the most part, the transition between my Sass styling and its
CSS-Nesting/custom-properties version went okay. I ran into a few
rough spots, however.
You can't get there from here
First of all, I learned that, unlike in Sass, you can't use a
variable to declare a media query. In Sass, you can do this:
$breakpoint-large: 1024px;
h1 {
font-size: 3rem;
@media screen and (min-width: $breakpoint-large) {
font-size: 4rem;
}
}
. . . but you can't do this with CSS variables:
:root {
--breakpoint-large: 1024px;
}
/* This media query **won't** work: */
h1 {
font-size: 3rem;
@media screen and (min-width: var(--breakpoint-large)) {
font-size: 4rem;
}
}
Ben Holmes's article explains it well. But, hey, that's what search/
replace is for, so I learned to live with it and do this, instead
(same example):
/* This media query **will** work: */
h1 {
font-size: 3rem;
@media screen and (min-width: 1024px) {
font-size: 4rem;
}
}
Another thing that brought me up short was the fact that the CSS
nesting spec doesn't allow concatenating selectors, although Sass and
some other nesting-savvy add-ons do. Here's a Sass example of what I
mean:
.homepage {
font-family: sans-serif;
&Leftside {
text-align: right;
font-size: 2rem;
}
}
. . . which Sass would compile to:
/* This is the desired result */
.homepage {
font-family: sans-serif;
}
.homepageLeftside {
text-align: right;
font-size: 2rem;
}
But if you try this with the CSS nesting spec, you get:
/*
This is NOT the desired result,
but is what you get from CSS nesting.
*/
.homepage: {
font-family: sans-serif;
}
Leftside.homepage {
text-align: right;
font-size: 2rem;
}
Thus, with CSS nesting, you'd have to do that sort of thing more
manually. Fortunately, I didn't have a lot of those to fix.
Partial-ly troublesome
Yet another temporary snag was that, through using PostCSS from
package.json to create the CSS files for Hugo Pipes to use, I had to
alter my usual practice of using Sass partials for better
organization of my styling. After getting some help with this from
Joe Mooring on the Hugo Discourse forum, I renamed each partial so
that Hugo Pipes would slurp them up in the right order:
. <-- The Hugo project folder
+- themes
+- newcss
+- assets
+- cssfrom
+- partials
+- 001_reset.css
+- 002_variables.css
+- 003_global.css
+- 050_utility.css
+- 060_nav.css
+- 070_vweights.css
+- 080_ffoxobliq.css
+- 099_print.css
Why cssfrom as that subfolder name in themes/newcss/assets/, by the
way? Because the css folder^1 -- i.e., the one my templating tells
Hugo Pipes to watch -- would be created and auto-populated during the
running of PostCSS from package.json, such as in these scripts:
"postcsscli": "postcss themes/newcss/assets/cssfrom --dir themes/newcss/assets/css",
"dev:postcss": "npm run postcsscli -- --watch",
. . . whereupon Hugo Pipes would be able to snarf it up for the
critical CSS to go in the head:
{{- $css := "" -}}
{{- $css = (resources.Match "css/0*.css") | resources.Concat "critical.css" -}}
{{- with $css }}
{{- end }}
. . . as well as for the "sorta scoped" styling that Hugo includes
conditionally throughout the site:
{{- range $cssTypes -}}
{{- $condition = index . 0 -}}
{{- $fileName = index . 1 -}}
{{- if eq $condition true -}}
{{- $css = resources.Get (print "css/" $fileName ".css") -}}
{{- if hugo.IsProduction -}}
{{- $css = $css | minify | fingerprint "md5" -}}
{{- end -}}
{{- end -}}
{{- end }}
Note: If those lines from package.json have you wondering why I did
it this way rather than relying solely on Hugo Pipes' built-in
PostCSS capabilities, it's because this approach works ten to fifteen
times faster in dev mode and seems to be a lot easier on my old box's
CPU.
Sharing arrangement
So, now, I have two themes for the site: (1.) one with Sass, and (2.)
one with CSS variables and PostCSS-enabled CSS nesting. One nice
thing about this setup is that, unlike the times when I've had a Sass
theme and a Tailwind CSS theme, I don't need two completely different
sets of layouts and Hugo partials to work with each theme. Rather,
the two themes can share the same layouts and nearly^2 all the same
partials, because these template files' final classes and rules are
the same. Indeed, the only drawback to the setup is that the scripts
part of package.json has grown quite a bit, since I have to provide
for both Sass and PostCSS.
Of course, I assume the CSS nesting specification -- whatever its
sort-of-final form will take -- will get largely universal browser
support someday, at which point things could get a lot simpler. Until
then, though, this setup will suffice.
Update later in the day: After receiving some additional information
from Jen Simmons via Mastodon, I revised/corrected links and examples
in this posts. Thanks, Jen!
---------------------------------------------------------------------
1. I include themes/newcss/assets/css in .gitIgnore, since this
folder and its contents get built every time I run Hugo. -[?]
2. Actually, there are three Hugo partials unique to each theme.
Two, excerpted above, are for the slightly different code that
pulls in the styling; and one is for the footer so I can specify,
on the "About" page, whether the site is using Sass or PostCSS.
-[?]
Latest commit (f98fd692) for page file:
2023-10-31 at 9:54:24 AM CDT.
Page history
Reply via email
"Reply via email" button and its contained email link hidden in an
attempt to limit spambots' access. Please activate JavaScript to see
the button.
View comments
Commenting feature requires activation of JavaScript.
PREV
Using Dart Sass with Hugo: taking it easy
Some of the future is now for CSS: a postscript
NEXT
Search this site
HTML sitemap * XML sitemap
Textual content (c) 2018-2023 Bryce Wray except where otherwise noted
and/or quoting external sources.
For other site-wide disclaimers/credits, see the footer of the "About
me" page.