Retro Windows 95 UI Framework in Pure CSS – 95CSS

Category: CSS & CSS3 , Frameworks | July 28, 2026
AuthorYoshiMannaert
Last UpdateJuly 28, 2026
LicenseMIT
Views27 views
Retro Windows 95 UI Framework in Pure CSS – 95CSS

95CSS is a pure CSS framework that recreates Windows 95 UI elements with native HTML controls and reusable utility classes.

It styles buttons, form fields, tabs, dialogs, progress bars, navigation bars, and grid layouts through a single stylesheet.

Features:

  • Pure CSS component styling with no bundled JavaScript.
  • Windows 95-inspired buttons, dialogs, forms, tabs, and navigation.
  • Native text, number, checkbox, radio, select, range, and color inputs.
  • Highlighted, focused, active, and disabled control states.
  • Four dialog size variants for cards, windows, and popup layouts.
  • Twelve-column grid with configurable column spans and gaps.
  • Spacing, width, margin, padding, and gap helper classes.
  • CSS custom properties for colors, spacing, borders, and shadows.
  • Included Windows 95-style web font.

How To Use It:

Installation

Load the core stylesheet inside the document <head>.

<link
  rel="stylesheet"
  href="/path/to/95css.min.css"
/>

You can also install the package with NPM:

npm install 95css

And then import the compiled stylesheet:

@import "95css/css/95css.min.css";

Basic Usage

95CSS styles native elements and a small set of layout classes. The following markup creates an open Windows 95-style dialog with a form and action buttons.

<dialog open class="is-lg">
  <div class="dialog-header">
    <h2>Network Connection</h2>
  </div>
  <div class="dialog-body">
    <div class="field-group">
      <div class="input-group">
        <label for="server-name">Server name</label>
        <input
          id="server-name"
          type="text"
          value="files.example.net"
        />
      </div>
      <div class="input-group">
        <label for="connection-type">Connection type</label>
        <select id="connection-type">
          <option>Local network</option>
          <option>Dial-up connection</option>
          <option>Direct cable</option>
        </select>
      </div>
      <label class="checkbox">
        <input type="checkbox" checked />
        Reconnect at startup
      </label>
      <div class="toolbar">
        <button class="is-highlighted">Connect</button>
        <button>Cancel</button>
      </div>
    </div>
  </div>
</dialog>

The open attribute displays the native dialog immediately. Remove it when JavaScript will control the dialog through showModal() and close().

Button States

Regular <button> elements receive the default raised Windows 95 border. Links can use the .btn class when they need the same appearance.

<div class="toolbar">
  <button>Default</button>
  <button class="is-highlighted">Primary action</button>
  <button class="is-focused">Keyboard focus</button>
  <button class="is-active">Pressed state</button>
  <button disabled>Unavailable</button>
  <a class="btn" href="/downloads">Download</a>
</div>

Interactive Tabs

95CSS supplies the tab appearance but does not switch panels. Your app code must update the active class, ARIA state, keyboard focus, and panel visibility.

<div class="tabs" role="tablist" aria-label="System settings">
  <button
    id="general-tab"
    class="tab is-active"
    type="button"
    role="tab"
    aria-selected="true"
    aria-controls="general-panel"
    tabindex="0"
  >
    General
  </button>
  <button
    id="display-tab"
    class="tab"
    type="button"
    role="tab"
    aria-selected="false"
    aria-controls="display-panel"
    tabindex="-1"
  >
    Display
  </button>
</div>
<section
  id="general-panel"
  class="dialog-body"
  role="tabpanel"
  aria-labelledby="general-tab"
>
  <p>Configure startup and system preferences.</p>
</section>
<section
  id="display-panel"
  class="dialog-body"
  role="tabpanel"
  aria-labelledby="display-tab"
  hidden
>
  <p>Configure colors and screen settings.</p>
</section>
<script>
  const tabs = document.querySelectorAll('[role="tab"]');
  const panels = document.querySelectorAll('[role="tabpanel"]');
  tabs.forEach((tab) => {
    tab.addEventListener('click', () => {
      tabs.forEach((item) => {
        const selected = item === tab;
        item.classList.toggle('is-active', selected);
        item.setAttribute('aria-selected', String(selected));
        item.tabIndex = selected ? 0 : -1;
      });
      panels.forEach((panel) => {
        panel.hidden = panel.id !== tab.getAttribute('aria-controls');
      });
    });
  });
</script>

Dialog Sizes

The framework includes four dialog size modifiers. The default dialog uses the medium width.

<dialog open class="is-sm">
  <div class="dialog-header">
    <h2>Small Window</h2>
  </div>
  <div class="dialog-body">
    <p>Compact status or confirmation content.</p>
  </div>
</dialog>
<dialog open class="is-md">
  <div class="dialog-header">
    <h2>Medium Window</h2>
  </div>
  <div class="dialog-body">
    <p>Standard form or message content.</p>
  </div>
</dialog>
<dialog open class="is-lg">
  <div class="dialog-header">
    <h2>Large Window</h2>
  </div>
  <div class="dialog-body">
    <p>Settings, account details, or longer forms.</p>
  </div>
</dialog>
<dialog open class="is-xl">
  <div class="dialog-header">
    <h2>Extra Large Window</h2>
  </div>
  <div class="dialog-body">
    <p>Dashboards, tables, or multi-column content.</p>
  </div>
</dialog>

Form Layouts

Place related fields inside .field-group. Each .input-group arranges its label above the control by default.

<div class="field-group">
  <div class="input-group">
    <label for="display-name">Display name</label>
    <input id="display-name" type="text" />
  </div>
  <div class="input-group">
    <label for="theme-color">Desktop color</label>
    <input id="theme-color" type="color" value="#008080" />
  </div>
  <div class="input-group">
    <label for="volume">System volume</label>
    <input id="volume" type="range" min="0" max="100" value="65" />
  </div>
  <div class="input-group">
    <label for="storage-progress">Disk usage</label>
    <progress id="storage-progress" value="68" max="100">68%</progress>
  </div>
</div>

Add .is-horizontal to an input group when the label and control should share one row.

<div class="input-group is-horizontal">
  <label for="user-id">User ID</label>
  <input id="user-id" type="text" value="GUEST-01" />
</div>

Twelve-Column Grid

The .grid container creates twelve equal columns. Combine .col with a column-span modifier for each child.

<div class="grid grid-gap-4">
  <section class="dialog col col-span-8">
    <div class="dialog-header">
      <h2>Main Workspace</h2>
    </div>
    <div class="dialog-body">
      <p>The primary content spans eight columns.</p>
    </div>
  </section>
  <aside class="dialog col col-span-4">
    <div class="dialog-header">
      <h2>Tools</h2>
    </div>
    <div class="dialog-body">
      <p>The sidebar spans four columns.</p>
    </div>
  </aside>
</div>

Available span helpers run from .col-span-1 through .col-span-12. Column start helpers follow the .col-start-1 through .col-start-12 pattern.

The framework does not add responsive breakpoints to these classes. Add your own media query when columns should stack on narrow screens.

@media (max-width: 720px) {
  .grid {
    grid-template-columns: 1fr;
  }
  .grid > .col {
    grid-column: 1;
  }
}

Styling And Customization

Customize the palette, spacing scale, and shadow recipes in CSS custom properties:

  • --color-white: Highlight color used in raised borders.
  • --color-black: Text and dark border color.
  • --color-gray-100: Light gray surface and shadow color.
  • --color-gray-200: Main component background.
  • --color-gray-300: Disabled text and dark bevel color.
  • --color-blue: Dialog title and selected-state color.
  • --color-teal: Default desktop background.
  • --color-yellow: Available accent color.
  • --color-red: Available warning or accent color.
  • --spacing-base: Base value used to calculate the spacing scale.

Helper Classes

Adjust your layout with the following CSS utilities:

  • .m-1 through .m-10: Apply margin on all sides.
  • .m-t-*, .m-r-*, .m-b-*, .m-l-*: Apply margin to one side.
  • .m-x-* and .m-y-*: Apply horizontal or vertical margin.
  • .p-1 through .p-10: Apply padding on all sides.
  • .p-t-*, .p-r-*, .p-b-*, .p-l-*: Apply padding to one side.
  • .p-x-* and .p-y-*: Apply horizontal or vertical padding.
  • .gap-1 through .gap-10: Set the flex or grid gap.
  • .grid-gap-1 through .grid-gap-10: Set the framework grid gap.
  • .w-full: Set the element width to 100%.
  • .w-1/2 through .w-1/6: Apply common fractional widths.

Alternatives:

You Might Be Interested In:


Leave a Reply