Class-light CSS blades inspired by Pico.css

Table of Contents

Install

Install CSS blades

Option A. From CDN:

<link href="https://cdn.jsdelivr.net/npm/@anydigital/blades@^0.27.0-alpha/assets/blades.min.css" rel="stylesheet" />
<link href="https://cdn.jsdelivr.net/npm/@anydigital/blades@^0.27.0-alpha/assets/blades.theme.min.css" rel="stylesheet" /><!-- optional -->

Option B. Via npm:

npm install @anydigital/blades

Then import in your .css:

@import "@anydigital/blades";
@import "@anydigital/blades.theme"; /* optional */

Living example: /anydigital/build-awesome-starter/blob/main/_styles/styles.css


Nunjucks / Liquid

HTML blades

for 11ty/Build Awesome, Jekyll, etc.


Table

🥷 Responsive table without wrapper →

Horizontal expanders

Simply insert <hr> inside <th> to forcibly widen too narrow columns (especially useful in markdown):

<th>Col <hr></th>

Example table:

SSG
Description
Build Awesome Simple, flexible Static Site Generator (SSG) written in JavaScript. It is designed to be a faster, modern alternative to Jekyll, known for its "zero-config" philosophy and focus on performance.

Same table without <hr>-expander would render as:

SSG Description
Build Awesome Simple, flexible Static Site Generator (SSG) written in JavaScript. It is designed to be a faster, modern alternative to Jekyll, known for its "zero-config" philosophy and focus on performance.
How it works
table {
  th {
    hr {
      width: 12ch; /* min ~65/12 = ~5 cols */
      height: 0;
      margin: 0;
      visibility: hidden;

      &.x2 {
        width: 24ch;
      }
    }
  }
}

Borderless table

<table class="borderless"> removes all default borders:

Less Borders
More Fun

Living example: /#minimal-dependencies table


Content


How it works
a {
  /* Helper to handle icons in links */
  > i {
    display: inline-block;
    font-style: normal;
  }

  /* Helper for favicons in links */
  &[data-has-favicon] {
    display: inline-block;

    > img {
      max-height: 1.25em;
      margin-top: calc(-0.25em / 2);
      margin-inline-end: 0.375ch; /* =3/8 */

      /* for tw-typography (.prose) */
      display: inline-block;
      margin-bottom: 0;
    }
  }
}

Heading anchors

h1,
h2,
h3,
h4,
h5,
h6 {
  position: relative;

  [data-is-anchor] {
    visibility: hidden;
    position: absolute;
    top: 0;
    right: 100%;
    padding-right: 0.2ch;
    color: silver;
    text-decoration: none;
  }
  &:hover {
    [data-is-anchor] {
      visibility: visible;
    }
  }
}

List markers

ul,
ol {
  li[data-marker]::marker {
    content: attr(data-marker) " ";
  }

  &.unlist {
    padding-inline-start: 0;

    > li {
      list-style: none;
    }
  }
}

Code

Extends /picocss/pico/blob/main/scss/content/_code.scss

pre {
  padding: 1rem 1.5rem;
  padding-inline-end: 2rem;

  @media screen and (max-width: 767px) {
    border-radius: 0;
  }
}

code {
  /* Code block caption via data-attr (to display filename, etc.) */
  &[data-caption] {
    &::before {
      content: attr(data-caption);
      display: block;
      margin-bottom: 1rem;
      opacity: 50%;
      font-style: italic;
    }
  }

  &:where(pre > *) {
    padding: 0;
  }
}

/*** Extends https://github.com/PrismJS/prism/blob/master/plugins/treeview/prism-treeview.css ***/
.token.treeview-part {
  .entry-line {
    width: 2.5em !important;
    opacity: 25%;
  }
  .entry-name:last-child {
    opacity: 50%;

    &::before {
      display: none !important;
    }
  }
}

Layout

🥷 Breakout elements →

Document

Extends /picocss/pico/blob/main/scss/layout/_document.scss

Prevent horizontal overflow and scrolling, modern way:

html {
  overflow-x: clip;
}

Landmarks

Extends /picocss/pico/blob/main/scss/layout/_landmarks.scss

  1. Ensure body takes at least the full height of the viewport (using dynamic viewport height for better mobile support).
  2. Make the body a flex container with column layout, and main to automatically fill available space. This is useful for creating sticky footers and full-height layouts.
body {
  min-height: 100dvh;

  display: flex;
  flex-direction: column;
  > main {
    flex-grow: 1;
  }
}

Table of contents

[data-is-toc] {
  font-size: 87.5%;

  a {
    text-decoration: none;
  }
  > ul {
    columns: 30ch auto; /* 2 cols max for 65ch container */
  }
}

Jump to top

[data-jump-to="top"] {
  position: fixed;
  bottom: 0;
  right: 0;
  padding-top: 50vh;
  opacity: 25%;

  &:hover {
    opacity: 75%;
  }
}

Utilities

Auto-columns

.columns {
  columns: 30ch auto; /* 2 cols max for 65ch container */

  /* Avoid breaking inside elements, such as nested lists */
  > * {
    break-inside: avoid;
  }
}

Auto-dark

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    .dark-auto {
      filter: invert(100%) hue-rotate(180deg);
    }
  }
}

Misc

.faded {
  opacity: 50%;
  &:hover {
    opacity: 87.5%;
  }
}

/* Extends https://tailwindcss.com/docs/filter-invert */
.invert {
  /* Fix the scrollbar color when inverted */
  ::-webkit-scrollbar {
    filter: invert(1) !important;
  }
}

Overrides for /picocss/pico/blob/main/scss/utilities/_reduce-motion.scss

@utility unreduce-animation-* {
  @media (prefers-reduced-motion: reduce) {
    &:not([aria-busy="true"]) {
      animation-duration: --value([ *]) !important;
      animation-delay: 0 !important;
      animation-iteration-count: infinite !important;
    }
  }
}