Frontend Masters Boost RSS Feed https://frontendmasters.com/blog Helping Your Journey to Senior Developer Thu, 25 Apr 2024 23:38:06 +0000 en-US hourly 1 https://wordpress.org/?v=6.5.2 225069128 The HTML, CSS, and SVG for a Classic Search Form https://frontendmasters.com/blog/the-html-css-and-svg-for-a-classic-search-form/ https://frontendmasters.com/blog/the-html-css-and-svg-for-a-classic-search-form/#respond Thu, 25 Apr 2024 23:38:05 +0000 https://frontendmasters.com/blog/?p=1821 Let’s build a search form that looks like this:

That feels like the absolute bowl-it-down-the-middle search form right now. Looks good but nothing fancy. And yet, coding it in HTML and CSS I don’t think is perfectly intuitive and makes use of a handful of decently modern and slightly lesser used features.

The Label-Wrapping HTML

At a glance, this looks like an <input> all by itself. Perhaps the placeholder text is pushed in with some text-indent or something and an <svg> icon is plopped on top. But no, that’s actually harder than what we’ve done here. Instead we’re going to wrap the input in a label like this:

<label class="searchLabelWrap">
  Search
  <input type="search" placeholder="Search" class="searchInput" name="s">
</label>

This wrapping means the label and input are automatically tied to each other (e.g. clicking the label will focus the input) without having to use the for attribute and a matching id.

We’re also using the search type here on the input, which is semantically correct, but also gives us the free UX of having a ✖️ “clear search” icon in the input for free.

Wrapping All That in a Search and Form element

HTML now has a <search> element, so again that’s a semantically smart choice, and we’ll also use a <form> element so that submitting the search can be done with the Enter key. Gotta think UX! If you don’t like the extra wrapper, you could put role="search" on the <form>, but I like it:

<search>
  <form action="/search" method="GET" id="searchForm">
    <label class="searchLabelWrap">
       ...
    </label>
  </form>
</search> 

The GET method means it will append our search term as a search parameter which is usually a desirable trait of a search form. The name attribute of the input will be the search param key. That’s looking pretty solid right there.

Hiding the Label, Adding an Icon

We definitely need there to be a text label for the input for screen readers, but since we’ll be visually marking the input with both a visual icon and placeholder text, I think it’s OK to hide the text label while leaving it accessible.

<label class="searchLabelWrap">
  <span class="visually-hidden">Search</span>
  <svg viewBox="0 0 512 512" aria-hidden="true" class="icon">
    <path d="..." />
  </svg>
  <input type="search" placeholder="Search" class="searchInput">
</label>
.visually-hidden {
  position: absolute;
  left: -9999px;
}

Label Wrapping Styling

Without any CSS, we’re in this sort of situation:

Perfectly functional, but we’ve got work to do. Visually, we want the icon to appear inside the “input” area. So we’ll actually apply the background to the searchLabelWrap instead here, and wipe out all the styling on the input itself. While we’re at it, let’s think about Dark Mode/Light Mode and use the newfangled light-dark() function. This is very new so, ya know, do what you gotta do. We’ll keep things aligned with flexbox and apply very chill other styles:

.searchLabelWrap {
  display: flex;
  gap: 0.5rem;
  background: light-dark(var(--gray-light), var(--gray-dark));
  padding: 0.5rem 1rem;
  border-radius: 0.5rem;
}

.searchInput {
  border: 0;
  outline: 0; /* focus style on parent */
  background: transparent;
  font: inherit;
}

We’re doing the sin of removing the focus style on the input, which isn’t a very accessible thing to do. So we gotta bring that back!

Focus Within FTW

It’s actually the input itself which receives the :focus, but we can target the parent here instead. Maybe use :has() you say? Like :has(input:focus) could work, but there is actually a cleaner way here:

.searchLabelWrap {
  ...

  &:focus-within {
    outline: 2px solid var(--focus-blue);
    outline-offset: 2px;
  }
}

I love :focus-within it’s so cool. It was kinda the OG has and it was theorized when it came out that it could be a gateway to :has() and that’s totally what happened.

Also notice the outline-offset there. I think that’s a nice touch to push the somewhat beefy outline away a smidge.

The Icon

I’m a fan of just using inline SVG for icons. No network request and easy to style my friends. Here’s one:

<svg viewBox="0 0 512 512" aria-hidden="true" class="icon" width="
20">
  <path d="M505 442.7L405.3 343c-4.5-4.5-10.6-7-17-7H372c27.6-35.3 44-79.7 44-128C416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c48.3 0 92.7-16.4 128-44v16.3c0 6.4 2.5 12.5 7 17l99.7 99.7c9.4 9.4 24.6 9.4 33.9 0l28.3-28.3c9.4-9.4 9.4-24.6.1-34zM208 336c-70.7 0-128-57.2-128-128 0-70.7 57.2-128 128-128 70.7 0 128 57.2 128 128 0 70.7-57.2 128-128 128z" />
</svg>

I like tossing a width on there because an <svg> with a viewBox before CSS loads can load super wide on the screen and it’s akward. CSS will come in and make it right here:

.icon {
  width: 1rem;
  aspect-ratio: 1;
  fill: currentColor;
}

You could apply different styling, but here I’m making the icon text follow the text color so it’s easier to update. The icon is also essentially in a square area hence the simple aspect-ratio.

Colors

I used a few --custom-properties as we went. I’ll define them here at the root, as well as ensure our page knows we’re intending to support both modes:

html {
  color-scheme: light dark;

  --gray-light: #eee;
  --gray-dark: #333;
  --focus-blue: #1976d2;
}

body {
  background: light-dark(white, black);
  color: light-dark(black, white);
  font: 100%/1.5 system-ui, sans-serif;
}

That’ll do use nicely, finishing things off.

Demo

]]>
https://frontendmasters.com/blog/the-html-css-and-svg-for-a-classic-search-form/feed/ 0 1821
Feedback on Masonry Layout https://frontendmasters.com/blog/feedback-on-masonry-layout/ https://frontendmasters.com/blog/feedback-on-masonry-layout/#respond Wed, 24 Apr 2024 20:40:14 +0000 https://frontendmasters.com/blog/?p=1833 Jen Simmons posted Help us invent CSS Grid Level 3, aka “Masonry” layout over on the WebKit blog the other day and is actively soliciting feedback.

Our hope is that web designers and developers chime in (post to social media, write blog posts) with your thoughts about which direction CSS should take.

Don’t mind if I do.

Do we need Masonry Layout at all?

Jen writes:

Others are questioning whether or not this kind of layout is needed on the web at all — they aren’t sure that well-known websites will use it.

I think people will use it. It can be a compelling way to lay out blocks of content. For “image galleries” alone I feel like it’s worth having a good solution for. To name the most notorious example, this type of layout has been an iconic part of the Pinterest branding since forever. How’s that for a well-known website? I’d love to see the day the actual pinterest.com uses a native web platform masonry.

Screenshot of homepage of pinterest.com

There are lots of things on the web that have naturally different aspect ratios, like images and Card components with arbitrary content. A “normal” grid layout with perfectly horizontal grid row lines isn’t always a good fit. Here’s an example of a reviews website where the reviews are of different sizes, and a masonry look works well:

Web designers have been trying to pull this layout off in various ways for ages. There are various JavaScript based solutions (using JavaScript for layout isn’t ideal, but when there is no other choice, it happens). Perhaps most famously Masonry, where the 16k+ stars on GitHub is compelling alone.

The cows have made a path here. It’s a cowroad.

Do we need a new way of doing Masonry?

I’ve made the point in the past there are existing ways to pull of this layout entirely in CSS. You can use CSS columns.

You can also use flexbox.

That is literally the layout that masonry is achieving without inventing anything new. But that leads to the next two sections.

This is partially a conversation about tabbing order.

Notice in the example above, the boxes are layed out as going “down” the first column, then back up to the second column at whatever box naturally comes next. This depends on the available width. But it might end up something like this:

[ 1 ] [ 4 ] [ 8 ]
[ 2 ] [ 5 ] [ 9 ]
[ 3 ] [ 6 ]
[ 7 ]

This is where I’m not 100% sure if problems set in or not. As I currently understand it:

  • ✅ Sighted mouse/trackpad user: not a problem
  • ✅ 100% screen reader user: not a problem
  • ⚠️ User that relies on tabbing through content visually: Maybe a problem??

So I’d love to fully understand if this vertical-by-row stacking order is actually a problem or not. And if it is, and it’s the only problem, are there other ways of solving it other than totally abandoning the columns approach? Is there some version of the (fake) idea .masonry-layout-with-columns { tabbing-order: visual; }?

So then as I understand it, if CSS grid-powered masonry became a thing, it kinda “solves” this by maintaining “as horizontal as-it-can” tabbing order. So tabbing through content goes more like this:

Screenshot of browser with masonry layout of a bunch of images. Arrows drawn over the top showing the tabbing order, which goes a bit up and down as it moves from image to image horizontally.
Is this definitely better than tabbing up and down columns? Unclear.

Is that actually better? It seems kinda funky either way to me. I just wouldn’t automatically take it for granted that this horizontal-ish tabbing order is automatically better. If the elements are of wildly different sizes, I can imagine the tabbing being more awkward than the column style tabbing (which is at least predictable).

Although if the columns went down much further than one viewport height, then I do see how the horizontal-ish method is preferable.

The name is a little funny.

The term masonry implies “like a mason would lay out bricks for a brick wall”. That’s funny to me as in that case, there actually are hard “row” lines.

brick wall

That kind of layout is already totally doable with flexbox and flex wrapping.

So I suppose the actual name masonry doesn’t feel quite right to me, especially for a term getting codified into the language.

I see “waterfall” is a possible alternative name and I think I’d vote that direction (I see there is active discussion). Or maybe the grid-template-rows: off; that actually feels nicely logical.

Didn’t we already go down this road?

Jen reminds:

A mechanism in CSS for “masonry layout” was first proposed by Mozilla in January 2020 as an extension of CSS Grid, and implemented as an experiment behind a flag in Firefox Nightly.

I’ve had a site using that as a “progressive enhancement” for most of the 4 years that’s been out. You can just set up a grid without masonry, and just add it on if it would work nicely.

.grid {
   display: grid;
   grid-template-columns: repeat(2, 1fr);
   gap: 4rem;
   grid-template-rows: masonry;
}

Seems perfectly fine to me. That would work by setting an alternative grid-template-rows on the line above as a fallback if needed or with using @supports to test the property: value pair.

Just because a test version got implemented doesn’t mean the final version has to follow that, I’m just saying I’ve played with it and used it and it seems fine.

Is it right for CSS grid?

Jen writes:

Some people remain skeptical that this capability should be part of CSS Grid

Questioning the current proposal is good. But you can’t just say you don’t like it without a pretty strong why or better alternatives. I didn’t scour the discourse myself, but the only one I see clearly in the article is:

main {
  display: masonry;
  masonry-columns: repeat(5, minmax(28ch, 1fr)); 
}

I don’t hate it, but it is a bit more limited than the fancier possibilities of grid-template-columns.

My main disagreement is that I feel like display is already so overloaded. It’s annoying to me that the same property that dictates the kind of layout the element does internally is the same thing that hides the element entirely. To me since the idea works well within the context of grid already, just use grid. Like it just seems like a natural fit.

Just this kind of control to me is obviously compelling:

And see the post for Jen’s example of using max-content columns which is honestly even more practical.

Mega menus have been hard to code, especially across multiple screen sizes. With CSS Grid Level 3, it becomes incredibly easy. A few lines of code creates a dynamic layout which adds and removes columns one at a time as space allows — without any media/container queries, and with wrapping prevention.

Then you add spanning columns to the party and subgrid and it’s clear me Jen has made a very strong case for adding “masonry” to CSS grid.

More

  • Do we ever get multiple values for gap where we can control the space between different rows/columns differently? Does the display: masonry approach allow that where grid would not?
  • Can we get a “automatically make tabbing order visually logical, I’m sick of thinking about it and want to re-order and re-arrange things as pleases me” situation going?
  • Are there any more fleshed out alternative proposals?
  • Are there any problems with using CSS grid for this? The advantages seem clear but the disadvantages do not.
  • Controlling individual column widths is sweet, should that make its way to CSS columns?
]]>
https://frontendmasters.com/blog/feedback-on-masonry-layout/feed/ 0 1833
Web Awesome Kickstarter https://frontendmasters.com/blog/web-awesome-kickstarter/ https://frontendmasters.com/blog/web-awesome-kickstarter/#respond Wed, 24 Apr 2024 15:12:39 +0000 https://frontendmasters.com/blog/?p=1823 What is the go-to component library these days? I’m not sure there is a clear winner right now. Bootstrap is still popular I’m sure. It seems stable but also sort on maintenance mode and the fact that they are recommending this feels like they are kinda done. I imagine the Sass dependency makes it slot into less and less new projects. The shadcn/ui project is having popularity boom, but the fact that it’s only for React also limits the reach.

Brad Frost kicked off discussion this year about what a global design system might be like. To my web-centric mind, the only answer to this is a component library of web components. And since that is the case, Shoelace is already on the job. I’ve only just learned that…

After setting the record in 2016 for the most funded and most backed software Kickstarter ever (both records still hold), the Font Awesome team is back with a new Kickstarter! Introducing: WEB AWESOME.

Essentially Shoelace 3 is now Web Awesome. Seems very smart. Building a business around what could become the go-to component library will help it become that and stay that.

]]>
https://frontendmasters.com/blog/web-awesome-kickstarter/feed/ 0 1823
Blocking AI Bots https://frontendmasters.com/blog/blocking-ai-bots/ https://frontendmasters.com/blog/blocking-ai-bots/#respond Tue, 23 Apr 2024 14:29:32 +0000 https://frontendmasters.com/blog/?p=1810 I heard from a guy once who was incredulous I’d want to block the bots that scrape websites to train AI models. Why wouldn’t I want to help train the intelligence of the future? I get that perspective, I do, but shouldn’t it be up to me? The companies that are scraping my sites are for-profit and turning the access to them into paid products. And they aren’t cutting checks — they’re drinking milkshakes. Nor are they typically linking to or crediting sources.

The AI company bots say they’ll respect a robots.txt directive, which is a file that instructs the permissions of whole-internet roving bots on a particular site. They might, but given the level of respect shown so far, I wouldn’t bet on it. I like the idea of instructing your actual web server to block the bots based on their User-Agent string. Ethan Marcotte did just this recently:

First, I polled a few different sources to build a list of currently-known crawler names. Once I had them, I dropped them into mod_rewrite rule in my .htaccess file:

<IfModule mod_rewrite.c>
RewriteEngine on
RewriteBase /

# block “AI” bots
RewriteCond %{HTTP_USER_AGENT} (AdsBot-Google|Amazonbot|anthropic-ai|Applebot|AwarioRssBot|AwarioSmartBot|Bytespider|CCBot|ChatGPT|ChatGPT-User|Claude-Web|ClaudeBot|cohere-ai|DataForSeoBot|Diffbot|FacebookBot|FacebookBot|Google-Extended|GPTBot|ImagesiftBot|magpie-crawler|omgili|Omgilibot|peer39_crawler|PerplexityBot|YouBot) [NC]
RewriteRule ^ – [F]
</IfModule>
]]>
https://frontendmasters.com/blog/blocking-ai-bots/feed/ 0 1810
The Front End Developer/Engineer Handbook 2024 — A Guide to Modern Web Development https://frontendmasters.com/blog/front-end-developer-handbook-2024/ https://frontendmasters.com/blog/front-end-developer-handbook-2024/#comments Tue, 23 Apr 2024 14:00:00 +0000 https://frontendmasters.com/blog/?p=1781 We just released the highly anticipated Frontend Handbook 2024, by Cody Lindley!

The handbook provides an in-depth overview of the skills, tools, and technologies necessary to excel as a front-end developer / engineer. With 38,000 words of practical knowledge and advice, it covers the core technologies—HTML, CSS, and JavaScript—and how they form the foundation of modern front-end development.

As Cody Lindley reflects on the current state of front-end development:

“Once upon a time, front-end development primarily focused on the user and the user interface, with programming/software playing a secondary role. […] We have to find our way back to the user, back to the user interface.”

Get an overview of popular tools, libraries, and frameworks that go beyond the front end, such as:

  • React.js/Next.js
  • Svelte/SveltKit
  • Vue.js/Nuxt
  • SolidJS/SolidStart
  • Angular
  • Astro
  • Qwik
  • Lit

These tools enable you to create full-stack web apps and websites that interact with databases and share templates across server and client.

You can also develop native applications using web technologies with frameworks like:

  • Electron for desktop apps
  • React Native and Capacitor for mobile apps
  • Tauri for mobile and desktop operating systems

Additionally, we touch on Progressive Web Apps (PWAs) and their ability to create installable applications with native-like experiences from a single codebase.

Whether you’re a seasoned front-end developer looking to refresh your understanding of the industry or a beginner eager to embark on a career in this exciting field, the Frontend Handbook 2024 is an essential resource.

To access the Frontend Handbook 2024, read it for free here:

]]>
https://frontendmasters.com/blog/front-end-developer-handbook-2024/feed/ 1 1781
Faces.js and Playing with Densely Packed Grids https://frontendmasters.com/blog/faces-js-and-playing-with-densely-packed-grids/ https://frontendmasters.com/blog/faces-js-and-playing-with-densely-packed-grids/#respond Mon, 22 Apr 2024 16:09:35 +0000 https://frontendmasters.com/blog/?p=1757 I only just recently saw Faces.js, a library for producing controllable cartoony avatars. It was launched in 2012, so I’m a little late to the party. It produces faces (busts, really) randomly, or with certain parameters locked to what you want.

# Generate a random face that always has blue skin
const face = generate({ body: { color: "blue" } });
display("my-div-id", face);

I think that’s a really cool idea, and if you needed this kind of thing on a project, you can install it yourself which is safer than using a hosted service for random avatars. Like, Pravatar is neat, but these services have a super high churn rate. Do not count on it sticking around.

I wanted to have a quick play and have it output a bunch of random faces on a grid. First I made 100 <div>s. You could do this any number of ways, including JavaScript, but I did it with Pug just for fun:

.faces
  - let i = 1;
  - while (i < 100)
    div(id=`face-${i}` class="face")
    - i++;

Then I made that into a grid:

.faces {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
}
.face {
  width: 100%
  aspect-ratio: 1 / 1;
}

Fun:

Hm. That makes me want to make the grid more interesting to look at, perhaps with some of the avatars spanning two columns (and thus two rows accommodate the height).

To do that I put a random number 1-10 on each face when creating the <div>s, as a data-* attribute:

.faces
  - let i = 1;
  - while (i < 100)
    - var n = Math.floor(Math.random() * 10 + 1);
    div(id=`face-${i}` class="face" data-size=n)
    - i++;

Then I can select some of them and make them bigger:

.face {
  width: 100%
  aspect-ratio: 1 / 1;
  
  &[data-size="5"] {
    grid-column: span 2;
    grid-row: span 2;
    scale: 1.2;
  }
}

I used scale there to juice the size even more and make them overlap:

I wanted to do a few more thing though. One, this left some gaps in the grid, as in, literal blank grid positions.

It’s incredibly satisfying to fill those in with just one extra grid declaration:

grid-auto-flow: dense;

Then I wanted the edges of the screen to allow for overlap, so the edges don’t seem perfectly lined up. I wanted it to look more like randomly cut wrapping paper. To do that, all I did was scale up the body (much like we did with the enlarged avatars) and then clip off the horizontal overlow.

body {
  scale: 1.2;
  overflow-x: clip;
}

I added a few more random sizes and scalings and, I dunno, it just ended up a satisfying little thing to play with.

Have you actually used a random avatar generator in a production app? On CodePen we just use a consistent generic one, which I hope kinda encourages people to replace it. I imagine random avatars are more useful in mockups and during development.

]]>
https://frontendmasters.com/blog/faces-js-and-playing-with-densely-packed-grids/feed/ 0 1757
Some Ascii Comments For Your Important Files https://frontendmasters.com/blog/some-ascii-comments-for-your-important-files/ https://frontendmasters.com/blog/some-ascii-comments-for-your-important-files/#respond Fri, 19 Apr 2024 17:31:19 +0000 https://frontendmasters.com/blog/?p=1737 Happy Friday!

Here’s a few ASCII “font” headers when you really need to make sure people know things when looking at your code or README document.

When you just don’t trust anyone but yourself:

  _|  _  ._ / _|_   _|_  _       _ |_  
(_| (_) | | |_ |_ (_) |_| (_ | |
___ __ __ __ ___ __ __ ____ __ __
// \\ (( \ || // // || || || \\ || (( \
||=|| \\ ||<< (( ||==|| ||_// || \\
|| || \_)) || \\ \\__ || || || \\ || \_))

When you need to explain why some weird code is the way it is:

 _     _   __  _____  ___   ___   _   __     __    _    
| |_| | | ( (` | | / / \ | |_) | | / /` / /\ | |
|_| | |_| _)_) |_| \_\_/ |_| \ |_| \_\_, /_/--\ |_|__
____ ____ ____ ____ ____ _ _ ____
|__/ |___ |__| [__ | | |\ | [__
| \ |___ | | ___] |__| | \| ___]

When there is that all important second step:

  , __                                _             
/|/ \ | |
|___/ _ _ _ _ _ _ _ _ | | _ ,_
| \ |/ / |/ |/ | |/ / |/ |/ | |/ \_|/ / |
| \_/|__/ | | |_/|__/ | | |_/\_/ |__/ |_/
.___________. ______ ______ __ _______ ___ .______
| | / __ \ / || | | ____| / \ | _ \
`---| |----`| | | | | ,----'| | | |__ / ^ \ | |_) |
| | | | | | | | | | | __| / /_\ \ | /
| | | `--' | | `----.| `----.| |____ / _____ \ | |\ \----.
|__| \______/ \______||_______||_______/__/ \__\ | _| `._____|

______ ___ ______ __ __ _______
/ | / \ / || | | | | ____|
| ,----' / ^ \ | ,----'| |__| | | |__
| | / /_\ \ | | | __ | | __|
| `----./ _____ \ | `----.| | | | | |____
\______/__/ \__\ \______||__| |__| |_______|
]]>
https://frontendmasters.com/blog/some-ascii-comments-for-your-important-files/feed/ 0 1737
What’s Going On in Dark Theme / Light Theme Land https://frontendmasters.com/blog/dark-and-light/ https://frontendmasters.com/blog/dark-and-light/#comments Thu, 18 Apr 2024 23:43:30 +0000 https://frontendmasters.com/blog/?p=1716 There has been a fresh round of enthusiasm and writing around light mode / dark mode support for the web lately. I think it’s driven partially by the new light-dark() function in CSS (CSS Color Module Level 5 spec) that makes it easier to declare values that change depending on the mode. Here’s the basic usage:

html {
  color-scheme: light dark;

  background: light-dark(white, black);
  color: light-dark(black, white);
}

In real life, you’d probably be using custom properties with your colors. So you’d set up your colors for light mode, then when the special dark mode media query matches, you’d re-declare all those variables, and then you’d use them. Paweł Grzybek has a nice basic explanation. Here’s a comparison.

You used to have to do this:

:root {
  color-scheme: light dark;

  --dark-color: #292524;
  --light-color: #f5f5f4;

  --text-color: var(--dark-color);
  --bg-color: var(--light-color);
}

@media (prefers-color-scheme: dark) {
  :root {
    --text-color: var(--light-color);
    --bg-color: var(--dark-color);
  }
}

body {
  color: var(--text-color);
  background-color: var(--bg-color);
}

And now you can do this:

:root {
  color-scheme: light dark;

  --light: #292524;
  --dark: #f5f5f4;
}

body {
  color: light-dark(var(--light), var(--dark));
  background-color: light-dark(var(--dark), var(--light));
}

Essentially, it prevents you from having to use the @media query and re-declare variables. I like it. I think it makes code like this more readable and succinct — pending variable naming and usage of course.

Here’s what it’s good for: designing a site that responds to the operating system level setting for light mode / dark mode. And you have to be good with the level of browser support (no Safari just yet, as I write, but it’s in preview). If you are wondering what the fallback is, it’s doing things the old way (see above), and if you’re going to write that you might as well leave it at that.

If you’re going to want to offer more themes than just light and dark, well, you’re out of luck here, you’ll need to implement something else, likely based on changing classes on the <html> element and updating variables when the class matches.

html.nickleoden-theme {
  --bg-color: purple;
  --text-color: green;
}

I could imagine a more composable toggle method in the future, but this is what we have for now.


When I first saw light-dark(), I liked the basic idea, but I figured as soon as you offer your own user toggle for mode, you’d be out of luck. After all, you can’t change what the prefers-color-scheme media query returns, and thus which of the two values light-dark() will pick. But it turns out you can! The trick lies in that color-scheme property. You’ll see recommendations that you use color-scheme: light dark;. If you only set one or the other, you’re forcing light-dark() to pick the relevant side.

So then your user toggle could force one or the other values on the document if it’s set. (If it’s not set, leave it alone!). Here’s that working:

I like that this is based on a CSS property, as it means that you can use the cascade if you need to, setting the color-scheme on a per-element basis.

That’s just cool I think.


Anne Sturdivant blogged some recent learnings about all this color theme stuff and I learned a few things. For one, color-scheme also has normal which is “no color schemes defined, default to the browser or OS setting”, which I would assume means works the same as light dark, but in my testing did not switch over to dark when I switched my OS 🤷. Then there is only as a keyword to, uhm, I guess even more forcibly set the theme? It’s not clear to me, and also not really supported yet anyway.

Annie also clearly points out that when you change the color-theme away from the default light mode, all sorts of stuff changes. It’s certainly not just the results of light-dark(). If you set dark, the UI scrollbars go dark, and all the different form controls go dark. In fact, that might be the number one use-case for color-scheme really, even if we do have accent-color now.


There is also this whole idea of System Colors that tends to come up in writing about this, so I’m going to do the same. These are “named” colors, like rebeccapurple, but they have a fancy baked in ability in that they can change when the color-scheme changes. So if you want to flip out basically white and black, but not bother with variables and fancy functions and whatnot, you’ve got:

body {
  background-color: Canvas;
  color: CanvasText;
  color-scheme: light dark;
}

Note the Canvas and CanvasText, those are the System Colors. Allow me to snipe the images of the available colors and what they look like in the different modes from a great article by Mads Stoumann.

Mads made a cool demo of a theme toggler that uses newfangled style queries that is worth checking out. Remember, though, that these client-side-only theme switchers are really just demos. It’s likely on a real-world site, if you’re offering a switcher, you should try to persist that information. A cookie, sessionStorage, localStorage, to a database… something. Then when you do that, there is the risk that the page renders before you can access and set that information, leading to FART, my most successful coining of an acronym ever. It’s a tricky thing, as delaying rendering just for something like this doesn’t feel right.


Another thing percolating in the industry is, as Bramus puts it: What if you had real control over Light Mode / Dark Mode on a per-site basis? I always say that web standards bodies, and even browsers themselves to some degree, are at their best when they see developers toiling and doing the same sort of things, and then introduce better and standardized methods. Properly implementing color themes and the toggling methods with persistence is real work! It doesn’t look like color themes are just a fad, so I think this is a clear opportunity for help.

I think a bit of browser UI would be perfectly welcome:

A perfect implementation would be that the browser itself remembers what choice you’ve made (light, dark, or default to system preference), and that is applied during rendering, avoiding FART. Sounds like it is going to require a new API and then potentially browsers actually using it themselves, which is kinda funny to think about. I normally think about web APIs as being for developers, not browsers.

]]>
https://frontendmasters.com/blog/dark-and-light/feed/ 2 1716
Things That Can Break aspect-ratio in CSS https://frontendmasters.com/blog/things-that-can-break-aspect-ratio-in-css/ https://frontendmasters.com/blog/things-that-can-break-aspect-ratio-in-css/#comments Tue, 16 Apr 2024 23:22:15 +0000 https://frontendmasters.com/blog/?p=1473 CSS has an aspect-ratio property, which has had full support since around 2021. It can be a very satisfying property to use, because it can help match how your brain 🧠 works or what the desired design outcome does better than forcing dimensions does. “I need a square here” or “I need to match the 16:9 size of a <video>are very reasonable design needs. Especially in a fluid environment where you’re purposely trying not to think in exact dimensions because you know they can change.

Usually, It Just Works

Here I’ve got a <div> sitting in a container. The <div> naturally fills the width. I’ve set aspect-ratio: 1 / 1; on it, thus, it’s a square. 🥁

That video example from the intro is also prudent. In that case, for whatever historical reason, <video> has a default style of being 300px wide, so if we want it to fill the space, we need to set width: 100% and then aspect-ratio will do what we want:

Element in a grid will behave nicely as well. Here, 12 <div>s are placed within a grid with a square aspect ratio and they respect it handily:

But things can go wrong, leaving an element that appears to not respect the aspect-ratio

Potential Breakage #1) Setting Both Dimensions

If both a height and width are set on an element, then aspect-ratio is ignored. That goes for block-size and inline-size too, of course, the logical property equivalents.

.el {
  inline-size: 300px;
  block-size: 200px;
  aspect-ratio: 1 / 1; /* does nothing */
}

That makes sense to me (which one would it ignore?), but it can be awfully confusing if one of the dimensions is set from somewhere you didn’t expect. Perhaps you were expecting to set a height and aspect-ratio on an <img>, not realizing your baseline CSS file also sets the width on images, that would make aspect-ratio fail somewhat unexpectedly.

This can be true of information outside of CSS as well. For example a height attribute on an <img> tag (which is highly recommended) counting as the other axis here and not allowing aspect-ratio to work:

Note that limiting dimensions with min-width, min-height, min-inline-size, min-block-size, max-width, max-height, max-block-size, max-inline-size will be respected and also might break the aspect-ratio.

Potential Breakage #2) Stretching

Here we have three <div> in a flex container all with different aspect ratios. But… they are all the same dimensions:

Why?! Those <div>s only have a width set on them, no height (or logical equivalent). The problem here is that the height/block-size is forced because flex items are influenced by the default align-items: stretch;

If we change that default to align-items: flex-start; on the parent flex container, you can see aspect-ratio start working:

This kind of thing can be true of any of the stretch values in CSS grid or flexbox. For example, CSS grid has justify-items: stretch; which is capable of causing this same kind of problem.

Potential Breakage #3) Content That Forces Height

One of the ways we used to pull of aspect-ratio was Uncle Dave’s ol’ Padded Box Trick. The box would be created by using padding-bottom on a zero-height box. Percentage padding is a percentage of the width, so that connection between width and height is established that way. But then you’d put an absolutely positioned box inside that. The problem with absolute positioning here is that the content is outside the normal flow of the document. So if, for example, you put text inside that is taller than the box, you’d have a problem. See below how the content hangs out of the box. The box has the right aspect-ratio, but it’s unlikely this is a desirable outcome:

If we use aspect-ratio for our box instead, we’ll get:

Now the orange box contains all the content, which again is probably the desired outcome here in most situations. But notably, the box is no longer the aspect-ratio that we declared.


Did I miss any of the ways aspect-ratio can break or have unexpected results? I suppose browser-support is another thing to consider, but it’s pretty solid.

]]>
https://frontendmasters.com/blog/things-that-can-break-aspect-ratio-in-css/feed/ 1 1473
require(esm) in Node.js https://frontendmasters.com/blog/requireesm-in-node-js/ https://frontendmasters.com/blog/requireesm-in-node-js/#comments Tue, 16 Apr 2024 22:09:17 +0000 https://frontendmasters.com/blog/?p=1707 Joyee Cheung made some waves in Node land last month:

Since ESM was shipped in Node.js, for many years, it was possible to import cjs, but not possible to require(esm). The frustration of ERR_REQUIRE_ESM has bothered many and probably has been the primary source of wasted hours in the Node.js ecosystem. If package authors wanted to make sure that both CJS and ESM users can consume their package, they either had to continue shipping their modules as CJS, or ship both the CJS and ESM version

Apparently, it will go out in v22, which isn’t out yet but should be soon.

It seems to me this should alleviate some of the pain the Node world is still feeling where projects and their dependencies are still a mix of both. But the true impact remains to be seen. Will you be upgrading to v22 to soothe any pain of your own?

]]>
https://frontendmasters.com/blog/requireesm-in-node-js/feed/ 1 1707