Blades CSS

Framework-agnostic, class-light CSS blade kit.

Use with Pico, Simple, Tailwind, or any other CSS reset/framework.


Table of Contents

Install

Via CDN
<link rel="stylesheet" href="
  https://cdn.jsdelivr.net/npm/@anyblades/blades@0/assets/blades.min.css
">
Via npm
npm install @anyblades/blades

Then in your .css:

@import "@anyblades/blades";

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

Preconfigured
Theme (optional)

blades.css includes default minimal styling; use blades.core.css to opt-out.

How it works
@import "./float-label.theme";

html {
  /* Prevent horizontal overflow and scrolling, modern way. */
  overflow-x: clip;

  /* Enable font smoothing */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

body {
  /* Ensure `body` takes at least the full height of the viewport (using dynamic viewport height for better mobile support). */
  min-height: 100dvh;

  /* 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. */
  display: flex;
  flex-direction: column;
  > main {
    flex-grow: 1;
  }

  /* Evaluates the last ~4 lines of text blocks to prevent a single word from sitting on the final line. */
  text-wrap: pretty;

  /* Enable global hyphenation */
  hyphens: auto;
  /* ... except for links and tables which are better (safer) without hyphenation */
  a,
  table {
    hyphens: none;
  }
}

a {
  &:not([href^="#"]) {
    text-decoration-thickness: 1px;

    &:hover {
      text-decoration-thickness: 2px;
    }
  }
}

h1 {
  font-size: 2.5em; /* for pico.css & tw-typography */
  margin-bottom: 1rem; /* for tw-typography */
}

hr {
  margin-block: 2em; /* for pico.css & tw-typography */
}

ul {
  ul {
    font-size: 87.5%;
  }
}

pre {
  small {
    opacity: 75%;
    font-weight: lighter;
  }
}

table {
  th {
    vertical-align: bottom;
    font-weight: bold;
  }
  td {
    vertical-align: top;
  }
  pre {
    margin-bottom: 0.25rem;
  }
}

[data-jump-to="top"] {
  opacity: 25%;
  &:hover {
    opacity: 75%;
  }

  > i {
    display: inline-block;
    padding: 0.25rem 0.375rem;
    margin: 0.5rem;
    font-size: 0.75rem;
    color: black;
    border-color: black;
  }
}

.breakout,
.breakout-all {
  > img,
  > figure {
    margin-bottom: 1rem;
  }
}

.faded {
  a {
    text-decoration-style: dotted;
  }
}

Layout

Breakout layout

The .breakout layout allows images, tables, and other figures to automatically extend or bleed beyond their parent container’s width.

View more

Auto-columns

.columns automatically creates columns with at least 30 characters each:

1

2

3

4

5

6

The smaller the font size, the more columns will be created:

1

2

3

4

5

6

7

8

9

Useful for tables of contents and long lists.

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

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

Jump to top

data-jump-to="top" fixes element to the corner and adds extra top padding to make it easy to click:

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

Content

Use Blades <i>-helper to wrap emojis, favicons, or simply drop Font Awesome icons inside links. It automatically handles sizing and alignment while preventing underline on icons.

View more

Heading anchors

Links with href="#..." inside headings are automatically displayed as anchors:

Heading with anchor #

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

  a[href^="#"] {
    position: absolute;
    right: 100%;
    top: 50%;
    transform: translateY(-50%);
    padding-right: 0.2ch;
    color: silver;
    text-decoration: none;
    visibility: hidden;
  }
  @media /* to avoid double-tap on touch devices */ (hover: hover) {
    &:hover {
      a[href^="#"] {
        visibility: visible;
      }
    }
  }
}

PRO example of automatic anchors for 11ty+markdown-it-anchor: /anyblades/eleventy-blades/blob/main/src/eleventy.config.js

List markers

Customize markers using inline style="--list-marker:..." on <ul>/<ol> or even individual <li>:

  • you
  • can
  • make
  • really
  • cool markers
  • with
  • Blades
How it works
ul,
ol {
  &[style*="--list-marker:"] {
    list-style-type: var(--list-marker);

    > li {
      list-style-type: inherit;
    }
  }
  li[style*="--list-marker:"] {
    list-style-type: var(--list-marker);
  }
  li[data-marker]::marker {
    content: attr(data-marker) " "; /* ⚠️ Chrome and Firefox only */
  }
}

Unlist

.unlist removes list styling:

  • One:
    1
  • Two:
    2
  • Three:
    3

.unlist-all also removes styling from all nested lists.

How it works
ul,
ol {
  &.unlist,
  &.unlist-all,
  .unlist-all & {
    padding-inline-start: 0;

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

Code

The <pre><code> blocks are Prism-compatible and support captions via data-caption="..." attribute:

./assets/
├── blades.core.css     # reusable class-light utilities, unthemed
├── blades.theme.css    # minimal opinionated theme
└── blades.css          # above two together
How it works
pre {
  padding: 1rem 1.5rem;
  padding-inline-end: 2rem;

  @media (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;
    }
  }
}

Table

Responsive table without wrapping container

.responsive makes a table full-bleed and scroll on mobile, without a need for a redundant wrapper (finally). Tables inside https://blades.ninja/css/breakout/ are responsive by default.

View more

Column expanders

Place <hr> element inside <th> column to expand it horizontally:

Column with <hr>
Same column without <hr> ...
(012) 345-6789 (012) 345-6789

Living examples of big tables with <hr>-expanders:

How it works
th {
  hr {
    width: 12ch; /* min ~65/12 = ~5 cols */
    height: 0;
    margin: 0;
    visibility: hidden;

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

Borderless table

.borderless removes all default borders:

Less borders
More fun

Living example: /#minimal-dependencies table


Forms

Float label CSS

Bulletproof classless CSS-only implementation of Float Label pattern with automatic fallback for ANY non-supporting browser.

View more


Utilities

Auto-dark

.dark-auto automatically creates a simple dark version of any element:

Look how cool 🔥🕷️🐦‍⬛🐄🦓 can look in the dark!

How it works
/* Per https://picocss.com/docs/css-variables#css-variables-for-color-schemes */
:root {
  --blades-dark-filter: invert(100%) hue-rotate(180deg);
}
.dark-auto {
  /* Dark color scheme (Auto) */
  @media (prefers-color-scheme: dark) {
    filter: var(--blades-dark-filter);
  }
  /* Dark color scheme (Forced) */
  &[data-theme="dark"],
  &:where([data-theme="dark"] *) {
    filter: var(--blades-dark-filter);
  }
}

Faded

.faded reduces the opacity of an element:

Hover to unfade me!
How it works
.faded {
  opacity: 50%;

  &:hover {
    opacity: 87.5%;
  }
}

More

Pico+Blades CSS ✨🥷

Pico CSS

Minimal CSS Framework for Semantic HTML

A minimalist and lightweight starter kit that prioritizes semantic syntax, making every HTML element responsive and elegant by default.

Write HTML, Add Pico CSS, and Voilà!

View more

Blades HTML

Generic Nunjucks/Liquid templates for 11ty/Build Awesome, Jekyll, Shopify, etc.

View more

Blades for Jekyll

View more


See also: