Material design-like form animations for Semantic UI
We decided not to use Material Design (#reasons) while re-developing our core application suite, although i really miss MD’s micro-interactions that happen in forms. Semantic UI, while it’s feature rich and easily pluggable, lacks these.
So let’s recreate them within @SemanticUI. We need to consider Semantic UIs structure, specifically, the field
wrapper, and, to make this pure css, we need to leverage html5’s :valid
. But every field is initially valid you say? That’s the rub, we have to trigger invalid on an empty field by making them required
.
Input
<form class="ui form">
<div class="field">
<input type="text" required>
<label>Email</label>
</div>
<div class="field">
<input type="password" required>
<label>Password</label>
</div>
</form>
.ui.form {
// Starting with .field, let's set the position of our wrapper
.field {
position: relative;
width: 100%;
&:not(.checkbox) {
margin-top: 1rem;
margin-bottom: 1.7rem;
}
// Now to position our `label` and style it more as the
// native `placeholder`
label {
color: lightgrey;
position: absolute;
left: .7rem;
top: .7rem;
transition: .2s ease-in;
}
// Next, `input`, so it's barely visible on any background
// excluding checkbox and we'll add textarea
input:not([type=checkbox]),
textarea {
background: transparent;
border: none;
border-bottom: 2px solid lightgrey;
border-radius: 0;
padding: .7rem;
transition: .2s ease-in;
&:focus ~ label,
&:valid ~ label {
color: grey;
font-size: 80%;
top: -1rem;
left: 0;
}
&:focus {
border-bottom: 2px solid dodgerblue;
outline: none;
}
}
}
}
And since we added textarea
…
Select
<form class="ui form">
<div class="field select">
<select required>
<option value=""></option>
<option value="">This is a selected option</option>
</select>
<label>Select</label>
</div>
</form>
.ui.form {
.field {
position: relative;
width: 100%;
&:not(.checkbox) {
margin-top: 1rem;
margin-bottom: 1.7rem;
}
label {
color: lightgrey;
position: absolute;
left: .7rem;
top: .7rem;
transition: .2s ease-in;
}
// Now we're adding a .select class to .field
&.select {
display: flex;
&:after {
align-self: center;
color: lightgrey;
content: "\f107";
// Semantic UI sets Font Awesome family name to Icons ;)
font-family: "Icons";
margin-left: -1rem;
}
select {
background: transparent;
border: none;
border-bottom: 2px solid lightgrey;
padding: .7rem 2rem .7rem .7rem;
position: relative;
border-radius: 0;
transition: .2s ease-in;
-webkit-appearance: none;
-moz-appearance: none;
&:focus {
outline: none !important;
border-bottom: 2px solid dodgerblue !important;
}
&:focus ~ label,
&:valid ~ label {
color: gray;
font-size: 80%;
top: -1rem;
left: 0;
}
}
}
}
}
{: .ui.info.message} Chrome and Safari both ignore border-radius on select elements unless -webkit-appearance is overridden to an appropriate value.
Checkbox
Now for the bonus round! And unless you’re on a -webkit
or -moz
browser, IOW, not IE
or Edge
, you just can’t do this. Ironically, IE
mobile supports the feature using -webkit-appearance
.
This entire CSS trick hinges on -prefix-appearance: none
, and, as luck would have it, appearance
has been dropped from the CSS3 spec. It will probably re-appear in CSS4-UI spec. We’ll see…anyway.
<form class="ui form">
<div class="field checkbox">
<input type="checkbox" required>
<label>checkbox</label>
</div>
</form>
// Now we're adding .checkbox to .field
.ui.form {
.field {
position: relative;
width: 100%;
&:not(.checkbox) {
margin-top: 1rem;
margin-bottom: 1.7rem;
}
label {
color: lightgrey;
position: absolute;
left: .7rem;
top: .7rem;
transition: .2s ease-in;
}
&.checkbox {
align-items: flex-start;
align-content: flex-start;
display: flex;
margin: .7rem 0;
position: relative;
input[type=checkbox] {
padding: .7rem;
border: 2px solid lightgrey;
transition: .2s ease-in;
-webkit-appearance: none;
-moz-appearance: none;
&:focus {
outline: none;
}
&:before {
color: grey;
content: "";
transition: .2s ease-in;
}
&:checked {
padding: .6rem .35rem;
margin: -.3rem .1rem 0 .7rem;
border-left: none;
border-top: none;
transform: rotate(45deg);
}
}
label {
font-size: initial;
position: static;
margin-left: 1rem;
align-self: center;
}
}
}
}