MIT License

项目介绍

gnat/css-scope-inline 是一个托管在 GitHub 上的开源项目,主要使用 HTML 编写,采用 MIT License 许可证,目前获得 691 个 Star、17 次 Fork。

仓库全名
gnat/css-scope-inline
开源许可证
MIT License
Star 数
691
Fork 数
17
未关闭 Issue
2

README 摘要

🌘 CSS Scope Inline (Art by shahabalizadeh) Why does this exist? You want an easy inline vanilla CSS experience without Tailwind CSS. Hate creating unique class names over and over.. to use once. You want to co-locate your styles for ⚡️ Locality of Behavior (LoB) You wish this would work in tags. Want all CSS features: Nesting, animations. Get scoped @keyframes! You wish @media queries were shorter for responsive…

完整内容见 GitHub 原始 README 或本页 。

常见问题

css-scope-inline 用什么语言开发?

主要使用 HTML 编写,采用 MIT License 许可证,目前有 691 个 Star。

css-scope-inline 可以免费商用吗?

仓库采用 MIT License 许可证,可免费使用与修改,商业使用请遵守许可证条款(例如保留版权声明与许可声明)。

如何获取 css-scope-inline 的源码?

可以直接克隆仓库:git clone https://github.com/gnat/css-scope-inline.git,默认分支为 main;安装与运行步骤见仓库 README。

css-scope-inline 最近还在维护吗?

仓库最近一次更新为 3月26日,当前有 2 个未关闭 Issue;Star 数为 691,可作为社区活跃度的参考。

关于

🌘 Scope your inline style tags in pure vanilla CSS! Only 16 lines. No build. No dependencies.

描述取自 GitHub 官方 API,中文内容由 GitRead 中文社区 编辑团队整理。

简要分析

热度分
740
价值分
421
活跃状态
活跃

语言占比

HTML
JavaScript

README

🌘 CSS Scope Inline

cover (Art by shahabalizadeh)

Why does this exist?

  • You want an easy inline vanilla CSS experience without Tailwind CSS.
  • Hate creating unique class names over and over… to use once.
  • You want to co-locate your styles for ⚡️ Locality of Behavior (LoB)
  • You wish this would work in <style> tags.
  • Want all CSS features: Nesting, animations. Get scoped @keyframes!
  • You wish @media queries were shorter for responsive design.
  • Only 16 lines. No build step. No dependencies.
  • Pairs well with htmx and Surreal
  • Want fewer layers, less complexity. Are aware of the cargo cult. ✈️

✨ Want to also scope your <script> tags? See our companion project Surreal

👁️ How does it look?

<div>
    <style>
        me { background: red; } /* ✨ this & self also work! */
        me button { background: blue; } /* style child elements inline! */
    </style>
    <button>I'm blue</button>
</div>

See the Live Example! Then view source.

🌘 How does it work?

This uses MutationObserver to monitor the DOM, and the moment a <style> tag is seen, it scopes the styles to whatever the parent element is. No flashing or popping.

This leaves your existing styles untouched. Mix in scoped <style> at your leisure.

🎁 Install

✂️ copy + 📋 paste the snippet into <script> in your <head>

Or, 📥 download into your project, and add <script src="script.js"></script> in your <head>

Or, 🌐 CDN: <script src="https://cdn.jsdelivr.net/gh/gnat/css-scope-inline@main/script.js"></script>

🤔 Why consider this over Tailwind CSS?

Use whatever you’d like, but there’s a few advantages with this approach over Tailwind, Twind, UnoCSS:

  • No repeat styles on child elements (no more @apply, no [&>thing]).
  • No repeat prefixes for media queries, hover, focus, etc.
  • No visual noise on every <div>. Use <style> on groups of elements.
  • Share real CSS between inline <style> and .css files. Just replace me
  • Regain your “inspect + edit styles + paste” workflow in your browser!
  • No suffering from lost syntax highlighting on properties and units.
  • No high risk of eventually requiring a build step.
  • No chance of deprecations. 16 lines is infinitely maintainable.
  • No suffering from FOUC (a flash of unstyled content).
  • No special binaries, no add-ons, no plugins to install.

⚡ Workflow Tips

  • Use vanilla CSS variables for your design system.
  • Flattened 1 rule = 1 line can be small like Tailwind. See examples
  • Positional selectors may be easier using div[n1] for <div n1> (instead of div:nth-child(1))
  • Child combinator can be very useful for granular control. Example: div>button
  • Use the short @media queries for responsive design.
    • Based on Tailwind breakpoints.
    • 🟢 = Default, no breakpoint required. See the Live Example!
    • Mobile First (flows above Default)
      • 🟢 Default xs sm md lg xl xx 🏁 End
    • Desktop First (flows below Default)
      • 🏁 End xs- sm- md- lg- xl- xx- 🟢 Default

👁️ Showdown: CSS Scope Inline vs Tailwind CSS

Basic example.

<!-- CSS Scope Inline -->
<div>
    <style>
        me { background: red; }
        me div { background: green; }
        me [n1] { background: yellow; }
        me [n2] { background: blue; }
    </style>
    red
    <div>green</div>
    <div>green</div>
    <div>green</div>
    <div n1>yellow</div>
    <div n2>blue</div>
    <div>green</div>
    <div>green</div>
</div>

<!-- Tailwind -->
<div class="bg-[red]">
    red
    <div class="bg-[green]">green</div>
    <div class="bg-[green]">green</div>
    <div class="bg-[green]">green</div>
    <div class="bg-[yellow]">yellow</div>
    <div class="bg-[blue]">blue</div>
    <div class="bg-[green]">green</div>
    <div class="bg-[green]">green</div>
</div>

Variables and child elements example.

At first glance, Tailwind Example 2 looks very promising, but:

  • 🔴 Every child style requires an explicit selector.
    • Tailwinds’ shorthand advantages start to disappear.
    • Tailwind becomes larger than vanilla CSS when more child elements are added.
    • This limited example is the best case scenario for Tailwind.
  • 🔴 Not visible on github: no highlighting for properties and units becomes painful.
<!doctype html>
<html>
    <head>
        <style>
            :root {
                --color-1: hsl(0 0% 88%);
                --color-1-active: hsl(214 20% 70%);
            }
        </style>
        <script src="https://cdn.tailwindcss.com"></script>
        <script src="https://cdn.jsdelivr.net/gh/gnat/css-scope-inline@main/script.js"></script>
    </head>
    <body>
        <!-- CSS Scope Inline -->
        <div>
            <style>
               me { margin:8px 6px; }
               me div a { display:block; padding:8px 12px; margin:10px 0; background:var(--color-1); border-radius:10px; text-align:center; }
               me div a:hover { background:var(--color-1-active); color:white; }
            </style>
            <div><a href="#">Home</a></div>
            <div><a href="#">Team</a></div>
            <div><a href="#">Profile</a></div>
            <div><a href="#">Settings</a></div>
            <div><a href="#">Log Out</a></div>
        </div>

        <!-- Tailwind Example 1 -->
        <div class="mx-2 my-4">
            <div><a href="#" class="block py-2 px-3 my-2 bg-[--color-1] rounded-lg text-center hover:bg-[--color-1-active] hover:text-white">Home</a></div>
            <div><a href="#" class="block py-2 px-3 my-2 bg-[--color-1] rounded-lg text-center hover:bg-[--color-1-active] hover:text-white">Team</a></div>
            <div><a href="#" class="block py-2 px-3 my-2 bg-[--color-1] rounded-lg text-center hover:bg-[--color-1-active] hover:text-white">Profile</a></div>
            <div><a href="#" class="block py-2 px-3 my-2 bg-[--color-1] rounded-lg text-center hover:bg-[--color-1-active] hover:text-white">Settings</a></div>
            <div><a href="#" class="block py-2 px-3 my-2 bg-[--color-1] rounded-lg text-center hover:bg-[--color-1-active] hover:text-white">Log Out</a></div>
        </div>

        <!-- Tailwind Example 2 -->
        <div class="mx-2 my-4
            [&_div_a]:block [&_div_a]:py-2 [&_div_a]:px-3 [&_div_a]:my-2 [&_div_a]:bg-[--color-1] [&_div_a]:rounded-lg [&_div_a]:text-center
            [&_div_a:hover]:bg-[--color-1-active] [&_div_a:hover]:text-white">
            <div><a href="#">Home</a></div>
            <div><a href="#">Team</a></div>
            <div><a href="#">Profile</a></div>
            <div><a href="#">Settings</a></div>
            <div><a href="#">Log Out</a></div>
        </div>
    </body>
</html>

🔎 Technical FAQ

  • Why do you use querySelectorAll() and not just process the MutationObserver results directly?
    • This was indeed the original design; it will work well up until you begin recieving subtrees (ex: DOM swaps with htmx, ajax, jquery, etc.) which requires walking all subtree elements to ensure we do not miss a <style>. This unfortunately involves re-scanning thousands of repeated elements. This is why querySelectorAll() ends up the performance (and simplicity) winner.

🌘 Change Log

1.1.0

  • Started change log.
  • Fix for domain names ending in .me when used url() properties.

评论

暂无评论