Introduction
There are already plenty of CSS frameworks, with varying levels of complexity. This one attempts to be a progressive enhancement on plain HTML5, with CSS based improvements with occasional JS components where necessary. It strays from the extreme simplicity of the flat layered "paper" trend in favor of more obvious classic visual cues enhanced for modern browsers.
All styling on elements, attributes or classes not prefixed with vp- only take effect inside .vp blocks to help reduce collisions with other frameworks. You can further disable part or all of a .vp block with the exclusion class .xvp.
Compiled CSS files are located in dist/. You may use vpweb.css to get the entire framework at once, or just some of the individual files described below. Be sure to import core.css first in order to avoid priority side-effects.
Efficient
The entire framework, all components included, is smaller than a typical company logo image:
| Size | Gzipped | Brotli | |
|---|---|---|---|
| vpweb.css | 22.4KB | 5.1KB | 4.5KB |
| vpweb.js | 10.2KB | 4.3KB | 3.8KB |
Browser Support
Currently compatible with Baseline's "Widely available" browser versions (30 months) which includes long term support versions as of 2025-01-01. Some features from "Newly available" may be used, but only when they degrade gracefully (i.e. content-visibility). This means we're refraining from using cutting-edge features like :has() and round().
- Chrome/Edge/Opera
- 103 (2022-04-26)
- Safari
- 16.4 (2023-03-27)
- Firefox
- 101, ESR 91.10 (2022-05-31)
Build Process
On the CSS side, you may reference the pre-built vpweb.css alone or @import 'vpweb.css'; from your CSS sources. You might even want to import only the bits you want such as core.css and grid.css to use our grid.
If you use @layers, just set our pre-defined vp layer where you want in your stack. All our internal layers are namespaced within this single global layer.
Core core.css
Minimal, non-opinionated reset to help normalize output across browsers.
Colors
CSS variables for the followig colors are available in two variants: saturated RGB triplets as --vp-X and 5% white-dimmed hex as --vp-X-05 (e.g. --vp-red-05). Helper classes also set these colors for the current text and border if any. Optional .bg class sets a background color in the same hue at 5% opacity. Optional .boxed class sets a thin border at 40% opacity.
In some uses like notes, semantic terms are used instead of direct color names, like error implying red, etc.
.cyan .blue .violet .red .orange .yellow .green .dim
Typography
.mono- System and user-preferred monospace font families (automatically applied to
code,kbd,pre,samp) .sans- System and user-preferred sans-serif font families (automatically applied to buttons and inputs)
.serif- System and user-preferred serif font families
Density
Three classes are recognized by various modules (i.e. grid) as indicative of spacing to use between items. The closest parent or self has priority.
.tight.tight.tight.spaced.spaced.spaced.relaxed.relaxed.relaxedResponsive
Certain classes restrict which devices can see an element, by viewport width or display type. Note that the names "mobile", "tablet" and "desktop" are used as nicknames for the three responsive size ranges, not as true device identification. CSS media queries use a "device pixel ratio" to define their own meaning for "px", so those are not actual pixels but industry standard values.
- Mobile:
- Less than 768px,
.mobile-only,.tablet-down - Tablet:
- From 768px to less than 992px,
.tablet-only,.tablet-up,.tablet-down - Desktop:
- From 992px up,
.tablet-up,.desktop-only - Large Desktop:
- From 1200px up,
.largedesktop-onlymay occasionally be useful. - Pointer:
- With no fine pointer,
.mouse-onlyis hidden. When no pointer can hover,.hover-onlyis hidden. - Print:
- On a screen,
.print-onlyis hidden, while on any other device,.screen-onlyis hidden.
Helper classes
.gone- Sets
display: none .sticky- Sets
position: sticky .center- Sets
text-align: center .right- Sets
text-align: right
Layouts layouts.css
Wrap .vp-wrap
Adds a max-width and side margins dictated by density (self or immediate parent).
Grids [vp-grid="N"]
Grids are defined by adding attribute vp-grid="x" to an element, where x is one of: 5, 8, 10 or 12. Cells in grids are immediate child elements, optionally with attribute vp-cols="x" where x is a number between 2 and 12 (1 being implicit). Rows wrap, so you only need to use multiple grid blocks for splitting incomplete lines or changing bases.
An <img> directly inside a [vp-grid] or wrapped in just an a automatically gets full width.
Responsive: On tablets, bases are divided by 1.5 (i.e. a 12-wide becomes 8-wide) and on mobile, by 3 (i.e. 12-wide becomes 4-wide) This elegantly accounts for the reduced widths, making column counts function as minimum absolute widths rather than as a percentage of the viewport.
Example: grid of 12ths vp-grid="12"
Stacks & Shelves .vp-stack, .vp-shelf
Applicable to any container block, including body. Sensitive to density.
.vp-stack- 2 or 3 immediate children are stacked vertically. The second child expands as necessary to make sure that the optional third child is always no higher than the bottom of the viewport.
.vp-shelf-
Same behavior, but horizontal from left to right. Set width using
min-widthto help with responsiveness. Two-column shelves have a Fibonacci-derived default ratio of (38.2%,61.8%), three-column shelves have (23.6%,52.8%,23.6%). Responsive: On tablets down, the third child goes below the other two and on mobile all three children become vertically stacked.
Examples:
main
main
...
...
...
...
...
main
...
...
...
...
...
Options
[vp-grid].stacking- Makes grid cells immediately go full-width for "tablet" and "mobile" sizes.
[vp-grid].growing- On desktop, fills incomplete rows by expanding each element in proportion to each other. On tablet-down, this is always the case.
[vp-grid].justified- On desktop, adds white space between elements in incomplete rows, to left and right align. On tablet-down, elements grow instead.
[vp-grid].centered- On desktop, adds white space left, right and between elements evenly in incomplete rows. On tablet-down, elements grow instead.
Forms forms.css
Note also that margins between some elements is affected by the form's density.
Fields label.vp-field > input|select|textarea
In addition to text, typical input types compatible with this class are: email, number, password, tel, text, url and possibly search. Fields expand to fill their container's width, which is handy in grids. We implement infield top aligned labels.
With JS enabled, an input without a forced width may grow/shrink with its content with the .vp-growing class.
For textarea, height changes instead.
Add .has-warning to a .vp-field or .invalid to a field or input/select/textarea for a permanent invalid indicator. (Though if JS is enabled, .invalid will be removed upon an edit which passes the browser's validity check.)
or plain:
Checkboxes label input[type=checkbox]
Radio selections label input[type=radio]
General rules of thumb: if there are between 3 and 5-7 options, a radio is probably the best input. Stack vertically if possible; space generously if horizontal. For 2 options, a checkbox is clearer. For more than 5-7 options, a select drop-down keeps the form cleaner. Remember to always check a default option when presenting a form's initial state.
Buttons button, .vp-button
Note that button-looking anchors among actual buttons need tabindex="0" to be keyboard accessible.
Button and field groups .vp-group > :is(button, .vp-button, input, select, textarea, .vp-field)
Optional .vp-group.growing makes any input grow proportionally to fill the container space.
Note that hidden members on either edge will make the corners on that edge sharp instead of rounded, so prefer disabling when possible.
When including a .vp-field which is split (i.e. with prefix/postfix elements), add class .bare if it is unlabeled, to keep it thin like regular inputs/selects.
Theming
Normal buttons automatically adapt to any background/foreground colors and font sizes set on their elements, as well as their parent background color. Icon buttons adapt to font size and their parent background color.
Responsive
For touch devices, all buttons have a minimum width and height of 16mm regardless of font size.
Tables tables.css
Tables respond to density with padding and font size.
| First | Second | Third | Fourth |
|---|---|---|---|
| First | 2.22% | X | Fourth is longer as a test |
| First | 2.22% | X | Fourth is longer as a test |
| First | 2.22% | X | Fourth is longer as a test |
| First | 2.22% | X | Fourth is longer as a test |
| First | 2.22% | X | Fourth is longer as a test |
| Second | Third | Fourth | |
|---|---|---|---|
| First | 2.22% | X | Fourth is longer as a test |
| First | 2.22% | X | Fourth is longer as a test |
| First | 2.22% | X | Fourth is longer as a test |
| First | 2.22% | X | Fourth is longer as a test |
| First | 2.22% | X | Fourth is longer as a test |
Options
- table.vp-2d
-
First column is a heading for each row, so hide first column of
theadandtfoot. - table.horizontal
- Horizontal borders only.
- table.gridded
- Horizontal and vertical borders.
- table.striped
-
Highlights every even row in the
tbody. - table.stacking
- Cells grow to full width on mobile (portrait) screens. No border between cells, just between rows.
- table.stick-vertical
-
theadandtfoot(allth) remain in viewport while the table is. - table.stick-horizontal
-
Left-most column (a
th) is considered a header and remains in viewport while the table is. - [vp-center="..."]
-
Center text in all whitespace-delimited column numbers (1..9) of direct children of this element.
Apply to
tbodytypically, or totableif you don't use it. - [vp-right="..."]
-
Right-align text in all whitespace-delimited column numbers (1..9) of direct children of this element.
Apply to
tbodytypically, or totableif you don't use it. - [vp-mono="..."]
-
Use monospace font in all whitespace-delimited column numbers (1..9) of direct children of this element.
Apply to
tbodytypically, or totableif you don't use it.
Notes notes.css
Element vp-note
class="error".class="warning".class="ok".class="boxed error".class="boxed bg warning".class="boxed bg ok".class="boxed" and vp-point="top-left".Options
- .boxed
- Not only adds a thin border, but also expands padding.
- .bg
- Adds a background at 5% opacity.
- [vp-point="..."]
- Adds a pointer triangle to any block, but designed to work with
vp-note. The value is a string composed of two words separated by a hyphen, e.g.top-left. The first word specifies which border it applies to, one of:top,bottom,leftorright. The second word specifies where on the border, either one ofleft,center,rightortop,middle,bottom.
Tabs tabs.css tabs.js
Accordions
A series of details elements, each with a summary child before the rest of their content, can perform as an accordion if each details is given an identical name="..." attribute.
This framework doesn't yet include styles for this basic HTML5 construct, but it is planned for the future.
Tabs vp-tabs
A block which contains two children: a list of tab handles (inline-block), and a list of tab panels (block). A little bit of JS adds the necessary ARIA attributes and behavior, such as arrows, home/end and proper tab support.
This is tab 1.
This is tab 2.
It is taller than the others to demonstrate how height is dynamic.
This is tab 3.
This is tab 1.
This is tab 2.
It is taller than the others to demonstrate how height is dynamic.
This is tab 3.
Options
vp-tabs.boxed-
Adds a box (similar to a
fieldset) around the panel area.
Transitions transitions.css
To avoid "flashing", transitions only apply inside a .vp-loaded, which is applied automatically when the document is fully loaded by our main JS bundle.
Generic
.loaded, .loaded *-
Subtle fade for
background-colorandpadding. .go-hidden,.go-visible-
Fade in/out of
opacity. Only useful in scripts because they are mutually exclusive. - TODO
- Slide in/out from one of the 4 sides