npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

html-by-css

v1.1.0

Published

Generate html by writing css

Downloads

11

Readme

html-by-css

Generate html by writing css.

Install

npm i html-by-css

Usage

import generate from 'html-by-css';

const source = `
  ul#list {
    list-style: none;
    margin: 0;
    padding: 0;

    & li.item*3 {
      padding: .5rem;

      :is(a[href="#"]) {
        content: Link;
        color: inherit;
      }
    }
  }
`;

const { html, css } = generate(source);

HTML

<ul id="list">
  <li class="item">
    <a href="#">Link</a>
  </li>
  <li class="item">
    <a href="#">Link</a>
  </li>
  <li class="item">
    <a href="#">Link</a>
  </li>
</ul>

CSS

/* legacy: false (default) */
ul#list {
  list-style: none;
  margin: 0;
  padding: 0;
  & li.item {
    padding: .5rem;
    :is(a[href="#"]) {
      color: inherit;
    }
  }
}

/* legacy: true */
ul#list {
  list-style: none;
  margin: 0;
  padding: 0;
}

ul#list li.item {
  padding: .5rem;
}

ul#list li.item :is(a[href="#"]) {
  color: inherit;
}

How it works

  • Use postcss to parse and walk through source.
  • On target nodes, process data as HTML:
    • Find content on non-pseudo elements and inject as text.
    • Find emmet syntax and duplicate elements.
    • Parse selector using css-what.
    • Transform selector to himalaya schema.
  • Process source as valid CSS:
    • Remove content on non-pseudo elements.
    • Remove emmet syntax.
    • Optionally, use postcss-nesting plugin to transform into legacy, non-nested CSS.
    • Apply additional plugins as provided.
  • Return object with { html, css }.

Features

Nesting

The nesting should be prepared using the current w3 CSS Nesting specification. The most important concept is that a nested selector must start with a symbol.

.foo {
  /* ❌ invalid */
  span {
    color: hotpink;
  }

  /* ✅ valid */
  & span {
    color: hotpink;
  }

  /* ❌ invalid */
  span & {
    color: hotpink;
  }

  /* ✅ valid */
  :is(span) & {
    color: hotpink;
  }
}	

If you wish to collapse the nesting for the CSS output, set legacy: true in the options. This uses postcss-nesting with the default options.

const { html, css } = generate(source, { legacy: true });

If you want to set your own options, provide your own version of the postcss-nesting plugin and configure.

import nesting from 'postcss-nesting';
import generate from 'html-by-css';

const postcssPlugins = [nesting({
  noIsPseudoSelector: true
})];
const { html, css } = generate(source, { plugins: postcssPlugins });

Warning

Do not use legacy: true with your own postcss-nesting configuration. The internal (legacy) usage will run first. Either do not declare or explicitly set legacy: false. This is only when using a custom postcss-nesting, all other plugins can be used with legacy: true.

PostCSS plugins

You can include additional postcss plugins. Example below helps with removing duplicate declarations.

import dedupe from 'postcss-discard-duplicates';
import generate from 'html-by-css';

const postcssPlugins = [dedupe()];
const { html, css } = generate(source, { plugins: postcssPlugins });

This is helpful if you have several similar elements with different contents.

ul#list {
  & li.item {
    & a*0 {
      color: inherit;
    }

    & a[href="/home"] {
      content: Home;
    }

    & a[href="/about"] {
      content: About;
    }

    & a[href="/contact"] {
      content: Contact
    }
  }
}

Note

The use of a*0 says write the styles found here, but don't write HTML. When you use this, the represented node and it's children will not be written as HTML.

Duplicate nodes

To create multiple elements, use emmet syntax.

ul {
  li*5 {
    /* Makes 5 <li/> elements */
  }
}

This li*5 selector is not valid CSS and is transformed during processing to li.

Text content

To add text content, use the content property on non-pseudo elements.

main {
  & h1 {
    content: Hello world!;
  }
}
<main>
  <h1>Hello world!</h1>
</main>

Note

There are no quotes around the string. Adding quotes would include the quotes in the output.

The content property is not valid on non-pseudo elements and is removed from these declarations during processing.

Testing

npm t

There's definitely some cases not covered in the tests yet.

  • [ ] content prop and nested selector (both text and children).
  • [ ] Other pseudo-selectors (:nth-child(), :checked).

Why

Your scientists were so preoccupied with whether they could, they didn't stop to think if they should.

There's a few projects out there that are HTML preprocessors (Haml, Pug) which have their own (sometimes CSS-like) syntax. I wondered if we could get closer to just writing CSS to produce HTML. With the new nesting specification and the power of postcss, it looks like we can!