framework icon indicating copy to clipboard operation
framework copied to clipboard

Support remote and local assets in custom CSS

Open Fil opened this issue 1 year ago • 10 comments
trafficstars

This includes images and fonts using url().

Using onResolve (as suggested in https://github.com/observablehq/framework/issues/786#issuecomment-2070227596)

closes #786 supersedes #788

Capture d’écran 2024-05-20 à 19 58 41

The test above uses a remote @font-face and a local background asset (horse.jpg); but any file type is supported (so you can finally have the custom cursors you've been dreaming of).

TODO:

  • [x] use a resolver hook
  • [x] support css @import

Fil avatar May 20 '24 18:05 Fil

I think it's close to done? (I'm not sure what you have in mind so that it can be finished.)

Fil avatar May 23 '24 05:05 Fil

Have you pushed your changes? I don’t see any changes to getResolvers here.

mbostock avatar May 23 '24 11:05 mbostock

I changed bundleStyles to accept a resolve hook, to which I pass a function that uses getResolvers — but I don't understand what needs to be changed in getResolvers.

Fil avatar May 23 '24 12:05 Fil

We need to parse the stylesheets and resolve/collect all the transitive dependencies. We can pair on it sometime.

mbostock avatar May 23 '24 15:05 mbostock

I think it works already, see for example https://github.com/observablehq/framework/pull/1372/files#diff-8adbd6b9683bb1d5268aa477247f4c6edf9ea93e5b13397535ff450b4d57ae38 style.css loads atkinson.css which loads the font. (To demonstrate further I should maybe add a local resource to atkinson.css — but I've tried and it works too.) Unless I'm missing something, the one thing that doesn't work is watching and HMR.

Fil avatar May 23 '24 16:05 Fil

I’m aware it works, but I think we should implement it by moving it into getResolvers because that’s where it belongs. This will fix the watching/hot replacement issue.

mbostock avatar May 23 '24 19:05 mbostock

Been trying to import self-hosted font assets and stumbled upon this PR. It would be great to be able to define @font-face indeed!

choucavalier avatar Jun 04 '24 12:06 choucavalier

I think there’s probably a lot more that we want to do here, and I haven’t figured out yet if it makes sense to try to do it all together or if there’s a more piecemeal approach. Specifically, what about inline styles like this?

<style type="text/css">

body {
  background-image: url("image.png");
}

</style>

We could detect the reference to image.png above and rewrite the CSS to reference the file in _file. (Note that we couldn’t support body.style.backgroundImage = 'url("image.png")' in JavaScript because it’s not statically analyzable, but you could use a FileAttachment.)

Similarly, given this:

<link rel="stylesheet" href="test.css" type="text/css">

And the following stylesheet:

body {
  background-image: url("image.png");
}

Presumably we’d want to rewrite test.css to reference image.png in _file too.

And then there’s the question of whether test.css should be bundled into a single stylesheet, or if we should only rewrite the stylesheets to correct for references to local assets?

I want to think about this some more.

mbostock avatar Jul 07 '24 01:07 mbostock

Been trying to import self-hosted font assets and stumbled upon this PR. It would be great to be able to define @font-face indeed!

Allowing @font-face to import font files that are local to a project would be good practice for possible archiving.

shadoof avatar Jul 23 '24 11:07 shadoof

I realized we didn’t have a tracking issue for this, only the font-face crash bug #786, so I filed #1573.

mbostock avatar Aug 11 '24 14:08 mbostock

I ran into this issue yesterday and I came up with a different solution. I decided to host the web-fonts on a dedicated sub-domain of my main Observable Framework website. As a bonus, I ended up with a place to collect interesting open source typefaces. Explained more here: https://jamesking.io/2025/06/09/font-collection

jamesking avatar Jun 09 '25 13:06 jamesking