Forms
Contents:
Missing.css aims to style HTML nicely without authors needing to concern themselves over anything other than using HTML tags with correct meanings, but this is not always feasible. Forms are a particularly complex part of HTML, with multiple ways to mark up the same semantics. For instance, you can label an element in multiple ways:
<form>
<label>Name <input></label>
<!-- or... -->
<label for=adr>Address</label> <input id=adr>
</form>
Because of this, it's not really possible to write a stylesheet that will work with any HTML form.
Missing.css will work best on forms that follow these markup conventions:
§ Inputs and labels
Inputs inside labels will be display:inline
.
Inputs outside labels will be display:block
.
Input placeholders are styled with text-align:end
to better distinguish them from actual input.
<form class="flex-row">
<div>
<label for=category>Category:</label>
<select id=category placeholder="Select a category...">
<option>Blues</option>
<!-- ... -->
</select>
</div>
<div>
<label for=search>Search:</label>
<input id=search type=search placeholder="Search...">
</div>
<div>
<label for=text>Text:</label>
<input id=text type=text placeholder="Type...">
</div>
</div>
§ Buttons
Wrap a <button>
in a <strong>
tag to get a primary button.
Buttons support the aria-pressed
and aria-expanded
attributes.
Buttons, .<button>
masquerades, and <input type=file>
all support colorways as well.
<script>
const toggle = el => (el.ariaPressed = (el.ariaPressed !== 'true'))
</script>
<section tabindex=0 class="overflow:auto">
<table id=button-table class="table">
<caption>Button demonstration</caption>
<thead>
<tr><th><th><th><code>.info</code><th><code>.ok</code><th><code>.warn</code><th><code>.bad</code>
<tbody>
<tr><th scope=row><code><button></code>
<td><button>Plain</button>
<td><button class="ok">Open</button>
<!-- ... -->
<tr><th scope=row class="padding-inline-start"><code>:disabled</code>
<td><button disabled>Plain</button>
<td><button disabled class="ok">Open</button>
<!-- ... -->
<tr><th scope=row class="padding-inline-start"><code>[aria-pressed=true]</code>
<td><button aria-pressed=true onclick="toggle(this)">Plain</button>
<td><button aria-pressed=true class="ok" onclick="toggle(this)">Open</button>
<!-- ... -->
<tr><th scope=row><code><strong><button></code>
<td><strong><button>Plain</button></strong>
<td><strong><button class="ok">Open</button></strong>
<!-- ... -->
<tr><th scope=row class="padding-inline-start"><code>:disabled</code>
<td><strong><button disabled>Plain</button></strong>
<td><strong><button disabled class="ok">Open</button></strong>
<!-- ... -->
<tr><th scope=row class="padding-inline-start"><code>[aria-pressed=true]</code>
<td><strong><button aria-pressed=true onclick="toggle(this)">Plain</button></strong>
<td><strong><button aria-pressed=true class="ok" onclick="toggle(this)">Open</button></strong>
<!-- ... -->
<tr><th scope=row><code><a class="<button>"></code>
<td><a href=#button-table class="<button>">Plain</button>
<td><a href=#button-table class="ok <button>">Open</button>
<!-- ... -->
</table>
</section>
.info | .ok | .warn | .bad
| ||
---|---|---|---|---|---|
<button>
| |||||
:disabled
| |||||
[aria-pressed=true]
| |||||
<strong><button>
| |||||
:disabled
| |||||
[aria-pressed=true]
| |||||
<a class="<button>">
| Plain | Info | Open | Reset | Close |
§ Tabular forms
You can use the .table
and .rows
classes to create a form with inputs lined up like cells of a table.
<form class="table rows">
<p><label for=inp>Label</label> <input id=inp></p>
...
§ Labeling radio buttons
The accepted way to label a group of radio buttons is to use <fieldset>
and <legend>
:
<fieldset>
<legend>Color</legend>
<ul>
<li><label><input type=radio name=color value="ff0000">Red</label>
<li><label><input type=radio name=color value="00ff00">Green</label>
<li><label><input type=radio name=color value="0000ff">Blue</label>
</ul>
</fieldset>
This works in missing.css, but these two elements are [notorious] for being hard to style.
You can use the following pattern instead, which will work with tabular forms.
Notice that the wrapper has role=radiogroup
and its aria-labelledby
value refers to the id
of the label for the whole radiogroup.
<div role=radiogroup aria-labelledby=color-lbl>
<span id=color-lbl>Color</span>
<div>
<div><label><input type=radio name=color value="ff0000"> Red</label></div>
<div><label><input type=radio name=color value="00ff00"> Green</label></div>
<div><label><input type=radio name=color value="0000ff"> Blue</label></div>
</div>
</div>
§ Select
Missing.css will attempt to style <select>
elements consistently across browsers.
Colorway support is limited until browser support for custom selects improves.
<form class="flex-switch">
<div>
<label for=none>None:</label>
<select id=none>
<option>One</option>
<option>Two</option>
<option>Three</option>
</select>
</div>
<!-- ... -->
<div>
<label for=bad>Bad:</label>
<select id=bad class="bad">
<option>One</option>
<option>Two</option>
<option>Three</option>
</select>
</div>
</form>
<span class="aestheticbreak"></span>
<form class="flex-switch">
<!-- ... -->
<label for=info>Info:
<select id=info class="info color bg">
<option>One</option>
<option>Two</option>
<option>Three</option>
</select>
<-- ... -->
</form>
§ Progress bar
Create a progress bar using the <progress>
element.
This element should be used to represent how much of a specific, ongoing process has been completed.
Be sure to add a <label>
for accessibility (in conjunction with .vh
or <v-h>
if you like).
The element can be put in an indeterminate state by not including the value
attribute.
Indeterminate <progress>
elements will show a pending animation if the user does not have @prefers-reduced-motion
set.
The element can be styled by setting --border-width
, --border-style
, and --border-radius
variables directly on the <progress>
element.
When not explicitly set, the element inherits from --interactive-border-width
, --interactive-border-style
, and --tab-border-radius
.
For full-width progress bars, use the .width:100%
utility class.
Colorways are supported.
<div class="flex-column">
<label for=p1 class="vh">Upload progress...</label>
<progress id=p1 value=0.5 class="width:100%"></progress>
<label for=p2>LCARS Scan...</label>
<progress id=p2 class="ok width:100%" value=0.25 style="height: 1.5em; --border-width: 6px; --border-style: double; --border-radius: 0 .5em"></progress>
<label for=p3>Virus progress...</label>
<progress id=p3 class="warn width:100%" value=0.75 style="--border-width: 3px; --border-style: inset; --border-radius: 0 .5rem .5rem .5rem"></progress>
<label for=p4>Indeterminate Cylon</label>
<progress id=p4 class="bad" style="width: 3em;">Indeterminate Cylon</progress>
</div>
§ Meter
Use the <meter>
element to create a meter guage.
This element is used to indicate a measurement within a known range and is semantically differen from the <progress>
element.
Similar to the <progress>
element, you can style a <meter>
by setting --border-width
, --border-style
, and --border-radius
directly on the element.
The <meter>
element derives its colors from the .ok
, .warn
, and .bad
colorways.
Warning: Due to cross-browser implementation differences, colorways are only fully supported in browsers that pass the @supports (selector(:-moz-meter-optimum))
check.
The color of the meter bar is correctly set in all browsers according to the values of --ok-fg
, --warn-fg
, and --bad-fg
.
However, only browsers passing the @supports
rule will also have the appropriate colorway background and border colors.
A suitable fallback choice has been made for these colors (--plain-bg
for the background and --interactive-bg
for the border) until browser support improves.
<strong>Disk usage (optimum is a medium amount of usage)</strong>
<label for=disk1>60GB Used:</label>
<meter id=disk1 min=0 max=100 value=60 low=30 high=70 optimum=50>60GB of 100GB</meter>
<strong>Battery level (optimum is full)</strong>
<label for=battery1>85% Charged:</label>
<meter id=battery1 min=0 max=100 value=85 low=20 high=70 optimum=100>85% charged</meter>
<strong>Temperature (optimum is low)</strong>
<label for=temp1>15°C:</label>
<meter id=temp1 min=0 max=50 value=15 low=20 high=30 optimum=0>15°C</meter>
Disk usage (optimum is a medium amount of usage)
Battery level (optimum is full)
Temperature (optimum is low)
<strong>Disk usage (getting full)</strong>
<label for=disk2>80GB Used:</label>
<meter id=disk2 min=0 max=100 value=80 low=30 high=70 optimum=50>80GB of 100GB</meter>
<strong>Battery level (getting low)</strong>
<label for=battery2>25% Charged:</label>
<meter id=battery2 min=0 max=100 value=25 low=20 high=70 optimum=100>15% charged</meter>
<strong>Temperature (overheating)</strong>
<label for=temp2>40°C:</label>
<meter id=temp2 min=0 max=50 value=40 low=10 high=30 optimum=0>40°C</meter>
<strong>Exam score (failing)</strong>
<label for=exam1>20% Score:</label>
<meter id=exam1 min=0 max=100 value=20 low=40 high=80 optimum=100>20% score</meter>
Disk usage (getting full)
Battery level (getting low)
Temperature (overheating)
Exam score (failing)