astro icon indicating copy to clipboard operation
astro copied to clipboard

🐛 BUG: Scoped Styles and PostCSS don't work together

Open ran-dall opened this issue 3 years ago • 10 comments

What version of astro are you using?

1.0.0-beta.27

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

N/A

What package manager are you using?

npm

What operating system are you using?

Linux

Describe the Bug

I've noticed when using PostCSS that Scope Styles don't fit the workflow. When Astro components use Scope Styles, they seem to bypass whatever PostCSS pipeline is implemented. Aside from missing out on whatever optimizations you have set up, it also causes problems when using plugins that implement things like mixins and variables.

I don't know if there would be a way to address it, but Vue has a pretty nice implementation working with PostCSS. Maybe similar can be done?

Link to Minimal Reproducible Example

N/A

Participation

  • [ ] I am willing to submit a pull request for this issue.

ran-dall avatar May 13 '22 01:05 ran-dall

Astro should be running all your styles through PostCSS before scoping them—these were designed to work together.

If you have a specific use case that isn't working, please provide a reproduction!

natemoo-re avatar May 13 '22 14:05 natemoo-re

Hey @natemoo-re. Thanks for the response.

I can give you a very simple example...

Set a variable through PostCSS (and its official PostCSS Simple Variables plugin), and try to use the variable within a component as a Scoped Style. Vite should ack with immediately saying it can't find the variable.

For a similar error, you can do the same for the Mixins plugin (or the Stylelint & PostCSS reporter plugin combo; however, with this example, you'll not get any output (from Vite) as if there was no input checked).

This leads me to believe that the Scoped Styles aren't being run through PostCSS as intended (if that's the case).

ran-dall avatar May 13 '22 18:05 ran-dall

@natemoo-re Never really got a response on this. 🥺

Here's an example (with the official PostCSS Mixins plugin), if you still need it. It's a pretty simple demo really, as I've said...


This works.

src/styles/mixins.css

...
@define-mixin transition-cubic {
  transition: all 0.5s ease;
  transition-timing-function: cubic-bezier(0.86, 0, 0.07, 1);
  transition-duration: 700ms;
}
...

src/styles/style.css

...
@import "mixins.css";
...
.navbar {
  width: 100%;
  padding: 0;
  position: absolute;
  left: 0;
  top: 0;
  z-index: 3;

  .container {
    flex-direction: column;

    .upper-side {
      width: 100%;
      display: flex;
      flex-wrap: wrap;
      padding: 20px 0;
      align-items: center;
      transform: translateY(-80px);
      @add-mixin transition-cubic;
      transition-delay: 1.2s;

      .logo {
        margin-left: 0;

        img {
          height: 48px;
        }
      }

      .phone-email {
        margin-right: 0;
        margin-left: auto;
        margin-top: 5px;
        text-align: right;
        color: #fff;

        img {
          float: right;
          height: 34px;
          margin-left: 15px;
        }

        h4 {
          margin-bottom: -5px;
          margin-top: 3px;
          font-size: 17px;
          font-weight: 600;
          line-height: 1;
        }

        small {
          line-height: 1;

          a {
            opacity: 0.5;
            color: #fff;

            &:hover {
              text-decoration: none;
              color: $color-light;
              opacity: 1;
            }
          }
        }
      }

      .language {
        margin-right: 40px;
        margin-left: 60px;
        padding: 10px 0;
        padding-right: 30px;
        border-right: 1px solid rgba(255, 255, 255, 0.15);

        a {
          display: inline-block;
          margin: 0 5px;
          color: #fff;
          font-weight: 600;

          &:hover {
            color: $color-light;
            text-decoration: none;
          }
        }
      }

      .hamburger {
        width: 30px;
        height: 21px;
        margin-right: 0;
      }
    }

    .menu {
      width: 100%;
      display: flex;
      flex-wrap: wrap;
      border-top: 1px solid rgba(255, 255, 255, 0.15);
      @add-mixin transition-cubic;
      transition-delay: 1.4s;
      opacity: 0;

      ul {
        display: flex;
        flex-wrap: wrap;
        margin-left: auto;
        margin-right: 0;
        margin-top: -1px;

        li {
          margin: 0;
          margin-left: 40px;
          padding: 0;
          list-style: none;
          position: relative;

          &:hover ul {
            top: 100%;
            opacity: 1;
            visibility: visible;
          }

          ul {
            min-width: 220px;
            position: absolute;
            left: -35px;
            top: 120%;
            background: $color-dark;
            margin: 0;
            padding: 25px 0;
            opacity: 0;
            visibility: hidden;
            @add-mixin transition;

            &:before {
              content: "";
              width: 0;
              height: 0;
              border-style: solid;
              border-width: 0 10px 10px 10px;
              border-color: transparent transparent $color-dark
                transparent;
              position: absolute;
              left: 35px;
              top: -10px;
            }

            li {
              margin: 0;
              padding: 0 35px;
              white-space: nowrap;

              a {
                padding: 8px 0;

                &:hover {
                  border-color: transparent;
                }
              }
            }
          }

          a {
            color: #fff;
            display: inline-block;
            font-weight: 600;
            padding: 25px 0;
            border-top: 1px solid transparent;

            &:hover {
              text-decoration: none;
              color: $color-light;
              border-top: 1px solid $color-light;
            }
          }
        }
      }
    }
  }
}

This does not work.

src/styles/mixins.css

...
@define-mixin transition-cubic {
  transition: all 0.5s ease;
  transition-timing-function: cubic-bezier(0.86, 0, 0.07, 1);
  transition-duration: 700ms;
}
...

src/styles/style.css

...
@import "mixins.css";
...

src/components/Navbar.astro

...
<style>
.navbar {
  width: 100%;
  padding: 0;
  position: absolute;
  left: 0;
  top: 0;
  z-index: 3;

  .container {
    flex-direction: column;

    .upper-side {
      width: 100%;
      display: flex;
      flex-wrap: wrap;
      padding: 20px 0;
      align-items: center;
      transform: translateY(-80px);
      @add-mixin transition-cubic;
      transition-delay: 1.2s;

      .logo {
        margin-left: 0;

        img {
          height: 48px;
        }
      }

      .phone-email {
        margin-right: 0;
        margin-left: auto;
        margin-top: 5px;
        text-align: right;
        color: #fff;

        img {
          float: right;
          height: 34px;
          margin-left: 15px;
        }

        h4 {
          margin-bottom: -5px;
          margin-top: 3px;
          font-size: 17px;
          font-weight: 600;
          line-height: 1;
        }

        small {
          line-height: 1;

          a {
            opacity: 0.5;
            color: #fff;

            &:hover {
              text-decoration: none;
              color: $color-light;
              opacity: 1;
            }
          }
        }
      }

      .language {
        margin-right: 40px;
        margin-left: 60px;
        padding: 10px 0;
        padding-right: 30px;
        border-right: 1px solid rgba(255, 255, 255, 0.15);

        a {
          display: inline-block;
          margin: 0 5px;
          color: #fff;
          font-weight: 600;

          &:hover {
            color: $color-light;
            text-decoration: none;
          }
        }
      }

      .hamburger {
        width: 30px;
        height: 21px;
        margin-right: 0;
      }
    }

    .menu {
      width: 100%;
      display: flex;
      flex-wrap: wrap;
      border-top: 1px solid rgba(255, 255, 255, 0.15);
      @add-mixin transition-cubic;
      transition-delay: 1.4s;
      opacity: 0;

      ul {
        display: flex;
        flex-wrap: wrap;
        margin-left: auto;
        margin-right: 0;
        margin-top: -1px;

        li {
          margin: 0;
          margin-left: 40px;
          padding: 0;
          list-style: none;
          position: relative;

          &:hover ul {
            top: 100%;
            opacity: 1;
            visibility: visible;
          }

          ul {
            min-width: 220px;
            position: absolute;
            left: -35px;
            top: 120%;
            background: $color-dark;
            margin: 0;
            padding: 25px 0;
            opacity: 0;
            visibility: hidden;
            @add-mixin transition;

            &:before {
              content: "";
              width: 0;
              height: 0;
              border-style: solid;
              border-width: 0 10px 10px 10px;
              border-color: transparent transparent $color-dark
                transparent;
              position: absolute;
              left: 35px;
              top: -10px;
            }

            li {
              margin: 0;
              padding: 0 35px;
              white-space: nowrap;

              a {
                padding: 8px 0;

                &:hover {
                  border-color: transparent;
                }
              }
            }
          }

          a {
            color: #fff;
            display: inline-block;
            font-weight: 600;
            padding: 25px 0;
            border-top: 1px solid transparent;

            &:hover {
              text-decoration: none;
              color: $color-light;
              border-top: 1px solid $color-light;
            }
          }
        }
      }
    }
  }
}
</style>

ERROR

error   postcss-mixins: /mnt/site/src/components/Navbar.astro?astro&type=style&lang.css:22:7: Undefined mixin transition-cubic
    at /mnt/site/src/components/Navbar.astro?astro&type=style&lang.css:22:7
    at Input.error (/mnt/site/node_modules/postcss/lib/input.js:148:16)
    at Proxy.error (/mnt/site/node_modules/postcss/lib/node.js:60:32)
    at insertMixin (/mnt/site/node_modules/postcss-mixins/index.js:126:18)
    at add-mixin (/mnt/site/node_modules/postcss-mixins/index.js:211:13)
    at LazyResult.visitTick (/mnt/site/node_modules/postcss/lib/lazy-result.js:502:16)
    at LazyResult.runAsync (/mnt/site/node_modules/postcss/lib/lazy-result.js:410:30)
    at async compileCSS (/mnt/site/node_modules/vite/dist/node/chunks/dep-59dc6e00.js:35762:27)
    at async transform (/mnt/site/node_modules/vite/dist/node/chunks/dep-59dc6e00.js:35313:55)
    at async preprocessStyle (file:///mnt/site/node_modules/astro/dist/vite-plugin-astro/compile.js:44:24)l


So the src/styles/mixins.css has already been processed out (from what I'm assuming) by the time scoped style hits?

ran-dall avatar Jun 14 '22 20:06 ran-dall

Sorry for dropping the ball on this, @ran-dall! Really appreciate the helpful reproduction.

So the src/styles/mixins.css has already been processed out (from what I'm assuming) by the time scoped style hits?

That might be the case, but you're correct that this should be working. I'll get this into our backlog and hopefully we can figure out what is going on here soon.

natemoo-re avatar Jun 14 '22 21:06 natemoo-re

@natemoo-re 🤝 I appreciate you picking it back up.

ran-dall avatar Jun 14 '22 22:06 ran-dall

@ran-dall I'm digging into this one now to see where the page-level postcss mixins are being lost in the component, in the meantime I noticed there's a bit of a work around in case this is blocking you on anything

<style>
    @import "/src/styles/mixins.css";

    .navbar {
        ...
    }
</style>

Not ideal as the ultimate fix, but importing the mixins to the component directly will at least make sure they're defined when scoping styles. Hoping to find the right fix to handle this as expected though :+1:

tony-sull avatar Jun 27 '22 20:06 tony-sull

@tony-sull Thanks brother for looking into this. Yeah, this is what I've been doing to work around the problem but it becomes exceedingly harder when you start having to do this once for variables, mixins, etc...but I agree, at least it unblocks the issue.

ran-dall avatar Jun 28 '22 02:06 ran-dall

It turns out the fix for this will be pretty complex and a bit risky as we're prepping for 1.0. Bumping this down to a p2-has-workaround but this will be a great one for us to dig into post-1.0 to see what PostCSS improvements we can make!

tony-sull avatar Jul 20 '22 15:07 tony-sull

It turns out the fix for this will be pretty complex and a bit risky as we're prepping for 1.0. Bumping this down to a p2-has-workaround but this will be a great one for us to dig into post-1.0 to see what PostCSS improvements we can make!

Could you please keep this tagged as important? Working smoothly with PostCSS is pretty critical - how easy it is to fix is separate from how important the bug is!

pikeas avatar Jul 22 '22 19:07 pikeas

@tony-sull Thank you for looking into it, mate. Appreciate it. It makes sense that it would be a post-1.0 fix.

@pikeas Understand your concern; however, we do have a workable workaround for the time being, and I think the Team's focus right now is 1.0. If you need help making that work, feel free to pay us a visit at Support Squad on Discord.

ran-dall avatar Jul 23 '22 00:07 ran-dall