withastro / astro

The web framework for content-driven websites. ⭐️ Star to support our work!
https://astro.build
Other
46.71k stars 2.48k forks source link

Scoped styles do not work with HTML string #4380

Closed joshuaiz closed 2 years ago

joshuaiz commented 2 years ago

What version of astro are you using?

1.0.6

Are you using an SSR adapter? If so, which one?

None

What package manager are you using?

yarn

What operating system are you using?

Mac

Describe the Bug

When hydrating an .astro component with an HTML string, scoped styles e.g. styles in <style></style> tags in the file are not applied to the HTML.

As a workaround, I'm using node-html-parser and then applying Tailwind classes after querying selectors in the parsed HTML which do get applied so something like this:

---
import { parse } from "node-html-parser";
const { pageData } = Astro.props;

const pageHTML = parse(pageData.body_html);

const paragraphs = pageHTML.querySelectorAll("p");
paragraphs.forEach((p) => {
    p.setAttribute("class", "mb-6 text-stone-700");
});

const h2s = pageHTML.querySelectorAll("h2");
h2s.forEach((h2) => {
    h2.setAttribute("class", "text-2xl font-bold text-stone-700");
});
---

<header class="page-header max-w-[900px] mx-auto mt-8">
    <h1 class="text-2xl font-bold">{pageData.title}</h1>
</header>

<div class="page-outer">
    <div class="page-inner max-w-[900px] mx-auto flex flex-col items-center">
        <div class="page-content">
            {pageHTML}
        </div>
    </div>
</div>

...but this seems kind of clunky.

I would assume this is a pretty common use case:

  1. Get raw HTML string from CMS (e.g. blog or page)
  2. Parse HTML for display
  3. Add styling

In the linked example you can see that the scoped styles are not applied to the parsed HTML. This is the case when using either set:html or node-html-parser.

Link to Minimal Reproducible Example

https://github-pqlrez--3000.local.webcontainer.io

Participation

FredKSchott commented 2 years ago

This is expected behavior. CSS scoping runs through our compiler and works by analyzing the file contents. This isn't possible when the HTML of the component lives inside of a JS variable.

FWIW this is how CSS scoping in Svelte, Vue and other similar frameworks. If anyone can think of a solution, I think people would be interested to discuss as a follow-up improvement in https://github.com/withastro/rfcs/discussions.

argbeknwn commented 1 year ago

@FredKSchott Thank you for the answer. It makes more sense now. @joshuaiz Another possible approach for TailwindCSS. You can try to use @tailwindcss/typography to achieve similar results.

<div class="page-content  prose prose-h2:text-2xl prose-h2:font-bold prose-h2:text-stone-700">
   {pageHTML}
</div>

https://tailwindcss.com/docs/typography-plugin https://tailwindcss.com/docs/typography-plugin#element-modifiers

joshuaiz commented 1 year ago

@argbeknwn this is actually my approach now except defining my own .prose classes without using @tailwindcss/typography. There's nothing wrong with that package but just wanted more control over the defaults.

rkyoku commented 1 year ago

Hi!

@FredKSchott a possible solution would be to only add the scope selector to the first selected element and not on subsequent elements/selectors (because only one where() will be enough to scope the style).

It will solve the issue for people who take care to always include a "root" element (e.g. an element that was not dynamically injected) in their selectors.

---
const html = `<ul></ul>`
---
<style>
    .myroot > ul {background: green}
</style>
<div class="myroot" set:html={html}></div>

Produces current HTML

<div class="myroot astro-1234"><ul></ul></div>

Produces current CSS

.myroot:where(.astro-1234) > ul:where(.astro-1234)

Suggested CSS

/* only one scope selector is enough */
.myroot:where(.astro-1234) > ul

PS: it seems also possible to use :global() for each sub-selector that implies a dynamically generated element (e.g. one without the scope class)

illiantech commented 3 months ago

Astro v4.13.3 Node v20.15.1 System Windows (x64) Package Manager pnpm Output static Adapter none Integrations none

Hello, I came here looking for solutions for a similar problem I have.

my styles don't load unless they are inline, I even created a Totally new project in astro with the latest version

but the problem persists

mpstaton commented 1 month ago

Is there any solution besides using Tailwind? I have nothing against Tailwind, like it actually, but I'm just trying to use proper CSS in this project to make sure I don't get super distant from straight CSS.