STYLING
FORMS

Frontend

Men først...

by Jonas Holbech

En omfattende gennemgang af

CORS

by Jonas Holbech

But first...

CORS

v/ Jonas Holbech

En omfattende gennemgang af

Extensions

axe Accessibility Linter

Error Lens

Styling

Search for a topic of interest...

Search

HTML forms

Styling

A better user experience

HTML forms

Frontend elective, 3rd SEM

Search

Search for a topic of interest...

HTML forms

UI States

Input states

Pseudo-classes

A CSS pseudo-class is a keyword added to a selector that specifies a special state of the selected element(s). For example, :hover can be used to change a button's color when the user's pointer hovers over it.

Pseudo-classes

Pseudo-classes

:valid

represents any <input> or other <form> element whose contents validate successfully

input:valid {
  border-color: green;
}

needs "required"

Pseudo-classes

:invalid

any <input> or other <form> element whose contents fail to validate.

input:invalid {
  border-color: red;
}

needs "required"

Pseudo-classes = states

Pseudo-classes = states

Pseudo-classes = states

Pseudo-classes / states

:disabled

represents any disabled element

:checked

selector represents any radio, checkbox, or option element that is checked or toggled to an on state

:focus/:focus-visible

represents an element that has received focus

:placeholder-shown

represents any <input> or <textarea> element that is currently displaying placeholder text.

:not(

:not(

:not(

:not(

)

)

)

)

Pseudo-classes / states

:disabled

doesn't represents any disabled element

:checked

selector represents any radio, checkbox, or option element that is not checked or toggled to an on state

:focus/:focus-visible

represents an element that hasn't received focus

:placeholder-shown

represents any <input> or <textarea> element that is currently not displaying placeholder text.

:not(

:not(

:not(

:not(

)

)

)

)

input:invalid:not(:focus, :placeholder-shown) { ... }

Placeholder-shown

input:invalid:not(:focus, :placeholder-shown) ~ .error-message { ... }

JS er påkrævet for at overholde A11y-standarder

:has()

.form-group:has(input:invalid) { ... }
.form-group:has(input:not(:focus, :placeholder-shown):invalid) .error-message { ... }
.form-group:has(input:not(:focus, :placeholder-shown):invalid) label { ... }

:has()

.form-group:has(input:invalid) { ... }
.form-group:has(input:not(:focus, :placeholder-shown):invalid) .error-message { ... }
label:has( + input:not(:focus, :placeholder-shown):invalid) { ... }

:has()

label {
  color: var(--color);
}

.form-field:has(:invalid) {
  --color: red;
}

.form-field:has(:valid) {
  --color: green;
}

:has()

:has()

Browser compatibility

🫢

:has()

Browser compatibility

form:focus-within {
  border-color: blue;
}
.form-control:focus-within .hint {
  color: red;
}

:focus-within

:focus-within

Exercise

Focus states

Focus states

Safari 💩

Focus states

Firefox 💩

Focus states

:focus-visible {
  outline: 2px solid #000;
  outline-offset: -2px;
  box-shadow: 0 0 0 2px #fff, inset 0 0 0 3px #fff;
}

input {
  appearance: none; /* Safari fix */
}

Tilføj "states" (pseudo-klasser) til dit formular

  • :focus-visible
  • :valid
  • :invalid (with error messages)
  • :disabled
  • :has

Tilføj styles for følgende pseudo-klasser:

Checkbox "hack"

Custom Checkboxes / Radios

User Agent styles

UA styles

:root {
  accent-color: deeppink;
}

doesn't work in Safari 💩

it does actually now (15.4) 🎊

but...

UA styles

form {
  accent-color: deeppink;
}

Rule of Least Power

Customize

input[type="checkbox"] {
  appearance: none;
  ...
}

/* Checked state */
input:checked::before {
  ...
}

Remove browser styles

Style custom checkmark with pseudo-elements

Ressourcer

Gør det mere spændende

Reducerer cognitive load

Gør det mere spændende

Animated checkmark

Animated checkmark

Preparing an SVG in Figma / Illustrator

Animated checkmark

Animated checkmark

Animated checkmark

Resources

Task 2 (optional)

Craft your own form design

  • Style the form elements in your video game form
  • Style the different states with the corresponding pseudo-classes
  • Customize your form controls (e.g. radio, checkbox, etc)

Default:

:focus

Buttons

Custom checkboxes and radio buttons

:invalid

:disabled

Craft your own form design

Craft your own form design

Reset / Normalize

form,
fieldset,
legend,
input,
button,
textarea,
select {
  margin: 0;
  padding: 0;
}

input,
button,
textarea,
select {
  font-family: inherit;
  font-size: max(16px, 1em);
}

button {
  appearance: none;
  border: 1px solid;
  background: transparent;
  cursor: pointer;
}

input[type="text"],
input[type="email"],
textarea {
  appearance: none;
  border: 1px solid;
  background: transparent;
}

Reset / Normalize

The cascade

Lad den være åben

Tilføj en blå border på 4px til .my-input

Kig i DevTools for at finde fejlen

Quiz

p:not(#id) {
  color: green;
}

p.class {
  color: red;
}
<p class="class">text</p>

<p id="id">last text</p>
p.test a {
  color: green;
}

a:hover {
  color: deeppink;
}
<p class="test">
  <a href="#0">Hvilken farve?</p>
</p>

Quiz

The cascade

Author styles

0,0,0

0,0,1

🤷‍♂️

Cascade layers

@layer reset {
  /* ... other reset rules */
  
  input[type="text"] {
    border: 1px solid gray;
  }
}

@layer components {
  /* ... other component rules */
  
  .my-input {
    border: 4px solid blue;
  }
}

order matters

Cascade layers

@layer reset, components, utilities;

@layer reset {
  /* ... other reset rules */
  
  input[type="text"] {
    border: 1px solid gray;
  }
}

@layer components {
  /* ... other component rules */
  
  .my-input {
    border: 4px solid blue;
  }
}

configure up front

1

2

3

Cascade layers

@layer reset, components, utilities;

@layer components {
  /* ... other component rules */
  
  .my-input {
    border: 4px solid blue;
  }
}

@layer reset {
  /* ... other reset rules */
  
  input[type="text"] {
    border: 1px solid gray;
  }
}

configure up front

1

2

3

Cascade layers

@layer reset, components, states;

@layer components {
  /* Buttons, inputs etc. */
}

@layer states {
  /* Make sure stats override, no matter specificity count */
  :disabled {
    background-color: #ddd;
    color: #999;
  }
  
  :focus-visible {
    outline: 2px solid var(--focus-color, currentColor);
    outline-offset: 2px;
  }
}

Cascade layers

@layer reset, theme, global, layout, components, utilities, states;

Cascade layers

@layer reset {
  ul[class] {
    margin: 0;
    padding: 0;
    list-style: none;
    text-align: start;
  }
}

@layer utilities {
  .space-top {
    margin-top: 2rem;
  }
}

eksempel

Cascade layers

A sensible CSS reset

Default styling

:root {
  --theme-color: 258 29% 43%;
  --accent-color: 180 50% 43%;
}

input {
  font: inherit;
  font-size: max(16px, 1em);
  padding: 0.25em 0.5em;
  background-color: #fff;
  border: 2px solid hsl(var(--theme-color));
}

input:is(:focus-visible, :hover) {
  border-color: hsl(var(--accent-color));
}

A sensible CSS reset

Default styling

input:is([type="checkbox"], [type="radio"]) {
  appearance: none;
  /* custom styling */
}

A sensible CSS reset

Or with accent-color

form {
  accent-color: var(--theme-color, hotpink);
  /* checkbox, radio, progress, range etc. */
}

A sensible CSS reset

Form layout

form {
  display: grid;
  gap: 1.5rem;
}

.form-group {
  display: grid;
  gap: .3125rem;
}
form {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}

form > input {
  flex: 1 1 10ch;
}

input[type="email"] {
  flex: 3 1 30ch;
}
.container {
  container-type: inline-size;
}

@container (width > 25rem) {
  .newsletter { ... }
}

Forms CSS

By Dannie Vinther

Forms CSS

Styling forms

  • 215